diff --git a/.github/actions/get-bootjdk/action.yml b/.github/actions/get-bootjdk/action.yml index 19c3a0128f4d4..1e569dd47c570 100644 --- a/.github/actions/get-bootjdk/action.yml +++ b/.github/actions/get-bootjdk/action.yml @@ -1,5 +1,5 @@ # -# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -104,6 +104,6 @@ runs: - name: 'Export path to where BootJDK is installed' id: path-name run: | - # Export the path - echo 'path=bootjdk/jdk' >> $GITHUB_OUTPUT + # Export the absolute path + echo "path=`pwd`/bootjdk/jdk" >> $GITHUB_OUTPUT shell: bash diff --git a/.github/actions/get-gtest/action.yml b/.github/actions/get-gtest/action.yml index e8d70699c8fcb..5de2b10cd3209 100644 --- a/.github/actions/get-gtest/action.yml +++ b/.github/actions/get-gtest/action.yml @@ -40,7 +40,7 @@ runs: var: GTEST_VERSION - name: 'Checkout GTest source' - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: google/googletest ref: 'v${{ steps.version.outputs.value }}' diff --git a/.github/actions/get-jtreg/action.yml b/.github/actions/get-jtreg/action.yml index 9e1435513997b..a45c0c1e6a959 100644 --- a/.github/actions/get-jtreg/action.yml +++ b/.github/actions/get-jtreg/action.yml @@ -1,5 +1,5 @@ # -# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ runs: key: jtreg-${{ steps.version.outputs.value }} - name: 'Checkout the JTReg source' - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: openjdk/jtreg ref: jtreg-${{ steps.version.outputs.value }} @@ -56,8 +56,14 @@ runs: - name: 'Build JTReg' run: | + # If runner architecture is x64 set JAVA_HOME_17_X64 otherwise set to JAVA_HOME_17_arm64 + if [[ '${{ runner.arch }}' == 'X64' ]]; then + JDK="$JAVA_HOME_17_X64" + else + JDK="$JAVA_HOME_17_arm64" + fi # Build JTReg and move files to the proper locations - bash make/build.sh --jdk "$JAVA_HOME_17_X64" + bash make/build.sh --jdk "$JDK" mkdir ../installed mv build/images/jtreg/* ../installed working-directory: jtreg/src diff --git a/.github/scripts/gen-test-results.sh b/.github/scripts/gen-test-results.sh index 73edb8b3d11fe..9e85eef4dc08d 100644 --- a/.github/scripts/gen-test-results.sh +++ b/.github/scripts/gen-test-results.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -44,8 +44,8 @@ for test in $failures $errors; do base_path="$(echo "$test" | tr '#' '_')" report_file="$report_dir/$base_path.jtr" hs_err_files=$(ls $report_dir/$base_path/hs_err*.log 2> /dev/null || true) + replay_files=$(ls $report_dir/$base_path/replay*.log 2> /dev/null || true) echo "#### $test" - echo '
View test results' echo '' echo '```' @@ -73,6 +73,20 @@ for test in $failures $errors; do echo '' fi + if [[ "$replay_files" != "" ]]; then + echo '
View HotSpot replay file' + echo '' + for replay in $replay_files; do + echo '```' + echo "$replay:" + echo '' + cat "$replay" + echo '```' + done + + echo '
' + echo '' + fi done >> $GITHUB_STEP_SUMMARY # With many failures, the summary can easily exceed 1024 kB, the limit set by Github diff --git a/.github/scripts/gen-test-summary.sh b/.github/scripts/gen-test-summary.sh index d016cb38649fd..a612bed552779 100644 --- a/.github/scripts/gen-test-summary.sh +++ b/.github/scripts/gen-test-summary.sh @@ -42,6 +42,7 @@ error_count=$(echo $errors | wc -w || true) if [[ "$failures" = "" && "$errors" = "" ]]; then # We know something went wrong, but not what + echo 'failure=true' >> $GITHUB_OUTPUT echo 'error-message=Unspecified test suite failure. Please see log for job for details.' >> $GITHUB_OUTPUT exit 0 fi diff --git a/.github/workflows/build-cross-compile.yml b/.github/workflows/build-cross-compile.yml index e27b7e2c05258..5db69f07d98c5 100644 --- a/.github/workflows/build-cross-compile.yml +++ b/.github/workflows/build-cross-compile.yml @@ -80,13 +80,12 @@ jobs: - target-cpu: riscv64 gnu-arch: riscv64 debian-arch: riscv64 - debian-repository: https://deb.debian.org/debian-ports - debian-keyring: /usr/share/keyrings/debian-ports-archive-keyring.gpg + debian-repository: https://httpredir.debian.org/debian/ debian-version: sid steps: - name: 'Checkout the JDK source' - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: 'Get the BootJDK' id: bootjdk @@ -101,6 +100,10 @@ jobs: with: platform: linux-x64 + - name: 'Get GTest' + id: gtest + uses: ./.github/actions/get-gtest + # Upgrading apt to solve libc6 installation bugs, see JDK-8260460. - name: 'Install toolchain and dependencies' run: | @@ -112,8 +115,7 @@ jobs: g++-${{ inputs.gcc-major-version }} \ gcc-${{ inputs.gcc-major-version }}-${{ matrix.gnu-arch }}-linux-gnu${{ matrix.gnu-abi}} \ g++-${{ inputs.gcc-major-version }}-${{ matrix.gnu-arch }}-linux-gnu${{ matrix.gnu-abi}} \ - libxrandr-dev libxtst-dev libcups2-dev libasound2-dev \ - debian-ports-archive-keyring + libxrandr-dev libxtst-dev libcups2-dev libasound2-dev sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${{ inputs.gcc-major-version }} 100 --slave /usr/bin/g++ g++ /usr/bin/g++-${{ inputs.gcc-major-version }} - name: 'Check cache for sysroot' @@ -132,9 +134,9 @@ jobs: sudo debootstrap --arch=${{ matrix.debian-arch }} --verbose - --include=fakeroot,symlinks,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype6-dev,libpng-dev + --include=fakeroot,symlinks,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype-dev,libpng-dev --resolve-deps - $(test -n "${{ matrix.debian-keyring }}" && echo "--keyring=${{ matrix.debian-keyring }}") + --variant=minbase ${{ matrix.debian-version }} sysroot ${{ matrix.debian-repository }} @@ -147,7 +149,8 @@ jobs: sudo chown ${USER} -R sysroot rm -rf sysroot/{dev,proc,run,sys,var} rm -rf sysroot/usr/{sbin,bin,share} - rm -rf sysroot/usr/lib/{apt,udev,systemd} + rm -rf sysroot/usr/lib/{apt,gcc,udev,systemd} + rm -rf sysroot/usr/libexec/gcc if: steps.get-cached-sysroot.outputs.cache-hit != 'true' - name: 'Configure' @@ -156,6 +159,7 @@ jobs: --with-conf-name=linux-${{ matrix.target-cpu }} --with-version-opt=${GITHUB_ACTOR}-${GITHUB_SHA} --with-boot-jdk=${{ steps.bootjdk.outputs.path }} + --with-gtest=${{ steps.gtest.outputs.path }} --with-zlib=system --enable-debug --disable-precompiled-headers diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 72b7cfb0613a1..f3ea4e4fb6ad8 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -78,7 +78,7 @@ jobs: steps: - name: 'Checkout the JDK source' - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: 'Get the BootJDK' id: bootjdk diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index cbe501ea60640..90bb6af044ff8 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -1,5 +1,5 @@ # -# Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,9 @@ on: platform: required: true type: string + runs-on: + required: true + type: string extra-conf-options: required: false type: string @@ -55,7 +58,7 @@ on: jobs: build-macos: name: build - runs-on: macos-11 + runs-on: ${{ inputs.runs-on }} strategy: fail-fast: false @@ -68,13 +71,13 @@ jobs: steps: - name: 'Checkout the JDK source' - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: 'Get the BootJDK' id: bootjdk uses: ./.github/actions/get-bootjdk with: - platform: macos-x64 + platform: ${{ inputs.platform }} - name: 'Get JTReg' id: jtreg @@ -87,7 +90,7 @@ jobs: - name: 'Install toolchain and dependencies' run: | # Run Homebrew installation and xcode-select - brew install make + brew install autoconf make sudo xcode-select --switch /Applications/Xcode_${{ inputs.xcode-toolset-version }}.app/Contents/Developer # This will make GNU make available as 'make' and not only as 'gmake' echo '/usr/local/opt/make/libexec/gnubin' >> $GITHUB_PATH diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 6a56df295baf3..d02ef91ad86f6 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -79,7 +79,7 @@ jobs: steps: - name: 'Checkout the JDK source' - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: 'Get MSYS2' uses: ./.github/actions/get-msys2 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ac8f886cbe26b..1704102f6f0f9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,5 +1,5 @@ # -# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -146,7 +146,7 @@ jobs: apt-architecture: 'i386' # Some multilib libraries do not have proper inter-dependencies, so we have to # install their dependencies manually. - apt-extra-packages: 'libfreetype6-dev:i386 libtiff-dev:i386 libcupsimage2-dev:i386 libc6-i386 libgcc-s1:i386 libstdc++6:i386' + apt-extra-packages: 'libfreetype-dev:i386 libtiff-dev:i386 libcupsimage2-dev:i386 libc6-i386 libgcc-s1:i386 libstdc++6:i386' extra-conf-options: '--with-target-bits=32' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} @@ -227,7 +227,8 @@ jobs: uses: ./.github/workflows/build-macos.yml with: platform: macos-x64 - xcode-toolset-version: '12.5.1' + runs-on: 'macos-13' + xcode-toolset-version: '14.3.1' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} if: needs.select.outputs.macos-x64 == 'true' @@ -238,8 +239,8 @@ jobs: uses: ./.github/workflows/build-macos.yml with: platform: macos-aarch64 - xcode-toolset-version: '12.5.1' - extra-conf-options: '--openjdk-target=aarch64-apple-darwin' + runs-on: 'macos-14' + xcode-toolset-version: '14.3.1' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} if: needs.select.outputs.macos-aarch64 == 'true' @@ -328,7 +329,17 @@ jobs: with: platform: macos-x64 bootjdk-platform: macos-x64 - runs-on: macos-11 + runs-on: macos-13 + + test-macos-aarch64: + name: macos-aarch64 + needs: + - build-macos-aarch64 + uses: ./.github/workflows/test.yml + with: + platform: macos-aarch64 + bootjdk-platform: macos-aarch64 + runs-on: macos-14 test-windows-x64: name: windows-x64 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f4d4e93c1875c..8808ab80d0ef6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,5 +1,5 @@ # -# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,10 @@ jobs: - 'jdk/tier1 part 3' - 'langtools/tier1' - 'hs/tier1 common' - - 'hs/tier1 compiler' + - 'hs/tier1 compiler part 1' + - 'hs/tier1 compiler part 2' + - 'hs/tier1 compiler part 3' + - 'hs/tier1 compiler not-xcomp' - 'hs/tier1 gc' - 'hs/tier1 runtime' - 'hs/tier1 serviceability' @@ -83,8 +86,20 @@ jobs: test-suite: 'test/hotspot/jtreg/:tier1_common' debug-suffix: -debug - - test-name: 'hs/tier1 compiler' - test-suite: 'test/hotspot/jtreg/:tier1_compiler' + - test-name: 'hs/tier1 compiler part 1' + test-suite: 'test/hotspot/jtreg/:tier1_compiler_1' + debug-suffix: -debug + + - test-name: 'hs/tier1 compiler part 2' + test-suite: 'test/hotspot/jtreg/:tier1_compiler_2' + debug-suffix: -debug + + - test-name: 'hs/tier1 compiler part 3' + test-suite: 'test/hotspot/jtreg/:tier1_compiler_3' + debug-suffix: -debug + + - test-name: 'hs/tier1 compiler not-xcomp' + test-suite: 'test/hotspot/jtreg/:tier1_compiler_not_xcomp' debug-suffix: -debug - test-name: 'hs/tier1 gc' @@ -105,7 +120,7 @@ jobs: steps: - name: 'Checkout the JDK source' - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: 'Get MSYS2' uses: ./.github/actions/get-msys2 @@ -132,7 +147,7 @@ jobs: run: | # On macOS we need to install some dependencies for testing brew install make - sudo xcode-select --switch /Applications/Xcode_11.7.app/Contents/Developer + sudo xcode-select --switch /Applications/Xcode_14.3.1.app/Contents/Developer # This will make GNU make available as 'make' and not only as 'gmake' echo '/usr/local/opt/make/libexec/gnubin' >> $GITHUB_PATH if: runner.os == 'macOS' diff --git a/.jcheck/conf b/.jcheck/conf index 8993c274fe0c9..e2ca212ab3a23 100644 --- a/.jcheck/conf +++ b/.jcheck/conf @@ -1,7 +1,7 @@ [general] -project=jdk +project=jdk-updates jbs=JDK -version=21 +version=21.0.3 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists diff --git a/doc/testing.html b/doc/testing.html index 0f81647ecae7f..19d937df1ead1 100644 --- a/doc/testing.html +++ b/doc/testing.html @@ -577,12 +577,15 @@

PKCS11 Tests

are hard to diagnose. For example, sun/security/pkcs11/Secmod/AddTrustedCert.java may fail on Ubuntu 18.04 with the default NSS version in the system. To run these tests -correctly, the system property test.nss.lib.paths is -required on Ubuntu 18.04 to specify the alternative NSS lib -directories.

+correctly, the system property +jdk.test.lib.artifacts.<NAME> is required on Ubuntu +18.04 to specify the alternative NSS lib directory. The +<NAME> component should be replaced with the name +element of the appropriate @Artifact class. (See +test/jdk/sun/security/pkcs11/PKCS11Test.java)

For example:

$ make test TEST="jtreg:sun/security/pkcs11/Secmod/AddTrustedCert.java" \
-    JTREG="JAVA_OPTIONS=-Dtest.nss.lib.paths=/path/to/your/latest/NSS-libs"
+ 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.

Client UI Tests

diff --git a/doc/testing.md b/doc/testing.md index 764fec15c8da7..9756a691a8c46 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -600,14 +600,16 @@ It is highly recommended to use the latest NSS version when running PKCS11 tests. Improper NSS version may lead to unexpected failures which are hard to diagnose. For example, sun/security/pkcs11/Secmod/AddTrustedCert.java may fail on Ubuntu 18.04 with the default NSS version in the system. To run these tests -correctly, the system property `test.nss.lib.paths` is required on Ubuntu 18.04 -to specify the alternative NSS lib directories. +correctly, the system property `jdk.test.lib.artifacts.` is required on +Ubuntu 18.04 to specify the alternative NSS lib directory. The `` +component should be replaced with the name element of the appropriate +`@Artifact` class. (See `test/jdk/sun/security/pkcs11/PKCS11Test.java`) For example: ``` $ make test TEST="jtreg:sun/security/pkcs11/Secmod/AddTrustedCert.java" \ - JTREG="JAVA_OPTIONS=-Dtest.nss.lib.paths=/path/to/your/latest/NSS-libs" + JTREG="JAVA_OPTIONS=-Djdk.test.lib.artifacts.nsslib-linux_aarch64=/path/to/NSS-libs" ``` For more notes about the PKCS11 tests, please refer to diff --git a/make/CreateJmods.gmk b/make/CreateJmods.gmk index 2901930cf8814..6fbaef6bdf1c4 100644 --- a/make/CreateJmods.gmk +++ b/make/CreateJmods.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. # 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,13 +81,11 @@ endif ifneq ($(CMDS_DIR), ) DEPS += $(call FindFiles, $(CMDS_DIR)) ifeq ($(call isTargetOs, windows)+$(SHIP_DEBUG_SYMBOLS), true+public) - # For public debug symbols on Windows, we have to use stripped pdbs, rename them - # and filter out a few launcher pdbs where there's a lib that goes by the same name + # For public debug symbols on Windows, we have to use stripped pdbs and rename them rename_stripped = $(patsubst %.stripped.pdb,%.pdb,$1) CMDS_DIR_FILTERED := $(subst modules_cmds,modules_cmds_filtered, $(CMDS_DIR)) FILES_CMDS := $(filter-out %.pdb, $(call FindFiles, $(CMDS_DIR))) \ - $(filter-out %jimage.stripped.pdb %jpackage.stripped.pdb %java.stripped.pdb, \ - $(filter %.stripped.pdb, $(call FindFiles, $(CMDS_DIR)))) + $(filter %.stripped.pdb, $(call FindFiles, $(CMDS_DIR))) $(eval $(call SetupCopyFiles, COPY_FILTERED_CMDS, \ SRC := $(CMDS_DIR), \ DEST := $(CMDS_DIR_FILTERED), \ @@ -96,18 +94,6 @@ ifneq ($(CMDS_DIR), ) )) DEPS += $(COPY_FILTERED_CMDS) JMOD_FLAGS += --cmds $(CMDS_DIR_FILTERED) - else ifeq ($(call isTargetOs, windows)+$(SHIP_DEBUG_SYMBOLS), true+full) - # For full debug symbols on Windows, we have to filter out a few launcher pdbs - # where there's a lib that goes by the same name - CMDS_DIR_FILTERED := $(subst modules_cmds,modules_cmds_filtered, $(CMDS_DIR)) - $(eval $(call SetupCopyFiles, COPY_FILTERED_CMDS, \ - SRC := $(CMDS_DIR), \ - DEST := $(CMDS_DIR_FILTERED), \ - FILES := $(filter-out %jimage.pdb %jpackage.pdb %java.pdb, \ - $(call FindFiles, $(CMDS_DIR))), \ - )) - DEPS += $(COPY_FILTERED_CMDS) - JMOD_FLAGS += --cmds $(CMDS_DIR_FILTERED) else JMOD_FLAGS += --cmds $(CMDS_DIR) endif diff --git a/make/Images.gmk b/make/Images.gmk index 5b2f776155f0c..225d9a93d4f72 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -267,9 +267,6 @@ else endif endif -FILTERED_PDBS := %jimage.stripped.pdb %jpackage.stripped.pdb %java.stripped.pdb \ - %jimage.pdb %jpackage.pdb %java.pdb %jimage.map %jpackage.map %java.map - # Param 1 - either JDK or JRE SetupCopyDebuginfo = \ $(foreach m, $(ALL_$1_MODULES), \ @@ -283,8 +280,8 @@ SetupCopyDebuginfo = \ $(eval $(call SetupCopyFiles, COPY_$1_CMDS_DEBUGINFO_$m, \ SRC := $(SUPPORT_OUTPUTDIR)/modules_cmds/$m, \ DEST := $($1_IMAGE_DIR)/$(CMDS_TARGET_SUBDIR), \ - FILES := $(filter-out $(FILTERED_PDBS), $(call FindDebuginfoFiles, \ - $(SUPPORT_OUTPUTDIR)/modules_cmds/$m)), \ + FILES := $(call FindDebuginfoFiles, \ + $(SUPPORT_OUTPUTDIR)/modules_cmds/$m), \ )) \ $(eval $1_TARGETS += $$(COPY_$1_CMDS_DEBUGINFO_$m)) \ ) diff --git a/make/Init.gmk b/make/Init.gmk index 151127d578803..61846217ecc34 100644 --- a/make/Init.gmk +++ b/make/Init.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -138,7 +138,10 @@ ifeq ($(HAS_SPEC),) # The spec files depend on the autoconf source code. This check makes sure # the configuration is up to date after changes to configure. $(SPECS): $(wildcard $(topdir)/make/autoconf/*) \ - $(if $(CUSTOM_CONFIG_DIR), $(wildcard $(CUSTOM_CONFIG_DIR)/*)) + $(if $(CUSTOM_CONFIG_DIR), $(wildcard $(CUSTOM_CONFIG_DIR)/*)) \ + $(addprefix $(topdir)/make/conf/, version-numbers.conf branding.conf) \ + $(if $(CUSTOM_CONF_DIR), $(wildcard $(addprefix $(CUSTOM_CONF_DIR)/, \ + version-numbers.conf branding.conf))) ifeq ($(CONF_CHECK), fail) @echo Error: The configuration is not up to date for \ "'$(lastword $(subst /, , $(dir $@)))'." diff --git a/make/JrtfsJar.gmk b/make/JrtfsJar.gmk index 278b7657a82d2..50ae82ca56567 100644 --- a/make/JrtfsJar.gmk +++ b/make/JrtfsJar.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -46,8 +46,10 @@ JIMAGE_PKGS := \ jdk/internal/jrtfs \ # +# Compile jrt-fs.jar with the interim compiler, as it +# ends up in the image, this will ensure reproducible classes $(eval $(call SetupJavaCompilation, BUILD_JRTFS, \ - COMPILER := bootjdk, \ + COMPILER := interim, \ DISABLED_WARNINGS := options, \ TARGET_RELEASE := $(TARGET_RELEASE_JDK8), \ SRC := $(TOPDIR)/src/java.base/share/classes, \ diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 770b81af8aca0..b82d2b2b6015d 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -178,7 +178,8 @@ ifeq ($(TEST_JOBS), 0) c = c * $(TEST_JOBS_FACTOR_JDL); \ c = c * $(TEST_JOBS_FACTOR_MACHINE); \ if (c < 1) c = 1; \ - printf "%.0f", c; \ + c = c + 0.5; \ + printf "%d", c; \ }') endif @@ -356,7 +357,7 @@ ExpandJtregPath = \ # with test id: dir/Test.java#selection -> Test.java#selection -> .java#selection -> #selection # without: dir/Test.java -> Test.java -> .java -> <> TestID = \ - $(subst .sh,,$(subst .html,,$(subst .java,,$(suffix $(notdir $1))))) + $(subst .jasm,,$(subst .sh,,$(subst .html,,$(subst .java,,$(suffix $(notdir $1)))))) # The test id starting with a hash (#testid) will be stripped by all # evals in ParseJtregTestSelectionInner and will be reinserted by calling @@ -800,8 +801,10 @@ define SetupRunJtregTestBody $1_JTREG_BASIC_OPTIONS += -e:JIB_DATA_DIR # If running on Windows, propagate the _NT_SYMBOL_PATH to enable # symbol lookup in hserr files + # The minidumps are disabled by default on client Windows, so enable them ifeq ($$(call isTargetOs, windows), true) $1_JTREG_BASIC_OPTIONS += -e:_NT_SYMBOL_PATH + $1_JTREG_BASIC_OPTIONS += -vmoption:-XX:+CreateCoredumpOnCrash else ifeq ($$(call isTargetOs, linux), true) $1_JTREG_BASIC_OPTIONS += -e:_JVM_DWARF_PATH=$$(SYMBOLS_IMAGE_DIR) endif @@ -860,11 +863,12 @@ define SetupRunJtregTestBody $$(eval $$(call SetupRunJtregTestCustom, $1)) - clean-workdir-$1: + clean-outputdirs-$1: $$(RM) -r $$($1_TEST_SUPPORT_DIR) + $$(RM) -r $$($1_TEST_RESULTS_DIR) $1_COMMAND_LINE := \ - $$(JAVA) $$($1_JTREG_LAUNCHER_OPTIONS) \ + $$(JTREG_JAVA) $$($1_JTREG_LAUNCHER_OPTIONS) \ -Dprogram=jtreg -jar $$(JT_HOME)/lib/jtreg.jar \ $$($1_JTREG_BASIC_OPTIONS) \ -testjdk:$$(JDK_UNDER_TEST) \ @@ -907,7 +911,7 @@ define SetupRunJtregTestBody done endif - run-test-$1: pre-run-test clean-workdir-$1 + run-test-$1: pre-run-test clean-outputdirs-$1 $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR) \ @@ -944,9 +948,9 @@ define SetupRunJtregTestBody $$(eval $1_TOTAL := 1) \ ) - $1: run-test-$1 parse-test-$1 clean-workdir-$1 + $1: run-test-$1 parse-test-$1 clean-outputdirs-$1 - TARGETS += $1 run-test-$1 parse-test-$1 clean-workdir-$1 + TARGETS += $1 run-test-$1 parse-test-$1 clean-outputdirs-$1 TEST_TARGETS += parse-test-$1 endef diff --git a/make/RunTestsPrebuilt.gmk b/make/RunTestsPrebuilt.gmk index ca20ccf26ad20..93febe5ed31d9 100644 --- a/make/RunTestsPrebuilt.gmk +++ b/make/RunTestsPrebuilt.gmk @@ -122,6 +122,7 @@ $(eval $(call SetupVariable,JT_HOME)) $(eval $(call SetupVariable,JDK_IMAGE_DIR,$(OUTPUTDIR)/images/jdk)) $(eval $(call SetupVariable,TEST_IMAGE_DIR,$(OUTPUTDIR)/images/test)) $(eval $(call SetupVariable,SYMBOLS_IMAGE_DIR,$(OUTPUTDIR)/images/symbols,NO_CHECK)) +$(eval $(call SetupVariable,JTREG_JDK,$(BOOT_JDK))) # Provide default values for tools that we need $(eval $(call SetupVariable,MAKE,make,NO_CHECK)) @@ -157,6 +158,10 @@ ifeq ($(UNAME_OS), CYGWIN) OPENJDK_TARGET_OS := windows OPENJDK_TARGET_OS_TYPE := windows OPENJDK_TARGET_OS_ENV := windows.cygwin +else ifeq ($(UNAME_OS), MINGW64) + OPENJDK_TARGET_OS := windows + OPENJDK_TARGET_OS_TYPE := windows + OPENJDK_TARGET_OS_ENV := windows.msys2 else OPENJDK_TARGET_OS_TYPE:=unix ifeq ($(UNAME_OS), Linux) @@ -169,6 +174,9 @@ else OPENJDK_TARGET_OS_ENV := $(OPENJDK_TARGET_OS) endif +# Sanity check env detection +$(info Detected target OS, type and env: [$(OPENJDK_TARGET_OS)] [$(OPENJDK_TARGET_OS_TYPE)] [$(OPENJDK_TARGET_OS_ENV)]) + # Assume little endian unless otherwise specified OPENJDK_TARGET_CPU_ENDIAN := little @@ -248,6 +256,7 @@ $(call CreateNewSpec, $(NEW_SPEC), \ TOPDIR := $(TOPDIR), \ OUTPUTDIR := $(OUTPUTDIR), \ BOOT_JDK := $(BOOT_JDK), \ + JTREG_JDK := $(JTREG_JDK), \ JT_HOME := $(JT_HOME), \ JDK_IMAGE_DIR := $(JDK_IMAGE_DIR), \ JCOV_IMAGE_DIR := $(JCOV_IMAGE_DIR), \ diff --git a/make/RunTestsPrebuiltSpec.gmk b/make/RunTestsPrebuiltSpec.gmk index 585fd24fda337..7fcaf56ff527e 100644 --- a/make/RunTestsPrebuiltSpec.gmk +++ b/make/RunTestsPrebuiltSpec.gmk @@ -124,6 +124,8 @@ JAR := $(FIXPATH) $(JAR_CMD) JLINK := $(FIXPATH) $(JLINK_CMD) JMOD := $(FIXPATH) $(JMOD_CMD) +JTREG_JAVA := $(FIXPATH) $(JTREG_JDK)/bin/java $(JAVA_FLAGS_BIG) $(JAVA_FLAGS) + BUILD_JAVA := $(JDK_IMAGE_DIR)/bin/JAVA ################################################################################ # Some common tools. Assume most common name and no path. diff --git a/make/ZipSecurity.gmk b/make/ZipSecurity.gmk index f7435f05efe6f..489bbef49f68b 100644 --- a/make/ZipSecurity.gmk +++ b/make/ZipSecurity.gmk @@ -88,9 +88,9 @@ ifeq ($(call isTargetOs, windows), true) $(eval $(call SetupZipArchive,BUILD_JGSS_BIN_ZIP, \ SRC := $(SUPPORT_OUTPUTDIR), \ INCLUDE_FILES := modules_libs/java.security.jgss/w2k_lsa_auth.dll \ - modules_libs/java.security.jgss/w2k_lsa_auth.diz \ - modules_libs/java.security.jgss/w2k_lsa_auth.map \ - modules_libs/java.security.jgss/w2k_lsa_auth.pdb, \ + modules_libs/java.security.jgss/w2k_lsa_auth.dll.diz \ + modules_libs/java.security.jgss/w2k_lsa_auth.dll.map \ + modules_libs/java.security.jgss/w2k_lsa_auth.dll.pdb, \ ZIP := $(IMAGES_OUTPUTDIR)/$(JGSS_ZIP_NAME))) TARGETS += $(IMAGES_OUTPUTDIR)/$(JGSS_ZIP_NAME) diff --git a/make/autoconf/basic.m4 b/make/autoconf/basic.m4 index f02c0e3370761..02c477f4c9fda 100644 --- a/make/autoconf/basic.m4 +++ b/make/autoconf/basic.m4 @@ -406,9 +406,9 @@ AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR], # WARNING: This might be a bad thing to do. You need to be sure you want to # have a configuration in this directory. Do some sanity checks! - if test ! -e "$OUTPUTDIR/spec.gmk"; then - # If we have a spec.gmk, we have run here before and we are OK. Otherwise, check for - # other files + if test ! -e "$OUTPUTDIR/spec.gmk" && test ! -e "$OUTPUTDIR/configure-support/generated-configure.sh"; then + # If we have a spec.gmk or configure-support/generated-configure.sh, + # we have run here before and we are OK. Otherwise, check for other files files_present=`$LS $OUTPUTDIR` # Configure has already touched config.log and confdefs.h in the current dir when this check # is performed. @@ -423,8 +423,9 @@ AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR], AC_MSG_NOTICE([Current directory is $CONFIGURE_START_DIR.]) AC_MSG_NOTICE([Since this is not the source root, configure will output the configuration here]) AC_MSG_NOTICE([(as opposed to creating a configuration in /build/).]) - AC_MSG_NOTICE([However, this directory is not empty. This is not allowed, since it could]) - AC_MSG_NOTICE([seriously mess up just about everything.]) + AC_MSG_NOTICE([However, this directory is not empty, additionally to some allowed files]) + AC_MSG_NOTICE([it contains $filtered_files.]) + AC_MSG_NOTICE([This is not allowed, since it could seriously mess up just about everything.]) AC_MSG_NOTICE([Try 'cd $TOPDIR' and restart configure]) AC_MSG_NOTICE([(or create a new empty directory and cd to it).]) AC_MSG_ERROR([Will not continue creating configuration in $CONFIGURE_START_DIR]) diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index f8fbe14cc38d3..06a62c9a8f148 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -117,6 +117,11 @@ AC_DEFUN([FLAGS_SETUP_DEBUG_SYMBOLS], FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${DEBUG_PREFIX_CFLAGS}], IF_FALSE: [ DEBUG_PREFIX_CFLAGS= + ], + IF_TRUE: [ + # Add debug prefix map gcc system include paths, as they cause + # non-deterministic debug paths depending on gcc path location. + DEBUG_PREFIX_MAP_GCC_INCLUDE_PATHS ] ) fi @@ -158,6 +163,55 @@ AC_DEFUN([FLAGS_SETUP_DEBUG_SYMBOLS], AC_SUBST(ASFLAGS_DEBUG_SYMBOLS) ]) +# gcc will embed the full system include paths in the debug info +# resulting in non-deterministic debug symbol files and thus +# non-reproducible native libraries if gcc includes are located +# in different paths. +# Add -fdebug-prefix-map'ings for root and gcc include paths, +# pointing to a common set of folders so that the binaries are deterministic: +# root include : /usr/include +# gcc include : /usr/local/gcc_include +# g++ include : /usr/local/gxx_include +AC_DEFUN([DEBUG_PREFIX_MAP_GCC_INCLUDE_PATHS], +[ + # Determine gcc system include paths. + # Assume default roots to start with: + GCC_ROOT_INCLUDE="/usr/include" + + # Determine is sysroot or devkit specified? + if test "x$SYSROOT" != "x"; then + GCC_ROOT_INCLUDE="${SYSROOT%/}/usr/include" + fi + + # Add root include mapping => /usr/include + GCC_INCLUDE_DEBUG_MAP_FLAGS="-fdebug-prefix-map=${GCC_ROOT_INCLUDE}/=/usr/include/" + + # Add gcc system include mapping => /usr/local/gcc_include + # Find location of stddef.h using build C compiler + GCC_SYSTEM_INCLUDE=`$ECHO "#include " | \ + $CC $CFLAGS -v -E - 2>&1 | \ + $GREP stddef | $TAIL -1 | $TR -s " " | $CUT -d'"' -f2` + if test "x$GCC_SYSTEM_INCLUDE" != "x"; then + GCC_SYSTEM_INCLUDE=`$DIRNAME $GCC_SYSTEM_INCLUDE` + GCC_INCLUDE_DEBUG_MAP_FLAGS="$GCC_INCLUDE_DEBUG_MAP_FLAGS \ + -fdebug-prefix-map=${GCC_SYSTEM_INCLUDE}/=/usr/local/gcc_include/" + fi + + # Add g++ system include mapping => /usr/local/gxx_include + # Find location of cstddef using build C++ compiler + GXX_SYSTEM_INCLUDE=`$ECHO "#include " | \ + $CXX $CXXFLAGS -v -E -x c++ - 2>&1 | \ + $GREP cstddef | $TAIL -1 | $TR -s " " | $CUT -d'"' -f2` + if test "x$GXX_SYSTEM_INCLUDE" != "x"; then + GXX_SYSTEM_INCLUDE=`$DIRNAME $GXX_SYSTEM_INCLUDE` + GCC_INCLUDE_DEBUG_MAP_FLAGS="$GCC_INCLUDE_DEBUG_MAP_FLAGS \ + -fdebug-prefix-map=${GXX_SYSTEM_INCLUDE}/=/usr/local/gxx_include/" + fi + + # Add to debug prefix cflags + DEBUG_PREFIX_CFLAGS="$DEBUG_PREFIX_CFLAGS $GCC_INCLUDE_DEBUG_MAP_FLAGS" +]) + AC_DEFUN([FLAGS_SETUP_WARNINGS], [ # Set default value. @@ -425,7 +479,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], [ #### OS DEFINES, these should be independent on toolchain if test "x$OPENJDK_TARGET_OS" = xlinux; then - CFLAGS_OS_DEF_JVM="-DLINUX" + CFLAGS_OS_DEF_JVM="-DLINUX -D_FILE_OFFSET_BITS=64" CFLAGS_OS_DEF_JDK="-D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE" elif test "x$OPENJDK_TARGET_OS" = xmacosx; then CFLAGS_OS_DEF_JVM="-D_ALLBSD_SOURCE -D_DARWIN_C_SOURCE -D_XOPEN_SOURCE" @@ -816,6 +870,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP], REPRODUCIBLE_CFLAGS= ] ) + AC_SUBST(REPRODUCIBLE_CFLAGS) fi # Prevent the __FILE__ macro from generating absolute paths into the built @@ -849,6 +904,22 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP], FILE_MACRO_CFLAGS= ] ) + if test "x$FILE_MACRO_CFLAGS" != x; then + # Add -pathmap for all VS system include paths using Windows + # full Long path name that is generated by the compiler + # Not enabled under WSL as there is no easy way to obtain the + # Windows full long paths, thus reproducible WSL builds will + # depend on building with the same VS toolchain install location. + if test "x$OPENJDK_BUILD_OS_ENV" != "xwindows.wsl1" && test "x$OPENJDK_BUILD_OS_ENV" != "xwindows.wsl2"; then + for ipath in ${$3SYSROOT_CFLAGS}; do + if test "x${ipath:0:2}" == "x-I"; then + ipath_path=${ipath#"-I"} + UTIL_FIXUP_WIN_LONG_PATH(ipath_path) + FILE_MACRO_CFLAGS="$FILE_MACRO_CFLAGS -pathmap:\"$ipath_path\"=vsi" + fi + done + fi + fi fi AC_MSG_CHECKING([how to prevent absolute paths in output]) diff --git a/make/autoconf/flags-other.m4 b/make/autoconf/flags-other.m4 index 8062a32601f3d..0af7c02cff6c2 100644 --- a/make/autoconf/flags-other.m4 +++ b/make/autoconf/flags-other.m4 @@ -88,6 +88,16 @@ AC_DEFUN([FLAGS_SETUP_RCFLAGS], AC_SUBST(RCFLAGS) ]) +AC_DEFUN([FLAGS_SETUP_NMFLAGS], +[ + # On AIX, we need to set NM flag -X64 for processing 64bit object files + if test "x$OPENJDK_TARGET_OS" = xaix; then + NMFLAGS="-X64" + fi + + AC_SUBST(NMFLAGS) +]) + ################################################################################ # platform independent AC_DEFUN([FLAGS_SETUP_ASFLAGS], diff --git a/make/autoconf/flags.m4 b/make/autoconf/flags.m4 index ddb2b4c8e0abc..7060edeff73b2 100644 --- a/make/autoconf/flags.m4 +++ b/make/autoconf/flags.m4 @@ -428,6 +428,7 @@ AC_DEFUN([FLAGS_SETUP_FLAGS], FLAGS_SETUP_ARFLAGS FLAGS_SETUP_STRIPFLAGS FLAGS_SETUP_RCFLAGS + FLAGS_SETUP_NMFLAGS FLAGS_SETUP_ASFLAGS FLAGS_SETUP_ASFLAGS_CPU_DEP([TARGET]) diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index f08cc6ddd4150..f56081223a600 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -822,6 +822,9 @@ AC_DEFUN([JDKOPT_CHECK_CODESIGN_PARAMS], $RM "$CODESIGN_TESTFILE" $TOUCH "$CODESIGN_TESTFILE" CODESIGN_SUCCESS=false + + $ECHO "check codesign, calling $CODESIGN $PARAMS $CODESIGN_TESTFILE" >&AS_MESSAGE_LOG_FD + eval \"$CODESIGN\" $PARAMS \"$CODESIGN_TESTFILE\" 2>&AS_MESSAGE_LOG_FD \ >&AS_MESSAGE_LOG_FD && CODESIGN_SUCCESS=true $RM "$CODESIGN_TESTFILE" diff --git a/make/autoconf/jdk-version.m4 b/make/autoconf/jdk-version.m4 index 6a7662556fdaf..7c9ecad77791b 100644 --- a/make/autoconf/jdk-version.m4 +++ b/make/autoconf/jdk-version.m4 @@ -110,6 +110,15 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE]) AC_SUBST(COMPANY_NAME) + # Set the JDK RC Company name + # Otherwise uses the value set for "vendor-name". + UTIL_ARG_WITH(NAME: jdk-rc-company-name, TYPE: string, + DEFAULT: $COMPANY_NAME, + DESC: [Set JDK RC company name. This is used for CompanyName properties of MS Windows binaries.], + DEFAULT_DESC: [from branding.conf], + CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE]) + AC_SUBST(JDK_RC_COMPANY_NAME) + # The vendor URL, if any # Only set VENDOR_URL if '--with-vendor-url' was used and is not empty. # Otherwise we will use the value from "branding.conf" included above. diff --git a/make/autoconf/lib-cups.m4 b/make/autoconf/lib-cups.m4 index 0a7df8b381be2..27d5efbc8c9e5 100644 --- a/make/autoconf/lib-cups.m4 +++ b/make/autoconf/lib-cups.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -68,12 +68,20 @@ AC_DEFUN_ONCE([LIB_SETUP_CUPS], fi fi if test "x$CUPS_FOUND" = xno; then - # Are the cups headers installed in the default /usr/include location? - AC_CHECK_HEADERS([cups/cups.h cups/ppd.h], [ - CUPS_FOUND=yes - CUPS_CFLAGS= - DEFAULT_CUPS=yes - ]) + # Are the cups headers installed in the default AIX or /usr/include location? + if test "x$OPENJDK_TARGET_OS" = "xaix"; then + AC_CHECK_HEADERS([/opt/freeware/include/cups/cups.h /opt/freeware/include/cups/ppd.h], [ + CUPS_FOUND=yes + CUPS_CFLAGS="-I/opt/freeware/include" + DEFAULT_CUPS=yes + ]) + else + AC_CHECK_HEADERS([cups/cups.h cups/ppd.h], [ + CUPS_FOUND=yes + CUPS_CFLAGS= + DEFAULT_CUPS=yes + ]) + fi fi if test "x$CUPS_FOUND" = xno; then HELP_MSG_MISSING_DEPENDENCY([cups]) diff --git a/make/autoconf/lib-tests.m4 b/make/autoconf/lib-tests.m4 index aa02ac4ef976f..f44a64e18b443 100644 --- a/make/autoconf/lib-tests.m4 +++ b/make/autoconf/lib-tests.m4 @@ -28,7 +28,7 @@ ################################################################################ # Minimum supported versions -JTREG_MINIMUM_VERSION=7.2 +JTREG_MINIMUM_VERSION=7.3.1 GTEST_MINIMUM_VERSION=1.13.0 ############################################################################### @@ -227,12 +227,47 @@ AC_DEFUN_ONCE([LIB_TESTS_SETUP_JTREG], UTIL_FIXUP_PATH(JT_HOME) AC_SUBST(JT_HOME) + # Specify a JDK for running jtreg. Defaults to the BOOT_JDK. + AC_ARG_WITH(jtreg-jdk, [AS_HELP_STRING([--with-jdk], + [path to JDK for running jtreg @<:@BOOT_JDK@:>@])]) + + AC_MSG_CHECKING([for jtreg jdk]) + if test "x${with_jtreg_jdk}" != x; then + if test "x${with_jtreg_jdk}" = xno; then + AC_MSG_RESULT([no, jtreg jdk not specified]) + elif test "x${with_jtreg_jdk}" = xyes; then + AC_MSG_RESULT([not specified]) + AC_MSG_ERROR([--with-jtreg-jdk needs a value]) + else + JTREG_JDK="${with_jtreg_jdk}" + AC_MSG_RESULT([$JTREG_JDK]) + UTIL_FIXUP_PATH(JTREG_JDK) + if test ! -f "$JTREG_JDK/bin/java"; then + AC_MSG_ERROR([Could not find jtreg java at $JTREG_JDK/bin/java]) + fi + fi + else + JTREG_JDK="${BOOT_JDK}" + AC_MSG_RESULT([no, using BOOT_JDK]) + fi + + UTIL_FIXUP_PATH(JTREG_JDK) + AC_SUBST([JTREG_JDK]) + # For use in the configure script + JTREG_JAVA="$FIXPATH $JTREG_JDK/bin/java" + # Verify jtreg version if test "x$JT_HOME" != x; then + AC_MSG_CHECKING([jtreg jar existence]) + if test ! -f "$JT_HOME/lib/jtreg.jar"; then + AC_MSG_ERROR([Could not find jtreg jar at $JT_HOME/lib/jtreg.jar]) + fi + AC_MSG_CHECKING([jtreg version number]) # jtreg -version looks like this: "jtreg 6.1+1-19" # Extract actual version part ("6.1" in this case) - jtreg_version_full=`$JAVA -jar $JT_HOME/lib/jtreg.jar -version | $HEAD -n 1 | $CUT -d ' ' -f 2` + jtreg_version_full=$($JTREG_JAVA -jar $JT_HOME/lib/jtreg.jar -version | $HEAD -n 1 | $CUT -d ' ' -f 2) + jtreg_version=${jtreg_version_full/%+*} AC_MSG_RESULT([$jtreg_version]) diff --git a/make/autoconf/lib-x11.m4 b/make/autoconf/lib-x11.m4 index 97a3f24a2dbf7..b1902a432a1e0 100644 --- a/make/autoconf/lib-x11.m4 +++ b/make/autoconf/lib-x11.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ AC_DEFUN_ONCE([LIB_SETUP_X11], X_CFLAGS= X_LIBS= else + x_libraries_orig="$x_libraries" if test "x${with_x}" = xno; then AC_MSG_ERROR([It is not possible to disable the use of X11. Remove the --without-x option.]) @@ -48,6 +49,7 @@ AC_DEFUN_ONCE([LIB_SETUP_X11], fi if test "x$x_libraries" = xNONE; then x_libraries="${with_x}/lib" + x_libraries_orig="$x_libraries" fi else # Check if the user has specified sysroot, but not --with-x, --x-includes or --x-libraries. @@ -82,8 +84,8 @@ AC_DEFUN_ONCE([LIB_SETUP_X11], AC_PATH_XTRA # AC_PATH_XTRA creates X_LIBS and sometimes adds -R flags. When cross compiling - # this doesn't make sense so we remove it. - if test "x$COMPILE_TYPE" = xcross; then + # this doesn't make sense so we remove it; same for sysroot (devkit). + if test "x$COMPILE_TYPE" = xcross || (test "x$SYSROOT" != "x" && test "x$x_libraries_orig" = xNONE); then X_LIBS=`$ECHO $X_LIBS | $SED 's/-R \{0,1\}[[^ ]]*//g'` fi diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4 index ebad69d9dcf75..feb0bcf3e753e 100644 --- a/make/autoconf/libraries.m4 +++ b/make/autoconf/libraries.m4 @@ -109,12 +109,6 @@ AC_DEFUN([LIB_SETUP_JVM_LIBS], BASIC_JVM_LIBS_$1="$BASIC_JVM_LIBS_$1 -latomic" fi fi - - # Because RISC-V only has word-sized atomics, it requires libatomic where - # other common architectures do not, so link libatomic by default. - if test "x$OPENJDK_$1_OS" = xlinux && test "x$OPENJDK_$1_CPU" = xriscv64; then - BASIC_JVM_LIBS_$1="$BASIC_JVM_LIBS_$1 -latomic" - fi ]) ################################################################################ diff --git a/make/autoconf/platform.m4 b/make/autoconf/platform.m4 index 0c987e9e9ab14..df610cc489bd3 100644 --- a/make/autoconf/platform.m4 +++ b/make/autoconf/platform.m4 @@ -567,8 +567,6 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER], HOTSPOT_$1_CPU_DEFINE=PPC64 elif test "x$OPENJDK_$1_CPU" = xppc64le; then HOTSPOT_$1_CPU_DEFINE=PPC64 - elif test "x$OPENJDK_$1_CPU" = xriscv32; then - HOTSPOT_$1_CPU_DEFINE=RISCV32 elif test "x$OPENJDK_$1_CPU" = xriscv64; then HOTSPOT_$1_CPU_DEFINE=RISCV64 @@ -577,10 +575,14 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER], HOTSPOT_$1_CPU_DEFINE=SPARC elif test "x$OPENJDK_$1_CPU" = xppc; then HOTSPOT_$1_CPU_DEFINE=PPC32 + elif test "x$OPENJDK_$1_CPU" = xriscv32; then + HOTSPOT_$1_CPU_DEFINE=RISCV32 elif test "x$OPENJDK_$1_CPU" = xs390; then HOTSPOT_$1_CPU_DEFINE=S390 elif test "x$OPENJDK_$1_CPU" = xs390x; then HOTSPOT_$1_CPU_DEFINE=S390 + elif test "x$OPENJDK_$1_CPU" = xloongarch64; then + HOTSPOT_$1_CPU_DEFINE=LOONGARCH64 elif test "x$OPENJDK_$1_CPU" != x; then HOTSPOT_$1_CPU_DEFINE=$(echo $OPENJDK_$1_CPU | tr a-z A-Z) fi diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in index 9419562b654e5..4d7abc334277c 100644 --- a/make/autoconf/spec.gmk.in +++ b/make/autoconf/spec.gmk.in @@ -191,6 +191,7 @@ PRODUCT_NAME:=@PRODUCT_NAME@ PRODUCT_SUFFIX:=@PRODUCT_SUFFIX@ JDK_RC_PLATFORM_NAME:=@JDK_RC_PLATFORM_NAME@ JDK_RC_NAME:=@JDK_RC_NAME@ +JDK_RC_COMPANY_NAME:=@JDK_RC_COMPANY_NAME@ COMPANY_NAME:=@COMPANY_NAME@ HOTSPOT_VM_DISTRO:=@HOTSPOT_VM_DISTRO@ MACOSX_BUNDLE_NAME_BASE=@MACOSX_BUNDLE_NAME_BASE@ @@ -424,6 +425,7 @@ LIBFFI_CFLAGS:=@LIBFFI_CFLAGS@ ENABLE_LIBFFI_BUNDLING:=@ENABLE_LIBFFI_BUNDLING@ LIBFFI_LIB_FILE:=@LIBFFI_LIB_FILE@ FILE_MACRO_CFLAGS := @FILE_MACRO_CFLAGS@ +REPRODUCIBLE_CFLAGS := @REPRODUCIBLE_CFLAGS@ BRANCH_PROTECTION_CFLAGS := @BRANCH_PROTECTION_CFLAGS@ STATIC_LIBS_CFLAGS := @STATIC_LIBS_CFLAGS@ @@ -601,6 +603,7 @@ AR := @AR@ ARFLAGS:=@ARFLAGS@ NM:=@NM@ +NMFLAGS:=@NMFLAGS@ STRIP:=@STRIP@ OBJDUMP:=@OBJDUMP@ CXXFILT:=@CXXFILT@ @@ -678,6 +681,9 @@ JAR = $(JAR_CMD) JLINK = $(JLINK_CMD) JMOD = $(JMOD_CMD) +JTREG_JDK := @JTREG_JDK@ +JTREG_JAVA = @FIXPATH@ $(JTREG_JDK)/bin/java $(JAVA_FLAGS_BIG) $(JAVA_FLAGS) + BUILD_JAVA_FLAGS := @BOOTCYCLE_JVM_ARGS_BIG@ BUILD_JAVA=@FIXPATH@ $(BUILD_JDK)/bin/java $(BUILD_JAVA_FLAGS) BUILD_JAVAC=@FIXPATH@ $(BUILD_JDK)/bin/javac diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index c89aab11d4bcb..7a24815d163f5 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -389,6 +389,10 @@ AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION], # This is necessary since AC_PROG_CC defaults CFLAGS to "-g -O2" CFLAGS="$ORG_CFLAGS" CXXFLAGS="$ORG_CXXFLAGS" + + # filter out some unwanted additions autoconf may add to CXX; we saw this on macOS with autoconf 2.72 + UTIL_GET_NON_MATCHING_VALUES(cxx_filtered, $CXX, -std=c++11 -std=gnu++11) + CXX="$cxx_filtered" ]) # Check if a compiler is of the toolchain type we expect, and save the version @@ -804,7 +808,11 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_EXTRA], case $TOOLCHAIN_TYPE in gcc|clang) - UTIL_REQUIRE_TOOLCHAIN_PROGS(CXXFILT, c++filt) + if test "x$OPENJDK_TARGET_OS" = xaix; then + UTIL_REQUIRE_TOOLCHAIN_PROGS(CXXFILT, ibm-llvm-cxxfilt) + else + UTIL_REQUIRE_TOOLCHAIN_PROGS(CXXFILT, c++filt) + fi ;; esac ]) diff --git a/make/autoconf/util.m4 b/make/autoconf/util.m4 index 83349aea99d0b..76426005f81d0 100644 --- a/make/autoconf/util.m4 +++ b/make/autoconf/util.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -199,7 +199,7 @@ AC_DEFUN([UTIL_GET_NON_MATCHING_VALUES], if test -z "$legal_values"; then $1="$2" else - result=`$GREP -Fvx "$legal_values" <<< "$values_to_check" | $GREP -v '^$'` + result=`$GREP -Fvx -- "$legal_values" <<< "$values_to_check" | $GREP -v '^$'` $1=${result//$'\n'/ } fi ]) @@ -226,7 +226,7 @@ AC_DEFUN([UTIL_GET_MATCHING_VALUES], if test -z "$illegal_values"; then $1="" else - result=`$GREP -Fx "$illegal_values" <<< "$values_to_check" | $GREP -v '^$'` + result=`$GREP -Fx -- "$illegal_values" <<< "$values_to_check" | $GREP -v '^$'` $1=${result//$'\n'/ } fi ]) diff --git a/make/autoconf/util_paths.m4 b/make/autoconf/util_paths.m4 index 3dd6ea7b489a2..8b2c776397bf6 100644 --- a/make/autoconf/util_paths.m4 +++ b/make/autoconf/util_paths.m4 @@ -118,6 +118,24 @@ AC_DEFUN([UTIL_FIXUP_PATH], fi ]) +############################################################################## +# Fixup path to be a Windows full long path +# Note: Only supported with cygwin/msys2 (cygpath tool) +AC_DEFUN([UTIL_FIXUP_WIN_LONG_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 + win_path=$($PATHTOOL -wl "$path") + if test "x$win_path" != "x$path"; then + $1="$win_path" + fi + fi + fi +]) + + ############################################################################### # Check if the given file is a unix-style or windows-style executable, that is, # if it expects paths in unix-style or windows-style. diff --git a/make/common/JdkNativeCompilation.gmk b/make/common/JdkNativeCompilation.gmk index 6a963ac2c498a..1a1333cf51707 100644 --- a/make/common/JdkNativeCompilation.gmk +++ b/make/common/JdkNativeCompilation.gmk @@ -98,7 +98,7 @@ GLOBAL_VERSION_INFO_RESOURCE := $(TOPDIR)/src/java.base/windows/native/common/ve JDK_RCFLAGS=$(RCFLAGS) \ -D"JDK_VERSION_STRING=$(VERSION_STRING)" \ - -D"JDK_COMPANY=$(COMPANY_NAME)" \ + -D"JDK_COMPANY=$(JDK_RC_COMPANY_NAME)" \ -D"JDK_VER=$(VERSION_NUMBER_FOUR_POSITIONS)" \ -D"JDK_COPYRIGHT=Copyright \xA9 $(COPYRIGHT_YEAR)" \ -D"JDK_NAME=$(JDK_RC_NAME) $(VERSION_SHORT)" \ diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk index 0d7ab6a7ef339..65843829e4fdd 100644 --- a/make/common/NativeCompilation.gmk +++ b/make/common/NativeCompilation.gmk @@ -48,12 +48,12 @@ define GetSymbols $(SED) -e 's/#.*//;s/global://;s/local://;s/\;//;s/^[ ]*/_/;/^_$$$$/d' | \ $(EGREP) -v "JNI_OnLoad|JNI_OnUnload|Agent_OnLoad|Agent_OnUnload|Agent_OnAttach" > \ $$(@D)/$$(basename $$(@F)).symbols || true; \ - $(NM) $$($1_TARGET) | $(GREP) " T " | \ + $(NM) $(NMFLAGS) $$($1_TARGET) | $(GREP) " T " | \ $(EGREP) "JNI_OnLoad|JNI_OnUnload|Agent_OnLoad|Agent_OnUnload|Agent_OnAttach" | \ $(CUT) -d ' ' -f 3 >> $$(@D)/$$(basename $$(@F)).symbols || true;\ else \ $(ECHO) "Getting symbols from nm"; \ - $(NM) -m $$($1_TARGET) | $(GREP) "__TEXT" | \ + $(NM) $(NMFLAGS) -m $$($1_TARGET) | $(GREP) "__TEXT" | \ $(EGREP) -v "non-external|private extern|__TEXT,__eh_frame" | \ $(SED) -e 's/.* //' > $$(@D)/$$(basename $$(@F)).symbols; \ fi @@ -1050,13 +1050,13 @@ define SetupNativeCompilationBody ifneq ($$($1_TYPE), STATIC_LIBRARY) # Generate debuginfo files. ifeq ($(call isTargetOs, windows), true) - $1_EXTRA_LDFLAGS += -debug "-pdb:$$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).pdb" \ - "-map:$$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).map" + $1_EXTRA_LDFLAGS += -debug "-pdb:$$($1_SYMBOLS_DIR)/$$($1_BASENAME).pdb" \ + "-map:$$($1_SYMBOLS_DIR)/$$($1_BASENAME).map" ifeq ($(SHIP_DEBUG_SYMBOLS), public) - $1_EXTRA_LDFLAGS += "-pdbstripped:$$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).stripped.pdb" + $1_EXTRA_LDFLAGS += "-pdbstripped:$$($1_SYMBOLS_DIR)/$$($1_BASENAME).stripped.pdb" endif - $1_DEBUGINFO_FILES := $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).pdb \ - $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).map + $1_DEBUGINFO_FILES := $$($1_SYMBOLS_DIR)/$$($1_BASENAME).pdb \ + $$($1_SYMBOLS_DIR)/$$($1_BASENAME).map else ifeq ($(call isTargetOs, linux), true) $1_DEBUGINFO_FILES := $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).debuginfo @@ -1104,7 +1104,11 @@ define SetupNativeCompilationBody $1 += $$($1_DEBUGINFO_FILES) ifeq ($$($1_ZIP_EXTERNAL_DEBUG_SYMBOLS), true) - $1_DEBUGINFO_ZIP := $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).diz + ifeq ($(call isTargetOs, windows), true) + $1_DEBUGINFO_ZIP := $$($1_SYMBOLS_DIR)/$$($1_BASENAME).diz + else + $1_DEBUGINFO_ZIP := $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).diz + endif $1 += $$($1_DEBUGINFO_ZIP) # The dependency on TARGET is needed for debuginfo files diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf index 35d26baaccb3f..3a08380a8b6aa 100644 --- a/make/conf/github-actions.conf +++ b/make/conf/github-actions.conf @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ # Versions and download locations for dependencies used by GitHub Actions (GHA) GTEST_VERSION=1.13.0 -JTREG_VERSION=7.2+1 +JTREG_VERSION=7.3.1+1 LINUX_X64_BOOT_JDK_EXT=tar.gz LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk20/bdc68b4b9cbc4ebcb30745c85038d91d/36/GPL/openjdk-20_linux-x64_bin.tar.gz @@ -36,6 +36,10 @@ MACOS_X64_BOOT_JDK_EXT=tar.gz MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk20/bdc68b4b9cbc4ebcb30745c85038d91d/36/GPL/openjdk-20_macos-x64_bin.tar.gz MACOS_X64_BOOT_JDK_SHA256=47cf960d9bb89dbe987535a389f7e26c42de7c984ef5108612d77c81aa8cc6a4 +MACOS_AARCH64_BOOT_JDK_EXT=tar.gz +MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk20/bdc68b4b9cbc4ebcb30745c85038d91d/36/GPL/openjdk-20_macos-aarch64_bin.tar.gz +MACOS_AARCH64_BOOT_JDK_SHA256=d020f5c512c043cfb7119a591bc7e599a5bfd76d866d939f5562891d9db7c9b3 + WINDOWS_X64_BOOT_JDK_EXT=zip WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk20/bdc68b4b9cbc4ebcb30745c85038d91d/36/GPL/openjdk-20_windows-x64_bin.zip WINDOWS_X64_BOOT_JDK_SHA256=c92fae5e42b9aecf444a66c8ec563c652f60b1e231dfdd33a4f5a3e3603058fb diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index da8f2f87a62e1..cf9097eee57c9 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -945,10 +945,7 @@ var getJibProfilesProfiles = function (input, common, data) { target_os: input.build_os, target_cpu: input.build_cpu, dependencies: [ "jtreg", "gnumake", "boot_jdk", "devkit", "jib" ], - labels: "test", - environment: { - "JT_JAVA": common.boot_jdk_home - } + labels: "test" } }; profiles = concatObjects(profiles, testOnlyProfiles); @@ -1188,9 +1185,9 @@ var getJibProfilesDependencies = function (input, common) { jtreg: { server: "jpg", product: "jtreg", - version: "7.2", + version: "7.3.1", build_number: "1", - file: "bundles/jtreg-7.2+1.zip", + file: "bundles/jtreg-7.3.1+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 985f986fc1ab3..b4571b544e2e7 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -28,15 +28,15 @@ DEFAULT_VERSION_FEATURE=21 DEFAULT_VERSION_INTERIM=0 -DEFAULT_VERSION_UPDATE=0 +DEFAULT_VERSION_UPDATE=3 DEFAULT_VERSION_PATCH=0 DEFAULT_VERSION_EXTRA1=0 DEFAULT_VERSION_EXTRA2=0 DEFAULT_VERSION_EXTRA3=0 -DEFAULT_VERSION_DATE=2023-09-19 +DEFAULT_VERSION_DATE=2024-04-16 DEFAULT_VERSION_CLASSFILE_MAJOR=65 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 DEFAULT_ACCEPTABLE_BOOT_VERSIONS="20 21" DEFAULT_JDK_SOURCE_TARGET_VERSION=21 -DEFAULT_PROMOTED_VERSION_PRE= +DEFAULT_PROMOTED_VERSION_PRE=ea diff --git a/make/data/charsetmapping/MS950_HKSCS.map b/make/data/charsetmapping/MS950_HKSCS.map new file mode 100644 index 0000000000000..77e2f014dc0dc --- /dev/null +++ b/make/data/charsetmapping/MS950_HKSCS.map @@ -0,0 +1,5019 @@ +# +# http://www.ogcio.gov.hk/ccli/eng/hskcs/mapping_table_2008.html +# +# commnent out following entries +# +# 88A3 <00EA,0304> +# 88A5 <00EA,030C> +# 8862 <00CA,0304> +# 8864 <00CA,030C> +# +8740 43F0 +8741 4C32 +8742 4603 +8743 45A6 +8744 4578 +8745 27267 +8746 4D77 +8747 45B3 +8748 27CB1 +8749 4CE2 +874A 27CC5 +874B 3B95 +874C 4736 +874D 4744 +874E 4C47 +874F 4C40 +8750 242BF +8751 23617 +8752 27352 +8753 26E8B +8754 270D2 +8755 4C57 +8756 2A351 +8757 474F +8758 45DA +8759 4C85 +875A 27C6C +875B 4D07 +875C 4AA4 +875D 46A1 +875E 26B23 +875F 7225 +8760 25A54 +8761 21A63 +8762 23E06 +8763 23F61 +8764 664D +8765 56FB +8767 7D95 +8768 591D +8769 28BB9 +876A 3DF4 +876B 9734 +876C 27BEF +876D 5BDB +876E 21D5E +876F 5AA4 +8770 3625 +8771 29EB0 +8772 5AD1 +8773 5BB7 +8774 5CFC +8775 676E +8776 8593 +8777 29945 +8778 7461 +8779 749D +877A 3875 +877B 21D53 +877C 2369E +877D 26021 +877E 3EEC +87A1 258DE +87A2 3AF5 +87A3 7AFC +87A4 9F97 +87A5 24161 +87A6 2890D +87A7 231EA +87A8 20A8A +87A9 2325E +87AA 430A +87AB 8484 +87AC 9F96 +87AD 942F +87AE 4930 +87AF 8613 +87B0 5896 +87B1 974A +87B2 9218 +87B3 79D0 +87B4 7A32 +87B5 6660 +87B6 6A29 +87B7 889D +87B8 744C +87B9 7BC5 +87BA 6782 +87BB 7A2C +87BC 524F +87BD 9046 +87BE 34E6 +87BF 73C4 +87C0 25DB9 +87C1 74C6 +87C2 9FC7 +87C3 57B3 +87C4 492F +87C5 544C +87C6 4131 +87C7 2368E +87C8 5818 +87C9 7A72 +87CA 27B65 +87CB 8B8F +87CC 46AE +87CD 26E88 +87CE 4181 +87CF 25D99 +87D0 7BAE +87D1 224BC +87D2 9FC8 +87D3 224C1 +87D4 224C9 +87D5 224CC +87D6 9FC9 +87D7 8504 +87D8 235BB +87D9 40B4 +87DA 9FCA +87DB 44E1 +87DC 2ADFF +87DD 62C1 +87DE 706E +87DF 9FCB +8840 31C0 +8841 31C1 +8842 31C2 +8843 31C3 +8844 31C4 +8845 2010C +8846 31C5 +8847 200D1 +8848 200CD +8849 31C6 +884A 31C7 +884B 200CB +884C 21FE8 +884D 31C8 +884E 200CA +884F 31C9 +8850 31CA +8851 31CB +8852 31CC +8853 2010E +8854 31CD +8855 31CE +8856 0100 +8857 00C1 +8858 01CD +8859 00C0 +885A 0112 +885B 00C9 +885C 011A +885D 00C8 +885E 014C +885F 00D3 +8860 01D1 +8861 00D2 +#8862 <00CA,0304> +8863 1EBE +#8864 <00CA,030C> +8865 1EC0 +8866 00CA +8867 0101 +8868 00E1 +8869 01CE +886A 00E0 +886B 0251 +886C 0113 +886D 00E9 +886E 011B +886F 00E8 +8870 012B +8871 00ED +8872 01D0 +8873 00EC +8874 014D +8875 00F3 +8876 01D2 +8877 00F2 +8878 016B +8879 00FA +887A 01D4 +887B 00F9 +887C 01D6 +887D 01D8 +887E 01DA +88A1 01DC +88A2 00FC +#88A3 <00EA,0304> +88A4 1EBF +#88A5 <00EA,030C> +88A6 1EC1 +88A7 00EA +88A8 0261 +88A9 23DA +88AA 23DB +8940 2A3A9 +8941 21145 +8943 650A +8946 4E3D +8947 6EDD +8948 9D4E +8949 91DF +894C 27735 +894D 6491 +894E 4F1A +894F 4F28 +8950 4FA8 +8951 5156 +8952 5174 +8953 519C +8954 51E4 +8955 52A1 +8956 52A8 +8957 533B +8958 534E +8959 53D1 +895A 53D8 +895B 56E2 +895C 58F0 +895D 5904 +895E 5907 +895F 5932 +8960 5934 +8961 5B66 +8962 5B9E +8963 5B9F +8964 5C9A +8965 5E86 +8966 603B +8967 6589 +8968 67FE +8969 6804 +896A 6865 +896B 6D4E +896C 70BC +896D 7535 +896E 7EA4 +896F 7EAC +8970 7EBA +8971 7EC7 +8972 7ECF +8973 7EDF +8974 7F06 +8975 7F37 +8976 827A +8977 82CF +8978 836F +8979 89C6 +897A 8BBE +897B 8BE2 +897C 8F66 +897D 8F67 +897E 8F6E +89A1 7411 +89A2 7CFC +89A3 7DCD +89A4 6946 +89A5 7AC9 +89A6 5227 +89AB 918C +89AC 78B8 +89AD 915E +89AE 80BC +89B0 8D0B +89B1 80F6 +89B2 209E7 +89B5 809F +89B6 9EC7 +89B7 4CCD +89B8 9DC9 +89B9 9E0C +89BA 4C3E +89BB 29DF6 +89BC 2700E +89BD 9E0A +89BE 2A133 +89BF 35C1 +89C1 6E9A +89C2 823E +89C3 7519 +89C5 4911 +89C6 9A6C +89C7 9A8F +89C8 9F99 +89C9 7987 +89CA 2846C +89CB 21DCA +89CC 205D0 +89CD 22AE6 +89CE 4E24 +89CF 4E81 +89D0 4E80 +89D1 4E87 +89D2 4EBF +89D3 4EEB +89D4 4F37 +89D5 344C +89D6 4FBD +89D7 3E48 +89D8 5003 +89D9 5088 +89DA 347D +89DB 3493 +89DC 34A5 +89DD 5186 +89DE 5905 +89DF 51DB +89E0 51FC +89E1 5205 +89E2 4E89 +89E3 5279 +89E4 5290 +89E5 5327 +89E6 35C7 +89E7 53A9 +89E8 3551 +89E9 53B0 +89EA 3553 +89EB 53C2 +89EC 5423 +89ED 356D +89EE 3572 +89EF 3681 +89F0 5493 +89F1 54A3 +89F2 54B4 +89F3 54B9 +89F4 54D0 +89F5 54EF +89F6 5518 +89F7 5523 +89F8 5528 +89F9 3598 +89FA 553F +89FB 35A5 +89FC 35BF +89FD 55D7 +89FE 35C5 +8A40 27D84 +8A41 5525 +8A43 20C42 +8A44 20D15 +8A45 2512B +8A46 5590 +8A47 22CC6 +8A48 39EC +8A49 20341 +8A4A 8E46 +8A4B 24DB8 +8A4C 294E5 +8A4D 4053 +8A4E 280BE +8A4F 777A +8A50 22C38 +8A51 3A34 +8A52 47D5 +8A53 2815D +8A54 269F2 +8A55 24DEA +8A56 64DD +8A57 20D7C +8A58 20FB4 +8A59 20CD5 +8A5A 210F4 +8A5B 648D +8A5C 8E7E +8A5D 20E96 +8A5E 20C0B +8A5F 20F64 +8A60 22CA9 +8A61 28256 +8A62 244D3 +8A64 20D46 +8A65 29A4D +8A66 280E9 +8A67 47F4 +8A68 24EA7 +8A69 22CC2 +8A6A 9AB2 +8A6B 3A67 +8A6C 295F4 +8A6D 3FED +8A6E 3506 +8A6F 252C7 +8A70 297D4 +8A71 278C8 +8A72 22D44 +8A73 9D6E +8A74 9815 +8A76 43D9 +8A77 260A5 +8A78 64B4 +8A79 54E3 +8A7A 22D4C +8A7B 22BCA +8A7C 21077 +8A7D 39FB +8A7E 2106F +8AA1 266DA +8AA2 26716 +8AA3 279A0 +8AA4 64EA +8AA5 25052 +8AA6 20C43 +8AA7 8E68 +8AA8 221A1 +8AA9 28B4C +8AAA 20731 +8AAC 480B +8AAD 201A9 +8AAE 3FFA +8AAF 5873 +8AB0 22D8D +8AB2 245C8 +8AB3 204FC +8AB4 26097 +8AB5 20F4C +8AB6 20D96 +8AB7 5579 +8AB8 40BB +8AB9 43BA +8ABB 4AB4 +8ABC 22A66 +8ABD 2109D +8ABE 81AA +8ABF 98F5 +8AC0 20D9C +8AC1 6379 +8AC2 39FE +8AC3 22775 +8AC4 8DC0 +8AC5 56A1 +8AC6 647C +8AC7 3E43 +8AC9 2A601 +8ACA 20E09 +8ACB 22ACF +8ACC 22CC9 +8ACE 210C8 +8ACF 239C2 +8AD0 3992 +8AD1 3A06 +8AD2 2829B +8AD3 3578 +8AD4 25E49 +8AD5 220C7 +8AD6 5652 +8AD7 20F31 +8AD8 22CB2 +8AD9 29720 +8ADA 34BC +8ADB 6C3D +8ADC 24E3B +8ADF 27574 +8AE0 22E8B +8AE1 22208 +8AE2 2A65B +8AE3 28CCD +8AE4 20E7A +8AE5 20C34 +8AE6 2681C +8AE7 7F93 +8AE8 210CF +8AE9 22803 +8AEA 22939 +8AEB 35FB +8AEC 251E3 +8AED 20E8C +8AEE 20F8D +8AEF 20EAA +8AF0 3F93 +8AF1 20F30 +8AF2 20D47 +8AF3 2114F +8AF4 20E4C +8AF6 20EAB +8AF7 20BA9 +8AF8 20D48 +8AF9 210C0 +8AFA 2113D +8AFB 3FF9 +8AFC 22696 +8AFD 6432 +8AFE 20FAD +8B40 233F4 +8B41 27639 +8B42 22BCE +8B43 20D7E +8B44 20D7F +8B45 22C51 +8B46 22C55 +8B47 3A18 +8B48 20E98 +8B49 210C7 +8B4A 20F2E +8B4B 2A632 +8B4C 26B50 +8B4D 28CD2 +8B4E 28D99 +8B4F 28CCA +8B50 95AA +8B51 54CC +8B52 82C4 +8B53 55B9 +8B55 29EC3 +8B56 9C26 +8B57 9AB6 +8B58 2775E +8B59 22DEE +8B5A 7140 +8B5B 816D +8B5C 80EC +8B5D 5C1C +8B5E 26572 +8B5F 8134 +8B60 3797 +8B61 535F +8B62 280BD +8B63 91B6 +8B64 20EFA +8B65 20E0F +8B66 20E77 +8B67 20EFB +8B68 35DD +8B69 24DEB +8B6A 3609 +8B6B 20CD6 +8B6C 56AF +8B6D 227B5 +8B6E 210C9 +8B6F 20E10 +8B70 20E78 +8B71 21078 +8B72 21148 +8B73 28207 +8B74 21455 +8B75 20E79 +8B76 24E50 +8B77 22DA4 +8B78 5A54 +8B79 2101D +8B7A 2101E +8B7B 210F5 +8B7C 210F6 +8B7D 579C +8B7E 20E11 +8BA1 27694 +8BA2 282CD +8BA3 20FB5 +8BA4 20E7B +8BA5 2517E +8BA6 3703 +8BA7 20FB6 +8BA8 21180 +8BA9 252D8 +8BAA 2A2BD +8BAB 249DA +8BAC 2183A +8BAD 24177 +8BAE 2827C +8BAF 5899 +8BB0 5268 +8BB1 361A +8BB2 2573D +8BB3 7BB2 +8BB4 5B68 +8BB5 4800 +8BB6 4B2C +8BB7 9F27 +8BB8 49E7 +8BB9 9C1F +8BBA 9B8D +8BBB 25B74 +8BBC 2313D +8BBD 55FB +8BBE 35F2 +8BBF 5689 +8BC0 4E28 +8BC1 5902 +8BC2 21BC1 +8BC3 2F878 +8BC4 9751 +8BC5 20086 +8BC6 4E5B +8BC7 4EBB +8BC8 353E +8BC9 5C23 +8BCA 5F51 +8BCB 5FC4 +8BCC 38FA +8BCD 624C +8BCE 6535 +8BCF 6B7A +8BD0 6C35 +8BD1 6C3A +8BD2 706C +8BD3 722B +8BD4 4E2C +8BD5 72AD +8BD6 248E9 +8BD7 7F52 +8BD8 793B +8BD9 7CF9 +8BDA 7F53 +8BDB 2626A +8BDC 34C1 +8BDE 2634B +8BDF 8002 +8BE0 8080 +8BE1 26612 +8BE2 26951 +8BE3 535D +8BE4 8864 +8BE5 89C1 +8BE6 278B2 +8BE7 8BA0 +8BE8 8D1D +8BE9 9485 +8BEA 9578 +8BEB 957F +8BEC 95E8 +8BED 28E0F +8BEE 97E6 +8BEF 9875 +8BF0 98CE +8BF1 98DE +8BF2 9963 +8BF3 29810 +8BF4 9C7C +8BF5 9E1F +8BF6 9EC4 +8BF7 6B6F +8BF8 F907 +8BF9 4E37 +8BFA 20087 +8BFB 961D +8BFC 6237 +8BFD 94A2 +8C40 503B +8C41 6DFE +8C42 29C73 +8C43 9FA6 +8C44 3DC9 +8C45 888F +8C46 2414E +8C47 7077 +8C48 5CF5 +8C49 4B20 +8C4A 251CD +8C4B 3559 +8C4C 25D30 +8C4D 6122 +8C4E 28A32 +8C4F 8FA7 +8C50 91F6 +8C51 7191 +8C52 6719 +8C53 73BA +8C54 23281 +8C55 2A107 +8C56 3C8B +8C57 21980 +8C58 4B10 +8C59 78E4 +8C5A 7402 +8C5B 51AE +8C5C 2870F +8C5D 4009 +8C5E 6A63 +8C5F 2A2BA +8C60 4223 +8C61 860F +8C62 20A6F +8C63 7A2A +8C64 29947 +8C65 28AEA +8C66 9755 +8C67 704D +8C68 5324 +8C69 2207E +8C6A 93F4 +8C6B 76D9 +8C6C 289E3 +8C6D 9FA7 +8C6E 77DD +8C6F 4EA3 +8C70 4FF0 +8C71 50BC +8C72 4E2F +8C73 4F17 +8C74 9FA8 +8C75 5434 +8C76 7D8B +8C77 5892 +8C78 58D0 +8C79 21DB6 +8C7A 5E92 +8C7B 5E99 +8C7C 5FC2 +8C7D 22712 +8C7E 658B +8CA1 233F9 +8CA2 6919 +8CA3 6A43 +8CA4 23C63 +8CA5 6CFF +8CA7 7200 +8CA8 24505 +8CA9 738C +8CAA 3EDB +8CAB 24A13 +8CAC 5B15 +8CAD 74B9 +8CAE 8B83 +8CAF 25CA4 +8CB0 25695 +8CB1 7A93 +8CB2 7BEC +8CB3 7CC3 +8CB4 7E6C +8CB5 82F8 +8CB6 8597 +8CB7 9FA9 +8CB8 8890 +8CB9 9FAA +8CBA 8EB9 +8CBB 9FAB +8CBC 8FCF +8CBD 855F +8CBE 99E0 +8CBF 9221 +8CC0 9FAC +8CC1 28DB9 +8CC2 2143F +8CC3 4071 +8CC4 42A2 +8CC5 5A1A +8CC9 9868 +8CCA 676B +8CCB 4276 +8CCC 573D +8CCE 85D6 +8CCF 2497B +8CD0 82BF +8CD1 2710D +8CD2 4C81 +8CD3 26D74 +8CD4 5D7B +8CD5 26B15 +8CD6 26FBE +8CD7 9FAD +8CD8 9FAE +8CD9 5B96 +8CDA 9FAF +8CDB 66E7 +8CDC 7E5B +8CDD 6E57 +8CDE 79CA +8CDF 3D88 +8CE0 44C3 +8CE1 23256 +8CE2 22796 +8CE3 439A +8CE4 4536 +8CE6 5CD5 +8CE7 23B1A +8CE8 8AF9 +8CE9 5C78 +8CEA 3D12 +8CEB 23551 +8CEC 5D78 +8CED 9FB2 +8CEE 7157 +8CEF 4558 +8CF0 240EC +8CF1 21E23 +8CF2 4C77 +8CF3 3978 +8CF4 344A +8CF5 201A4 +8CF6 26C41 +8CF7 8ACC +8CF8 4FB4 +8CF9 20239 +8CFA 59BF +8CFB 816C +8CFC 9856 +8CFD 298FA +8CFE 5F3B +8D40 20B9F +8D42 221C1 +8D43 2896D +8D44 4102 +8D45 46BB +8D46 29079 +8D47 3F07 +8D48 9FB3 +8D49 2A1B5 +8D4A 40F8 +8D4B 37D6 +8D4C 46F7 +8D4D 26C46 +8D4E 417C +8D4F 286B2 +8D50 273FF +8D51 456D +8D52 38D4 +8D53 2549A +8D54 4561 +8D55 451B +8D56 4D89 +8D57 4C7B +8D58 4D76 +8D59 45EA +8D5A 3FC8 +8D5B 24B0F +8D5C 3661 +8D5D 44DE +8D5E 44BD +8D5F 41ED +8D60 5D3E +8D61 5D48 +8D62 5D56 +8D63 3DFC +8D64 380F +8D65 5DA4 +8D66 5DB9 +8D67 3820 +8D68 3838 +8D69 5E42 +8D6A 5EBD +8D6B 5F25 +8D6C 5F83 +8D6D 3908 +8D6E 3914 +8D6F 393F +8D70 394D +8D71 60D7 +8D72 613D +8D73 5CE5 +8D74 3989 +8D75 61B7 +8D76 61B9 +8D77 61CF +8D78 39B8 +8D79 622C +8D7A 6290 +8D7B 62E5 +8D7C 6318 +8D7D 39F8 +8D7E 56B1 +8DA1 3A03 +8DA2 63E2 +8DA3 63FB +8DA4 6407 +8DA5 645A +8DA6 3A4B +8DA7 64C0 +8DA8 5D15 +8DA9 5621 +8DAA 9F9F +8DAB 3A97 +8DAC 6586 +8DAD 3ABD +8DAE 65FF +8DAF 6653 +8DB0 3AF2 +8DB1 6692 +8DB2 3B22 +8DB3 6716 +8DB4 3B42 +8DB5 67A4 +8DB6 6800 +8DB7 3B58 +8DB8 684A +8DB9 6884 +8DBA 3B72 +8DBB 3B71 +8DBC 3B7B +8DBD 6909 +8DBE 6943 +8DBF 725C +8DC0 6964 +8DC1 699F +8DC2 6985 +8DC3 3BBC +8DC4 69D6 +8DC5 3BDD +8DC6 6A65 +8DC7 6A74 +8DC8 6A71 +8DC9 6A82 +8DCA 3BEC +8DCB 6A99 +8DCC 3BF2 +8DCD 6AAB +8DCE 6AB5 +8DCF 6AD4 +8DD0 6AF6 +8DD1 6B81 +8DD2 6BC1 +8DD3 6BEA +8DD4 6C75 +8DD5 6CAA +8DD6 3CCB +8DD7 6D02 +8DD8 6D06 +8DD9 6D26 +8DDA 6D81 +8DDB 3CEF +8DDC 6DA4 +8DDD 6DB1 +8DDE 6E15 +8DDF 6E18 +8DE0 6E29 +8DE1 6E86 +8DE2 289C0 +8DE3 6EBB +8DE4 6EE2 +8DE5 6EDA +8DE6 9F7F +8DE7 6EE8 +8DE8 6EE9 +8DE9 6F24 +8DEA 6F34 +8DEB 3D46 +8DEC 23F41 +8DED 6F81 +8DEE 6FBE +8DEF 3D6A +8DF0 3D75 +8DF1 71B7 +8DF2 5C99 +8DF3 3D8A +8DF4 702C +8DF5 3D91 +8DF6 7050 +8DF7 7054 +8DF8 706F +8DF9 707F +8DFA 7089 +8DFB 20325 +8DFC 43C1 +8DFD 35F1 +8DFE 20ED8 +8E40 23ED7 +8E41 57BE +8E42 26ED3 +8E43 713E +8E44 257E0 +8E45 364E +8E46 69A2 +8E47 28BE9 +8E48 5B74 +8E49 7A49 +8E4A 258E1 +8E4B 294D9 +8E4C 7A65 +8E4D 7A7D +8E4E 259AC +8E4F 7ABB +8E50 7AB0 +8E51 7AC2 +8E52 7AC3 +8E53 71D1 +8E54 2648D +8E55 41CA +8E56 7ADA +8E57 7ADD +8E58 7AEA +8E59 41EF +8E5A 54B2 +8E5B 25C01 +8E5C 7B0B +8E5D 7B55 +8E5E 7B29 +8E5F 2530E +8E60 25CFE +8E61 7BA2 +8E62 7B6F +8E63 839C +8E64 25BB4 +8E65 26C7F +8E66 7BD0 +8E67 8421 +8E68 7B92 +8E6A 25D20 +8E6B 3DAD +8E6C 25C65 +8E6D 8492 +8E6E 7BFA +8E70 7C35 +8E71 25CC1 +8E72 7C44 +8E73 7C83 +8E74 24882 +8E75 7CA6 +8E76 667D +8E77 24578 +8E78 7CC9 +8E79 7CC7 +8E7A 7CE6 +8E7B 7C74 +8E7C 7CF3 +8E7D 7CF5 +8EA1 7E67 +8EA2 451D +8EA3 26E44 +8EA4 7D5D +8EA5 26ED6 +8EA6 748D +8EA7 7D89 +8EA8 7DAB +8EA9 7135 +8EAA 7DB3 +8EAC 24057 +8EAD 26029 +8EAE 7DE4 +8EAF 3D13 +8EB0 7DF5 +8EB1 217F9 +8EB2 7DE5 +8EB3 2836D +8EB5 26121 +8EB6 2615A +8EB7 7E6E +8EB8 7E92 +8EB9 432B +8EBA 946C +8EBB 7E27 +8EBC 7F40 +8EBD 7F41 +8EBE 7F47 +8EBF 7936 +8EC0 262D0 +8EC1 99E1 +8EC2 7F97 +8EC3 26351 +8EC4 7FA3 +8EC5 21661 +8EC6 20068 +8EC7 455C +8EC8 23766 +8EC9 4503 +8ECA 2833A +8ECB 7FFA +8ECC 26489 +8ECE 8008 +8ECF 801D +8ED1 802F +8ED2 2A087 +8ED3 26CC3 +8ED4 803B +8ED5 803C +8ED6 8061 +8ED7 22714 +8ED8 4989 +8ED9 26626 +8EDA 23DE3 +8EDB 266E8 +8EDC 6725 +8EDD 80A7 +8EDE 28A48 +8EDF 8107 +8EE0 811A +8EE1 58B0 +8EE2 226F6 +8EE3 6C7F +8EE4 26498 +8EE5 24FB8 +8EE6 64E7 +8EE7 2148A +8EE8 8218 +8EE9 2185E +8EEA 6A53 +8EEB 24A65 +8EEC 24A95 +8EED 447A +8EEE 8229 +8EEF 20B0D +8EF0 26A52 +8EF1 23D7E +8EF2 4FF9 +8EF3 214FD +8EF4 84E2 +8EF5 8362 +8EF6 26B0A +8EF7 249A7 +8EF8 23530 +8EF9 21773 +8EFA 23DF8 +8EFB 82AA +8EFC 691B +8EFD 2F994 +8EFE 41DB +8F40 854B +8F41 82D0 +8F42 831A +8F43 20E16 +8F44 217B4 +8F45 36C1 +8F46 2317D +8F47 2355A +8F48 827B +8F49 82E2 +8F4A 8318 +8F4B 23E8B +8F4C 26DA3 +8F4D 26B05 +8F4E 26B97 +8F4F 235CE +8F50 3DBF +8F51 831D +8F52 55EC +8F53 8385 +8F54 450B +8F55 26DA5 +8F56 83AC +8F58 83D3 +8F59 347E +8F5A 26ED4 +8F5B 6A57 +8F5C 855A +8F5D 3496 +8F5E 26E42 +8F5F 22EEF +8F60 8458 +8F61 25BE4 +8F62 8471 +8F63 3DD3 +8F64 44E4 +8F65 6AA7 +8F66 844A +8F67 23CB5 +8F68 7958 +8F6A 26B96 +8F6B 26E77 +8F6C 26E43 +8F6D 84DE +8F6F 8391 +8F70 44A0 +8F71 8493 +8F72 84E4 +8F73 25C91 +8F74 4240 +8F75 25CC0 +8F76 4543 +8F77 8534 +8F78 5AF2 +8F79 26E99 +8F7A 4527 +8F7B 8573 +8F7C 4516 +8F7D 67BF +8F7E 8616 +8FA1 28625 +8FA2 2863B +8FA3 85C1 +8FA4 27088 +8FA5 8602 +8FA6 21582 +8FA7 270CD +8FA8 2F9B2 +8FA9 456A +8FAA 8628 +8FAB 3648 +8FAC 218A2 +8FAD 53F7 +8FAE 2739A +8FAF 867E +8FB0 8771 +8FB1 2A0F8 +8FB2 87EE +8FB3 22C27 +8FB4 87B1 +8FB5 87DA +8FB6 880F +8FB7 5661 +8FB8 866C +8FB9 6856 +8FBA 460F +8FBB 8845 +8FBC 8846 +8FBD 275E0 +8FBE 23DB9 +8FBF 275E4 +8FC0 885E +8FC1 889C +8FC2 465B +8FC3 88B4 +8FC4 88B5 +8FC5 63C1 +8FC6 88C5 +8FC7 7777 +8FC8 2770F +8FC9 8987 +8FCA 898A +8FCD 89A7 +8FCE 89BC +8FCF 28A25 +8FD0 89E7 +8FD1 27924 +8FD2 27ABD +8FD3 8A9C +8FD4 7793 +8FD5 91FE +8FD6 8A90 +8FD7 27A59 +8FD8 7AE9 +8FD9 27B3A +8FDA 23F8F +8FDB 4713 +8FDC 27B38 +8FDD 717C +8FDE 8B0C +8FDF 8B1F +8FE0 25430 +8FE1 25565 +8FE2 8B3F +8FE3 8B4C +8FE4 8B4D +8FE5 8AA9 +8FE6 24A7A +8FE7 8B90 +8FE8 8B9B +8FE9 8AAF +8FEA 216DF +8FEB 4615 +8FEC 884F +8FED 8C9B +8FEE 27D54 +8FEF 27D8F +8FF0 2F9D4 +8FF1 3725 +8FF2 27D53 +8FF3 8CD6 +8FF4 27D98 +8FF5 27DBD +8FF6 8D12 +8FF7 8D03 +8FF8 21910 +8FF9 8CDB +8FFA 705C +8FFB 8D11 +8FFC 24CC9 +8FFD 3ED0 +9040 8DA9 +9041 28002 +9042 21014 +9043 2498A +9044 3B7C +9045 281BC +9046 2710C +9047 7AE7 +9048 8EAD +9049 8EB6 +904A 8EC3 +904B 92D4 +904C 8F19 +904D 8F2D +904E 28365 +904F 28412 +9050 8FA5 +9051 9303 +9052 2A29F +9053 20A50 +9054 8FB3 +9055 492A +9056 289DE +9057 2853D +9058 23DBB +9059 5EF8 +905A 23262 +905B 8FF9 +905C 2A014 +905D 286BC +905E 28501 +905F 22325 +9060 3980 +9061 26ED7 +9062 9037 +9063 2853C +9064 27ABE +9065 9061 +9066 2856C +9067 2860B +9068 90A8 +9069 28713 +906A 90C4 +906B 286E6 +906C 90AE +906E 9167 +906F 3AF0 +9070 91A9 +9071 91C4 +9072 7CAC +9073 28933 +9074 21E89 +9075 920E +9076 6C9F +9077 9241 +9078 9262 +9079 255B9 +907B 28AC6 +907C 23C9B +907D 28B0C +907E 255DB +90A1 20D31 +90A2 932C +90A3 936B +90A4 28AE1 +90A5 28BEB +90A6 708F +90A7 5AC3 +90A8 28AE2 +90A9 28AE5 +90AA 4965 +90AB 9244 +90AC 28BEC +90AD 28C39 +90AE 28BFF +90AF 9373 +90B0 945B +90B1 8EBC +90B2 9585 +90B3 95A6 +90B4 9426 +90B5 95A0 +90B6 6FF6 +90B7 42B9 +90B8 2267A +90B9 286D8 +90BA 2127C +90BB 23E2E +90BC 49DF +90BD 6C1C +90BE 967B +90BF 9696 +90C0 416C +90C1 96A3 +90C2 26ED5 +90C3 61DA +90C4 96B6 +90C5 78F5 +90C6 28AE0 +90C7 96BD +90C8 53CC +90C9 49A1 +90CA 26CB8 +90CB 20274 +90CC 26410 +90CD 290AF +90CE 290E5 +90CF 24AD1 +90D0 21915 +90D1 2330A +90D2 9731 +90D3 8642 +90D4 9736 +90D5 4A0F +90D6 453D +90D7 4585 +90D8 24AE9 +90D9 7075 +90DA 5B41 +90DB 971B +90DD 291D5 +90DE 9757 +90DF 5B4A +90E0 291EB +90E1 975F +90E2 9425 +90E3 50D0 +90E4 230B7 +90E5 230BC +90E6 9789 +90E7 979F +90E8 97B1 +90E9 97BE +90EA 97C0 +90EB 97D2 +90EC 97E0 +90ED 2546C +90EE 97EE +90EF 741C +90F0 29433 +90F2 97F5 +90F3 2941D +90F4 2797A +90F5 4AD1 +90F6 9834 +90F7 9833 +90F8 984B +90F9 9866 +90FA 3B0E +90FB 27175 +90FC 3D51 +90FD 20630 +90FE 2415C +9140 25706 +9141 98CA +9142 98B7 +9143 98C8 +9144 98C7 +9145 4AFF +9146 26D27 +9147 216D3 +9148 55B0 +9149 98E1 +914A 98E6 +914B 98EC +914C 9378 +914D 9939 +914E 24A29 +914F 4B72 +9150 29857 +9151 29905 +9152 99F5 +9153 9A0C +9154 9A3B +9155 9A10 +9156 9A58 +9157 25725 +9158 36C4 +9159 290B1 +915A 29BD5 +915B 9AE0 +915C 9AE2 +915D 29B05 +915E 9AF4 +915F 4C0E +9160 9B14 +9161 9B2D +9162 28600 +9163 5034 +9164 9B34 +9165 269A8 +9166 38C3 +9167 2307D +9168 9B50 +9169 9B40 +916A 29D3E +916B 5A45 +916C 21863 +916D 9B8E +916E 2424B +916F 9C02 +9170 9BFF +9171 9C0C +9172 29E68 +9173 9DD4 +9174 29FB7 +9175 2A192 +9176 2A1AB +9177 2A0E1 +9178 2A123 +9179 2A1DF +917A 9D7E +917B 9D83 +917C 2A134 +917D 9E0E +917E 6888 +91A1 9DC4 +91A2 2215B +91A3 2A193 +91A4 2A220 +91A5 2193B +91A6 2A233 +91A7 9D39 +91A8 2A0B9 +91A9 2A2B4 +91AA 9E90 +91AB 9E95 +91AC 9E9E +91AD 9EA2 +91AE 4D34 +91AF 9EAA +91B0 9EAF +91B1 24364 +91B2 9EC1 +91B3 3B60 +91B4 39E5 +91B5 3D1D +91B6 4F32 +91B7 37BE +91B8 28C2B +91B9 9F02 +91BA 9F08 +91BB 4B96 +91BC 9424 +91BD 26DA2 +91BE 9F17 +91C0 9F39 +91C1 569F +91C2 568A +91C3 9F45 +91C4 99B8 +91C5 2908B +91C6 97F2 +91C7 847F +91C8 9F62 +91C9 9F69 +91CA 7ADC +91CB 9F8E +91CC 7216 +91CD 4BBE +91CE 24975 +91CF 249BB +91D0 7177 +91D1 249F8 +91D2 24348 +91D3 24A51 +91D4 739E +91D5 28BDA +91D6 218FA +91D7 799F +91D8 2897E +91D9 28E36 +91DA 9369 +91DB 93F3 +91DC 28A44 +91DD 92EC +91DE 9381 +91DF 93CB +91E0 2896C +91E1 244B9 +91E2 7217 +91E3 3EEB +91E4 7772 +91E5 7A43 +91E6 70D0 +91E7 24473 +91E8 243F8 +91E9 717E +91EA 217EF +91EB 70A3 +91EC 218BE +91ED 23599 +91EE 3EC7 +91EF 21885 +91F0 2542F +91F1 217F8 +91F2 3722 +91F3 216FB +91F4 21839 +91F5 36E1 +91F6 21774 +91F7 218D1 +91F8 25F4B +91F9 3723 +91FA 216C0 +91FB 575B +91FC 24A25 +91FD 213FE +91FE 212A8 +9240 213C6 +9241 214B6 +9242 8503 +9243 236A6 +9245 8455 +9246 24994 +9247 27165 +9248 23E31 +9249 2555C +924A 23EFB +924B 27052 +924C 44F4 +924D 236EE +924E 2999D +924F 26F26 +9250 67F9 +9251 3733 +9252 3C15 +9253 3DE7 +9254 586C +9255 21922 +9256 6810 +9257 4057 +9258 2373F +9259 240E1 +925A 2408B +925B 2410F +925C 26C21 +925D 54CB +925E 569E +925F 266B1 +9260 5692 +9261 20FDF +9262 20BA8 +9263 20E0D +9264 93C6 +9265 28B13 +9266 939C +9267 4EF8 +9268 512B +9269 3819 +926A 24436 +926B 4EBC +926C 20465 +926D 2037F +926E 4F4B +926F 4F8A +9270 25651 +9271 5A68 +9272 201AB +9273 203CB +9274 3999 +9275 2030A +9276 20414 +9277 3435 +9278 4F29 +9279 202C0 +927A 28EB3 +927B 20275 +927C 8ADA +927D 2020C +927E 4E98 +92A1 50CD +92A2 510D +92A3 4FA2 +92A4 4F03 +92A5 24A0E +92A6 23E8A +92A7 4F42 +92A8 502E +92A9 506C +92AA 5081 +92AB 4FCC +92AC 4FE5 +92AD 5058 +92AE 50FC +92B3 6E76 +92B4 23595 +92B5 23E39 +92B6 23EBF +92B7 6D72 +92B8 21884 +92B9 23E89 +92BA 51A8 +92BB 51C3 +92BC 205E0 +92BD 44DD +92BE 204A3 +92BF 20492 +92C0 20491 +92C1 8D7A +92C2 28A9C +92C3 2070E +92C4 5259 +92C5 52A4 +92C6 20873 +92C7 52E1 +92C9 467A +92CA 718C +92CB 2438C +92CC 20C20 +92CD 249AC +92CE 210E4 +92CF 69D1 +92D0 20E1D +92D2 3EDE +92D3 7499 +92D4 7414 +92D5 7456 +92D6 7398 +92D7 4B8E +92D8 24ABC +92D9 2408D +92DA 53D0 +92DB 3584 +92DC 720F +92DD 240C9 +92DE 55B4 +92DF 20345 +92E0 54CD +92E1 20BC6 +92E2 571D +92E3 925D +92E4 96F4 +92E5 9366 +92E6 57DD +92E7 578D +92E8 577F +92E9 363E +92EA 58CB +92EB 5A99 +92EC 28A46 +92ED 216FA +92EE 2176F +92EF 21710 +92F0 5A2C +92F1 59B8 +92F2 928F +92F3 5A7E +92F4 5ACF +92F5 5A12 +92F6 25946 +92F7 219F3 +92F8 21861 +92F9 24295 +92FA 36F5 +92FB 6D05 +92FC 7443 +92FD 5A21 +92FE 25E83 +9340 5A81 +9341 28BD7 +9342 20413 +9343 93E0 +9344 748C +9345 21303 +9346 7105 +9347 4972 +9348 9408 +9349 289FB +934A 93BD +934B 37A0 +934C 5C1E +934D 5C9E +934E 5E5E +934F 5E48 +9350 21996 +9351 2197C +9352 23AEE +9353 5ECD +9354 5B4F +9355 21903 +9356 21904 +9357 3701 +9358 218A0 +9359 36DD +935A 216FE +935B 36D3 +935C 812A +935D 28A47 +935E 21DBA +935F 23472 +9360 289A8 +9361 5F0C +9362 5F0E +9363 21927 +9364 217AB +9365 5A6B +9366 2173B +9367 5B44 +9368 8614 +9369 275FD +936A 8860 +936B 607E +936C 22860 +936D 2262B +936E 5FDB +936F 3EB8 +9370 225AF +9371 225BE +9372 29088 +9373 26F73 +9374 61C0 +9375 2003E +9376 20046 +9377 2261B +9378 6199 +9379 6198 +937A 6075 +937B 22C9B +937C 22D07 +937D 246D4 +937E 2914D +93A1 6471 +93A2 24665 +93A3 22B6A +93A4 3A29 +93A5 22B22 +93A6 23450 +93A7 298EA +93A8 22E78 +93A9 6337 +93AA 2A45B +93AB 64B6 +93AC 6331 +93AD 63D1 +93AE 249E3 +93AF 22D67 +93B0 62A4 +93B1 22CA1 +93B2 643B +93B3 656B +93B4 6972 +93B5 3BF4 +93B6 2308E +93B7 232AD +93B8 24989 +93B9 232AB +93BA 550D +93BB 232E0 +93BC 218D9 +93BD 2943F +93BE 66CE +93BF 23289 +93C0 231B3 +93C1 3AE0 +93C2 4190 +93C3 25584 +93C4 28B22 +93C5 2558F +93C6 216FC +93C7 2555B +93C8 25425 +93C9 78EE +93CA 23103 +93CB 2182A +93CC 23234 +93CD 3464 +93CE 2320F +93CF 23182 +93D0 242C9 +93D1 668E +93D2 26D24 +93D3 666B +93D4 4B93 +93D5 6630 +93D6 27870 +93D7 21DEB +93D8 6663 +93D9 232D2 +93DA 232E1 +93DB 661E +93DC 25872 +93DD 38D1 +93DE 2383A +93DF 237BC +93E0 3B99 +93E1 237A2 +93E2 233FE +93E3 74D0 +93E4 3B96 +93E5 678F +93E6 2462A +93E7 68B6 +93E8 681E +93E9 3BC4 +93EA 6ABE +93EB 3863 +93EC 237D5 +93ED 24487 +93EE 6A33 +93EF 6A52 +93F0 6AC9 +93F1 6B05 +93F2 21912 +93F3 6511 +93F4 6898 +93F5 6A4C +93F6 3BD7 +93F7 6A7A +93F8 6B57 +93F9 23FC0 +93FA 23C9A +93FB 93A0 +93FC 92F2 +93FD 28BEA +93FE 28ACB +9440 9289 +9441 2801E +9442 289DC +9443 9467 +9444 6DA5 +9445 6F0B +9446 249EC +9448 23F7F +9449 3D8F +944A 6E04 +944B 2403C +944C 5A3D +944D 6E0A +944E 5847 +944F 6D24 +9450 7842 +9451 713B +9452 2431A +9453 24276 +9454 70F1 +9455 7250 +9456 7287 +9457 7294 +9458 2478F +9459 24725 +945A 5179 +945B 24AA4 +945C 205EB +945D 747A +945E 23EF8 +945F 2365F +9460 24A4A +9461 24917 +9462 25FE1 +9463 3F06 +9464 3EB1 +9465 24ADF +9466 28C23 +9467 23F35 +9468 60A7 +9469 3EF3 +946A 74CC +946B 743C +946C 9387 +946D 7437 +946E 449F +946F 26DEA +9470 4551 +9471 7583 +9472 3F63 +9473 24CD9 +9474 24D06 +9475 3F58 +9476 7555 +9477 7673 +9478 2A5C6 +9479 3B19 +947A 7468 +947B 28ACC +947C 249AB +947D 2498E +947E 3AFB +94A1 3DCD +94A2 24A4E +94A3 3EFF +94A4 249C5 +94A5 248F3 +94A6 91FA +94A7 5732 +94A8 9342 +94A9 28AE3 +94AA 21864 +94AB 50DF +94AC 25221 +94AD 251E7 +94AE 7778 +94AF 23232 +94B0 770E +94B1 770F +94B2 777B +94B3 24697 +94B4 23781 +94B5 3A5E +94B6 248F0 +94B7 7438 +94B8 749B +94B9 3EBF +94BA 24ABA +94BB 24AC7 +94BC 40C8 +94BD 24A96 +94BE 261AE +94BF 9307 +94C0 25581 +94C1 781E +94C2 788D +94C3 7888 +94C4 78D2 +94C5 73D0 +94C6 7959 +94C7 27741 +94C8 256E3 +94C9 410E +94CB 8496 +94CC 79A5 +94CD 6A2D +94CE 23EFA +94CF 7A3A +94D0 79F4 +94D1 416E +94D2 216E6 +94D3 4132 +94D4 9235 +94D5 79F1 +94D6 20D4C +94D7 2498C +94D8 20299 +94D9 23DBA +94DA 2176E +94DB 3597 +94DC 556B +94DD 3570 +94DE 36AA +94DF 201D4 +94E0 20C0D +94E1 7AE2 +94E2 5A59 +94E3 226F5 +94E4 25AAF +94E5 25A9C +94E6 5A0D +94E7 2025B +94E8 78F0 +94E9 5A2A +94EA 25BC6 +94EB 7AFE +94EC 41F9 +94ED 7C5D +94EE 7C6D +94EF 4211 +94F0 25BB3 +94F1 25EBC +94F2 25EA6 +94F3 7CCD +94F4 249F9 +94F5 217B0 +94F6 7C8E +94F7 7C7C +94F8 7CAE +94F9 6AB2 +94FA 7DDC +94FB 7E07 +94FC 7DD3 +94FD 7F4E +94FE 26261 +9540 2615C +9541 27B48 +9542 7D97 +9543 25E82 +9544 426A +9545 26B75 +9546 20916 +9547 67D6 +9548 2004E +9549 235CF +954A 57C4 +954B 26412 +954C 263F8 +954D 24962 +954E 7FDD +954F 7B27 +9550 2082C +9551 25AE9 +9552 25D43 +9553 7B0C +9554 25E0E +9555 99E6 +9556 8645 +9557 9A63 +9558 6A1C +9559 2343F +955A 39E2 +955B 249F7 +955C 265AD +955D 9A1F +955E 265A0 +955F 8480 +9560 27127 +9561 26CD1 +9562 44EA +9563 8137 +9564 4402 +9565 80C6 +9566 8109 +9567 8142 +9568 267B4 +9569 98C3 +956A 26A42 +956B 8262 +956C 8265 +956D 26A51 +956E 8453 +956F 26DA7 +9570 8610 +9571 2721B +9572 5A86 +9573 417F +9574 21840 +9575 5B2B +9576 218A1 +9577 5AE4 +9578 218D8 +9579 86A0 +957A 2F9BC +957B 23D8F +957C 882D +957D 27422 +957E 5A02 +95A1 886E +95A2 4F45 +95A3 8887 +95A4 88BF +95A5 88E6 +95A6 8965 +95A7 894D +95A8 25683 +95A9 8954 +95AA 27785 +95AB 27784 +95AC 28BF5 +95AD 28BD9 +95AE 28B9C +95AF 289F9 +95B0 3EAD +95B1 84A3 +95B2 46F5 +95B3 46CF +95B4 37F2 +95B5 8A3D +95B6 8A1C +95B7 29448 +95B8 5F4D +95B9 922B +95BA 24284 +95BB 65D4 +95BC 7129 +95BD 70C4 +95BE 21845 +95BF 9D6D +95C0 8C9F +95C1 8CE9 +95C2 27DDC +95C3 599A +95C4 77C3 +95C5 59F0 +95C6 436E +95C7 36D4 +95C8 8E2A +95C9 8EA7 +95CA 24C09 +95CB 8F30 +95CC 8F4A +95CD 42F4 +95CE 6C58 +95CF 6FBB +95D0 22321 +95D1 489B +95D2 6F79 +95D3 6E8B +95D4 217DA +95D5 9BE9 +95D6 36B5 +95D7 2492F +95D8 90BB +95DA 5571 +95DB 4906 +95DC 91BB +95DD 9404 +95DE 28A4B +95DF 4062 +95E0 28AFC +95E1 9427 +95E2 28C1D +95E3 28C3B +95E4 84E5 +95E5 8A2B +95E6 9599 +95E7 95A7 +95E8 9597 +95E9 9596 +95EA 28D34 +95EB 7445 +95EC 3EC2 +95ED 248FF +95EE 24A42 +95EF 243EA +95F0 3EE7 +95F1 23225 +95F2 968F +95F3 28EE7 +95F4 28E66 +95F5 28E65 +95F6 3ECC +95F7 249ED +95F8 24A78 +95F9 23FEE +95FA 7412 +95FB 746B +95FC 3EFC +95FD 9741 +95FE 290B0 +9640 6847 +9641 4A1D +9642 29093 +9643 257DF +9645 9368 +9646 28989 +9647 28C26 +9648 28B2F +9649 263BE +964A 92BA +964B 5B11 +964C 8B69 +964D 493C +964E 73F9 +964F 2421B +9650 979B +9651 9771 +9652 9938 +9653 20F26 +9654 5DC1 +9655 28BC5 +9656 24AB2 +9657 981F +9658 294DA +9659 92F6 +965A 295D7 +965B 91E5 +965C 44C0 +965D 28B50 +965E 24A67 +965F 28B64 +9660 98DC +9661 28A45 +9662 3F00 +9663 922A +9664 4925 +9665 8414 +9666 993B +9667 994D +9668 27B06 +9669 3DFD +966A 999B +966B 4B6F +966C 99AA +966D 9A5C +966E 28B65 +966F 258C8 +9670 6A8F +9671 9A21 +9672 5AFE +9673 9A2F +9674 298F1 +9675 4B90 +9676 29948 +9677 99BC +9678 4BBD +9679 4B97 +967A 937D +967B 5872 +967C 21302 +967D 5822 +967E 249B8 +96A1 214E8 +96A2 7844 +96A3 2271F +96A4 23DB8 +96A5 68C5 +96A6 3D7D +96A7 9458 +96A8 3927 +96A9 6150 +96AA 22781 +96AB 2296B +96AC 6107 +96AD 9C4F +96AE 9C53 +96AF 9C7B +96B0 9C35 +96B1 9C10 +96B2 9B7F +96B3 9BCF +96B4 29E2D +96B5 9B9F +96B6 2A1F5 +96B7 2A0FE +96B8 9D21 +96B9 4CAE +96BA 24104 +96BB 9E18 +96BC 4CB0 +96BD 9D0C +96BE 2A1B4 +96BF 2A0ED +96C0 2A0F3 +96C1 2992F +96C2 9DA5 +96C3 84BD +96C4 26E12 +96C5 26FDF +96C6 26B82 +96C7 85FC +96C8 4533 +96C9 26DA4 +96CA 26E84 +96CB 26DF0 +96CC 8420 +96CD 85EE +96CE 26E00 +96CF 237D7 +96D0 26064 +96D1 79E2 +96D2 2359C +96D3 23640 +96D4 492D +96D5 249DE +96D6 3D62 +96D7 93DB +96D8 92BE +96D9 9348 +96DA 202BF +96DB 78B9 +96DC 9277 +96DD 944D +96DE 4FE4 +96DF 3440 +96E0 9064 +96E1 2555D +96E2 783D +96E3 7854 +96E4 78B6 +96E5 784B +96E6 21757 +96E7 231C9 +96E8 24941 +96E9 369A +96EA 4F72 +96EB 6FDA +96EC 6FD9 +96EE 701E +96EF 5414 +96F0 241B5 +96F1 57BB +96F2 58F3 +96F3 578A +96F4 9D16 +96F5 57D7 +96F6 7134 +96F7 34AF +96F8 241AC +96F9 71EB +96FA 26C40 +96FB 24F97 +96FD 217B5 +96FE 28A49 +9740 610C +9741 5ACE +9742 5A0B +9743 42BC +9744 24488 +9745 372C +9746 4B7B +9747 289FC +9748 93BB +9749 93B8 +974A 218D6 +974B 20F1D +974C 8472 +974D 26CC0 +974E 21413 +974F 242FA +9750 22C26 +9751 243C1 +9752 5994 +9753 23DB7 +9754 26741 +9755 7DA8 +9756 2615B +9757 260A4 +9758 249B9 +9759 2498B +975A 289FA +975B 92E5 +975C 73E2 +975D 3EE9 +975E 74B4 +975F 28B63 +9760 2189F +9761 3EE1 +9762 24AB3 +9763 6AD8 +9764 73F3 +9765 73FB +9766 3ED6 +9767 24A3E +9768 24A94 +9769 217D9 +976A 24A66 +976B 203A7 +976C 21424 +976D 249E5 +976E 7448 +976F 24916 +9770 70A5 +9771 24976 +9772 9284 +9773 73E6 +9774 935F +9775 204FE +9776 9331 +9777 28ACE +9778 28A16 +9779 9386 +977A 28BE7 +977B 255D5 +977C 4935 +977D 28A82 +977E 716B +97A1 24943 +97A2 20CFF +97A3 56A4 +97A4 2061A +97A5 20BEB +97A6 20CB8 +97A7 5502 +97A8 79C4 +97A9 217FA +97AA 7DFE +97AB 216C2 +97AC 24A50 +97AD 21852 +97AE 452E +97AF 9401 +97B0 370A +97B1 28AC0 +97B2 249AD +97B3 59B0 +97B4 218BF +97B5 21883 +97B6 27484 +97B7 5AA1 +97B8 36E2 +97B9 23D5B +97BA 36B0 +97BB 925F +97BC 5A79 +97BD 28A81 +97BE 21862 +97BF 9374 +97C0 3CCD +97C1 20AB4 +97C2 4A96 +97C3 398A +97C4 50F4 +97C5 3D69 +97C6 3D4C +97C7 2139C +97C8 7175 +97C9 42FB +97CA 28218 +97CB 6E0F +97CC 290E4 +97CD 44EB +97CE 6D57 +97CF 27E4F +97D0 7067 +97D1 6CAF +97D2 3CD6 +97D3 23FED +97D4 23E2D +97D5 6E02 +97D6 6F0C +97D7 3D6F +97D8 203F5 +97D9 7551 +97DA 36BC +97DB 34C8 +97DC 4680 +97DD 3EDA +97DE 4871 +97DF 59C4 +97E0 926E +97E1 493E +97E2 8F41 +97E3 28C1C +97E4 26BC0 +97E5 5812 +97E6 57C8 +97E7 36D6 +97E8 21452 +97E9 70FE +97EA 24362 +97EB 24A71 +97EC 22FE3 +97ED 212B0 +97EE 223BD +97EF 68B9 +97F0 6967 +97F1 21398 +97F2 234E5 +97F3 27BF4 +97F4 236DF +97F5 28A83 +97F6 237D6 +97F7 233FA +97F8 24C9F +97F9 6A1A +97FA 236AD +97FB 26CB7 +97FC 843E +97FD 44DF +97FE 44CE +9840 26D26 +9841 26D51 +9842 26C82 +9843 26FDE +9844 6F17 +9845 27109 +9846 833D +9847 2173A +9848 83ED +9849 26C80 +984A 27053 +984B 217DB +984C 5989 +984D 5A82 +984E 217B3 +984F 5A61 +9850 5A71 +9851 21905 +9852 241FC +9853 372D +9854 59EF +9855 2173C +9856 36C7 +9857 718E +9858 9390 +9859 669A +985A 242A5 +985B 5A6E +985C 5A2B +985D 24293 +985E 6A2B +985F 23EF9 +9860 27736 +9861 2445B +9862 242CA +9863 711D +9864 24259 +9865 289E1 +9866 4FB0 +9867 26D28 +9868 5CC2 +9869 244CE +986A 27E4D +986B 243BD +986C 6A0C +986D 24256 +986E 21304 +986F 70A6 +9870 7133 +9871 243E9 +9872 3DA5 +9873 6CDF +9874 2F825 +9875 24A4F +9876 7E65 +9877 59EB +9878 5D2F +9879 3DF3 +987A 5F5C +987B 24A5D +987C 217DF +987D 7DA4 +987E 8426 +98A1 5485 +98A2 23AFA +98A3 23300 +98A4 20214 +98A5 577E +98A6 208D5 +98A7 20619 +98A8 3FE5 +98A9 21F9E +98AA 2A2B6 +98AB 7003 +98AC 2915B +98AD 5D70 +98AE 738F +98AF 7CD3 +98B0 28A59 +98B1 29420 +98B2 4FC8 +98B3 7FE7 +98B4 72CD +98B5 7310 +98B6 27AF4 +98B7 7338 +98B8 7339 +98B9 256F6 +98BA 7341 +98BB 7348 +98BC 3EA9 +98BD 27B18 +98BE 906C +98BF 71F5 +98C0 248F2 +98C1 73E1 +98C2 81F6 +98C3 3ECA +98C4 770C +98C5 3ED1 +98C6 6CA2 +98C7 56FD +98C8 7419 +98C9 741E +98CA 741F +98CB 3EE2 +98CC 3EF0 +98CD 3EF4 +98CE 3EFA +98CF 74D3 +98D0 3F0E +98D1 3F53 +98D2 7542 +98D3 756D +98D4 7572 +98D5 758D +98D6 3F7C +98D7 75C8 +98D8 75DC +98D9 3FC0 +98DA 764D +98DB 3FD7 +98DC 7674 +98DD 3FDC +98DE 767A +98DF 24F5C +98E0 7188 +98E1 5623 +98E2 8980 +98E3 5869 +98E4 401D +98E5 7743 +98E6 4039 +98E7 6761 +98E8 4045 +98E9 35DB +98EA 7798 +98EB 406A +98EC 406F +98ED 5C5E +98EE 77BE +98EF 77CB +98F0 58F2 +98F1 7818 +98F2 70B9 +98F3 781C +98F4 40A8 +98F5 7839 +98F6 7847 +98F7 7851 +98F8 7866 +98F9 8448 +98FA 25535 +98FB 7933 +98FC 6803 +98FD 7932 +98FE 4103 +9940 4109 +9941 7991 +9942 7999 +9943 8FBB +9944 7A06 +9945 8FBC +9946 4167 +9947 7A91 +9948 41B2 +9949 7ABC +994A 8279 +994B 41C4 +994C 7ACF +994D 7ADB +994E 41CF +994F 4E21 +9950 7B62 +9951 7B6C +9952 7B7B +9953 7C12 +9954 7C1B +9955 4260 +9956 427A +9957 7C7B +9958 7C9C +9959 428C +995A 7CB8 +995B 4294 +995C 7CED +995D 8F93 +995E 70C0 +995F 20CCF +9960 7DCF +9961 7DD4 +9962 7DD0 +9963 7DFD +9964 7FAE +9965 7FB4 +9966 729F +9967 4397 +9968 8020 +9969 8025 +996A 7B39 +996B 802E +996C 8031 +996D 8054 +996E 3DCC +996F 57B4 +9970 70A0 +9971 80B7 +9972 80E9 +9973 43ED +9974 810C +9975 732A +9976 810E +9977 8112 +9978 7560 +9979 8114 +997A 4401 +997B 3B39 +997C 8156 +997D 8159 +997E 815A +99A1 4413 +99A2 583A +99A3 817C +99A4 8184 +99A5 4425 +99A6 8193 +99A7 442D +99A8 81A5 +99A9 57EF +99AA 81C1 +99AB 81E4 +99AC 8254 +99AD 448F +99AE 82A6 +99AF 8276 +99B0 82CA +99B1 82D8 +99B2 82FF +99B3 44B0 +99B4 8357 +99B5 9669 +99B6 698A +99B7 8405 +99B8 70F5 +99B9 8464 +99BA 60E3 +99BB 8488 +99BC 4504 +99BD 84BE +99BE 84E1 +99BF 84F8 +99C0 8510 +99C1 8538 +99C2 8552 +99C3 453B +99C4 856F +99C5 8570 +99C6 85E0 +99C7 4577 +99C8 8672 +99C9 8692 +99CA 86B2 +99CB 86EF +99CC 9645 +99CD 878B +99CE 4606 +99CF 4617 +99D0 88AE +99D1 88FF +99D2 8924 +99D3 8947 +99D4 8991 +99D5 27967 +99D6 8A29 +99D7 8A38 +99D8 8A94 +99D9 8AB4 +99DA 8C51 +99DB 8CD4 +99DC 8CF2 +99DD 8D1C +99DE 4798 +99DF 585F +99E0 8DC3 +99E1 47ED +99E2 4EEE +99E3 8E3A +99E4 55D8 +99E5 5754 +99E6 8E71 +99E7 55F5 +99E8 8EB0 +99E9 4837 +99EA 8ECE +99EB 8EE2 +99EC 8EE4 +99ED 8EED +99EE 8EF2 +99EF 8FB7 +99F0 8FC1 +99F1 8FCA +99F2 8FCC +99F3 9033 +99F4 99C4 +99F5 48AD +99F6 98E0 +99F7 9213 +99F8 491E +99F9 9228 +99FA 9258 +99FB 926B +99FC 92B1 +99FD 92AE +99FE 92BF +9A40 92E3 +9A41 92EB +9A42 92F3 +9A43 92F4 +9A44 92FD +9A45 9343 +9A46 9384 +9A47 93AD +9A48 4945 +9A49 4951 +9A4A 9EBF +9A4B 9417 +9A4C 5301 +9A4D 941D +9A4E 942D +9A4F 943E +9A50 496A +9A51 9454 +9A52 9479 +9A53 952D +9A54 95A2 +9A55 49A7 +9A56 95F4 +9A57 9633 +9A58 49E5 +9A59 67A0 +9A5A 4A24 +9A5B 9740 +9A5C 4A35 +9A5D 97B2 +9A5E 97C2 +9A5F 5654 +9A60 4AE4 +9A61 60E8 +9A62 98B9 +9A63 4B19 +9A64 98F1 +9A65 5844 +9A66 990E +9A67 9919 +9A68 51B4 +9A69 991C +9A6A 9937 +9A6B 9942 +9A6C 995D +9A6D 9962 +9A6E 4B70 +9A6F 99C5 +9A70 4B9D +9A71 9A3C +9A72 9B0F +9A73 7A83 +9A74 9B69 +9A75 9B81 +9A76 9BDD +9A77 9BF1 +9A78 9BF4 +9A79 4C6D +9A7A 9C20 +9A7B 376F +9A7C 21BC2 +9A7D 9D49 +9A7E 9C3A +9AA1 9EFE +9AA2 5650 +9AA3 9D93 +9AA4 9DBD +9AA5 9DC0 +9AA6 9DFC +9AA7 94F6 +9AA8 8FB6 +9AA9 9E7B +9AAA 9EAC +9AAB 9EB1 +9AAC 9EBD +9AAD 9EC6 +9AAE 94DC +9AAF 9EE2 +9AB0 9EF1 +9AB1 9EF8 +9AB2 7AC8 +9AB3 9F44 +9AB4 20094 +9AB5 202B7 +9AB6 203A0 +9AB7 691A +9AB8 94C3 +9AB9 59AC +9ABA 204D7 +9ABB 5840 +9ABC 94C1 +9ABD 37B9 +9ABE 205D5 +9ABF 20615 +9AC0 20676 +9AC1 216BA +9AC2 5757 +9AC3 7173 +9AC4 20AC2 +9AC5 20ACD +9AC6 20BBF +9AC7 546A +9AC8 2F83B +9AC9 20BCB +9ACA 549E +9ACB 20BFB +9ACC 20C3B +9ACD 20C53 +9ACE 20C65 +9ACF 20C7C +9AD0 60E7 +9AD1 20C8D +9AD2 567A +9AD3 20CB5 +9AD4 20CDD +9AD5 20CED +9AD6 20D6F +9AD7 20DB2 +9AD8 20DC8 +9AD9 6955 +9ADA 9C2F +9ADB 87A5 +9ADC 20E04 +9ADD 20E0E +9ADE 20ED7 +9ADF 20F90 +9AE0 20F2D +9AE1 20E73 +9AE2 5C20 +9AE3 20FBC +9AE4 5E0B +9AE5 2105C +9AE6 2104F +9AE7 21076 +9AE8 671E +9AE9 2107B +9AEA 21088 +9AEB 21096 +9AEC 3647 +9AED 210BF +9AEE 210D3 +9AEF 2112F +9AF0 2113B +9AF1 5364 +9AF2 84AD +9AF3 212E3 +9AF4 21375 +9AF5 21336 +9AF6 8B81 +9AF7 21577 +9AF8 21619 +9AF9 217C3 +9AFA 217C7 +9AFB 4E78 +9AFC 70BB +9AFD 2182D +9AFE 2196A +9B40 21A2D +9B41 21A45 +9B42 21C2A +9B43 21C70 +9B44 21CAC +9B45 21EC8 +9B46 62C3 +9B47 21ED5 +9B48 21F15 +9B49 7198 +9B4A 6855 +9B4B 22045 +9B4C 69E9 +9B4D 36C8 +9B4E 2227C +9B4F 223D7 +9B50 223FA +9B51 2272A +9B52 22871 +9B53 2294F +9B54 82FD +9B55 22967 +9B56 22993 +9B57 22AD5 +9B58 89A5 +9B59 22AE8 +9B5A 8FA0 +9B5B 22B0E +9B5C 97B8 +9B5D 22B3F +9B5E 9847 +9B5F 9ABD +9B60 22C4C +9B62 22C88 +9B63 22CB7 +9B64 25BE8 +9B65 22D08 +9B66 22D12 +9B67 22DB7 +9B68 22D95 +9B69 22E42 +9B6A 22F74 +9B6B 22FCC +9B6C 23033 +9B6D 23066 +9B6E 2331F +9B6F 233DE +9B70 5FB1 +9B71 6648 +9B72 66BF +9B73 27A79 +9B74 23567 +9B75 235F3 +9B77 249BA +9B79 2361A +9B7A 23716 +9B7C 20346 +9B7D 58B5 +9B7E 670E +9BA1 6918 +9BA2 23AA7 +9BA3 27657 +9BA4 25FE2 +9BA5 23E11 +9BA6 23EB9 +9BA7 275FE +9BA8 2209A +9BA9 48D0 +9BAA 4AB8 +9BAB 24119 +9BAC 28A9A +9BAD 242EE +9BAE 2430D +9BAF 2403B +9BB0 24334 +9BB1 24396 +9BB2 24A45 +9BB3 205CA +9BB4 51D2 +9BB5 20611 +9BB6 599F +9BB7 21EA8 +9BB8 3BBE +9BB9 23CFF +9BBA 24404 +9BBB 244D6 +9BBC 5788 +9BBD 24674 +9BBE 399B +9BBF 2472F +9BC0 285E8 +9BC1 299C9 +9BC2 3762 +9BC3 221C3 +9BC4 8B5E +9BC5 28B4E +9BC7 24812 +9BC8 248FB +9BC9 24A15 +9BCA 7209 +9BCB 24AC0 +9BCC 20C78 +9BCD 5965 +9BCE 24EA5 +9BCF 24F86 +9BD0 20779 +9BD1 8EDA +9BD2 2502C +9BD3 528F +9BD4 573F +9BD5 7171 +9BD6 25299 +9BD7 25419 +9BD8 23F4A +9BD9 24AA7 +9BDA 55BC +9BDB 25446 +9BDC 2546E +9BDD 26B52 +9BDF 3473 +9BE0 2553F +9BE1 27632 +9BE2 2555E +9BE3 4718 +9BE4 25562 +9BE5 25566 +9BE6 257C7 +9BE7 2493F +9BE8 2585D +9BE9 5066 +9BEA 34FB +9BEB 233CC +9BED 25903 +9BEE 477C +9BEF 28948 +9BF0 25AAE +9BF1 25B89 +9BF2 25C06 +9BF3 21D90 +9BF4 57A1 +9BF5 7151 +9BF7 26102 +9BF8 27C12 +9BF9 9056 +9BFA 261B2 +9BFB 24F9A +9BFC 8B62 +9BFD 26402 +9BFE 2644A +9C40 5D5B +9C41 26BF7 +9C43 26484 +9C44 2191C +9C45 8AEA +9C46 249F6 +9C47 26488 +9C48 23FEF +9C49 26512 +9C4A 4BC0 +9C4B 265BF +9C4C 266B5 +9C4D 2271B +9C4E 9465 +9C4F 257E1 +9C50 6195 +9C51 5A27 +9C52 2F8CD +9C54 56B9 +9C55 24521 +9C56 266FC +9C57 4E6A +9C58 24934 +9C59 9656 +9C5A 6D8F +9C5B 26CBD +9C5C 3618 +9C5D 8977 +9C5E 26799 +9C5F 2686E +9C60 26411 +9C61 2685E +9C63 268C7 +9C64 7B42 +9C65 290C0 +9C66 20A11 +9C67 26926 +9C69 26939 +9C6A 7A45 +9C6C 269FA +9C6D 9A26 +9C6E 26A2D +9C6F 365F +9C70 26469 +9C71 20021 +9C72 7983 +9C73 26A34 +9C74 26B5B +9C75 5D2C +9C76 23519 +9C78 26B9D +9C79 46D0 +9C7A 26CA4 +9C7B 753B +9C7C 8865 +9C7D 26DAE +9C7E 58B6 +9CA1 371C +9CA2 2258D +9CA3 2704B +9CA4 271CD +9CA5 3C54 +9CA6 27280 +9CA7 27285 +9CA8 9281 +9CA9 2217A +9CAA 2728B +9CAB 9330 +9CAC 272E6 +9CAD 249D0 +9CAE 6C39 +9CAF 949F +9CB0 27450 +9CB1 20EF8 +9CB2 8827 +9CB3 88F5 +9CB4 22926 +9CB5 28473 +9CB6 217B1 +9CB7 6EB8 +9CB8 24A2A +9CB9 21820 +9CBA 39A4 +9CBB 36B9 +9CBE 453F +9CBF 66B6 +9CC0 29CAD +9CC1 298A4 +9CC2 8943 +9CC3 277CC +9CC4 27858 +9CC5 56D6 +9CC6 40DF +9CC7 2160A +9CC8 39A1 +9CC9 2372F +9CCA 280E8 +9CCB 213C5 +9CCC 71AD +9CCD 8366 +9CCE 279DD +9CCF 291A8 +9CD1 4CB7 +9CD2 270AF +9CD3 289AB +9CD4 279FD +9CD5 27A0A +9CD6 27B0B +9CD7 27D66 +9CD8 2417A +9CD9 7B43 +9CDA 797E +9CDB 28009 +9CDC 6FB5 +9CDD 2A2DF +9CDE 6A03 +9CDF 28318 +9CE0 53A2 +9CE1 26E07 +9CE2 93BF +9CE3 6836 +9CE4 975D +9CE5 2816F +9CE6 28023 +9CE7 269B5 +9CE8 213ED +9CE9 2322F +9CEA 28048 +9CEB 5D85 +9CEC 28C30 +9CED 28083 +9CEE 5715 +9CEF 9823 +9CF0 28949 +9CF1 5DAB +9CF2 24988 +9CF3 65BE +9CF4 69D5 +9CF5 53D2 +9CF6 24AA5 +9CF7 23F81 +9CF8 3C11 +9CF9 6736 +9CFA 28090 +9CFB 280F4 +9CFC 2812E +9CFD 21FA1 +9CFE 2814F +9D40 28189 +9D41 281AF +9D42 2821A +9D43 28306 +9D44 2832F +9D45 2838A +9D46 35CA +9D47 28468 +9D48 286AA +9D49 48FA +9D4A 63E6 +9D4B 28956 +9D4C 7808 +9D4D 9255 +9D4E 289B8 +9D4F 43F2 +9D50 289E7 +9D51 43DF +9D52 289E8 +9D53 28B46 +9D54 28BD4 +9D55 59F8 +9D56 28C09 +9D58 28FC5 +9D59 290EC +9D5B 29110 +9D5C 2913C +9D5D 3DF7 +9D5E 2915E +9D5F 24ACA +9D60 8FD0 +9D61 728F +9D62 568B +9D63 294E7 +9D64 295E9 +9D65 295B0 +9D66 295B8 +9D67 29732 +9D68 298D1 +9D69 29949 +9D6A 2996A +9D6B 299C3 +9D6C 29A28 +9D6D 29B0E +9D6E 29D5A +9D6F 29D9B +9D70 7E9F +9D71 29EF8 +9D72 29F23 +9D73 4CA4 +9D74 9547 +9D75 2A293 +9D76 71A2 +9D77 2A2FF +9D78 4D91 +9D79 9012 +9D7A 2A5CB +9D7B 4D9C +9D7C 20C9C +9D7D 8FBE +9D7E 55C1 +9DA1 8FBA +9DA2 224B0 +9DA3 8FB9 +9DA4 24A93 +9DA5 4509 +9DA6 7E7F +9DA7 6F56 +9DA8 6AB1 +9DA9 4EEA +9DAA 34E4 +9DAB 28B2C +9DAC 2789D +9DAD 373A +9DAE 8E80 +9DAF 217F5 +9DB0 28024 +9DB1 28B6C +9DB2 28B99 +9DB3 27A3E +9DB4 266AF +9DB5 3DEB +9DB6 27655 +9DB7 23CB7 +9DB8 25635 +9DB9 25956 +9DBA 4E9A +9DBB 25E81 +9DBC 26258 +9DBD 56BF +9DBE 20E6D +9DBF 8E0E +9DC0 5B6D +9DC1 23E88 +9DC2 24C9E +9DC3 63DE +9DC5 217F6 +9DC6 2187B +9DC7 6530 +9DC8 562D +9DC9 25C4A +9DCA 541A +9DCB 25311 +9DCC 3DC6 +9DCD 29D98 +9DCE 4C7D +9DCF 5622 +9DD0 561E +9DD1 7F49 +9DD2 25ED8 +9DD3 5975 +9DD4 23D40 +9DD5 8770 +9DD6 4E1C +9DD7 20FEA +9DD8 20D49 +9DD9 236BA +9DDA 8117 +9DDB 9D5E +9DDC 8D18 +9DDD 763B +9DDE 9C45 +9DDF 764E +9DE0 77B9 +9DE1 9345 +9DE2 5432 +9DE3 8148 +9DE4 82F7 +9DE5 5625 +9DE6 8132 +9DE7 8418 +9DE8 80BD +9DE9 55EA +9DEA 7962 +9DEB 5643 +9DEC 5416 +9DED 20E9D +9DEE 35CE +9DEF 5605 +9DF0 55F1 +9DF1 66F1 +9DF2 282E2 +9DF3 362D +9DF4 7534 +9DF5 55F0 +9DF6 55BA +9DF7 5497 +9DF8 5572 +9DF9 20C41 +9DFA 20C96 +9DFB 5ED0 +9DFC 25148 +9DFD 20E76 +9DFE 22C62 +9E40 20EA2 +9E41 9EAB +9E42 7D5A +9E43 55DE +9E44 21075 +9E45 629D +9E46 976D +9E47 5494 +9E48 8CCD +9E49 71F6 +9E4A 9176 +9E4B 63FC +9E4C 63B9 +9E4D 63FE +9E4E 5569 +9E4F 22B43 +9E50 9C72 +9E51 22EB3 +9E52 519A +9E53 34DF +9E54 20DA7 +9E55 51A7 +9E56 544D +9E57 551E +9E58 5513 +9E59 7666 +9E5A 8E2D +9E5B 2688A +9E5C 75B1 +9E5D 80B6 +9E5E 8804 +9E5F 8786 +9E60 88C7 +9E61 81B6 +9E62 841C +9E63 210C1 +9E64 44EC +9E65 7304 +9E66 24706 +9E67 5B90 +9E68 830B +9E69 26893 +9E6A 567B +9E6B 226F4 +9E6C 27D2F +9E6D 241A3 +9E6E 27D73 +9E6F 26ED0 +9E70 272B6 +9E71 9170 +9E72 211D9 +9E73 9208 +9E74 23CFC +9E75 2A6A9 +9E76 20EAC +9E77 20EF9 +9E78 7266 +9E79 21CA2 +9E7A 474E +9E7B 24FC2 +9E7C 27FF9 +9E7D 20FEB +9E7E 40FA +9EA1 9C5D +9EA2 651F +9EA3 22DA0 +9EA4 48F3 +9EA5 247E0 +9EA6 29D7C +9EA7 20FEC +9EA8 20E0A +9EAA 275A3 +9EAB 20FED +9EAD 26048 +9EAE 21187 +9EAF 71A3 +9EB0 7E8E +9EB1 9D50 +9EB2 4E1A +9EB3 4E04 +9EB4 3577 +9EB5 5B0D +9EB6 6CB2 +9EB7 5367 +9EB8 36AC +9EB9 39DC +9EBA 537D +9EBB 36A5 +9EBC 24618 +9EBD 589A +9EBE 24B6E +9EBF 822D +9EC0 544B +9EC1 57AA +9EC2 25A95 +9EC3 20979 +9EC5 3A52 +9EC6 22465 +9EC7 7374 +9EC8 29EAC +9EC9 4D09 +9ECA 9BED +9ECB 23CFE +9ECC 29F30 +9ECD 4C5B +9ECE 24FA9 +9ECF 2959E +9ED0 29FDE +9ED1 845C +9ED2 23DB6 +9ED3 272B2 +9ED4 267B3 +9ED5 23720 +9ED6 632E +9ED7 7D25 +9ED8 23EF7 +9ED9 23E2C +9EDA 3A2A +9EDB 9008 +9EDC 52CC +9EDD 3E74 +9EDE 367A +9EDF 45E9 +9EE0 2048E +9EE1 7640 +9EE2 5AF0 +9EE3 20EB6 +9EE4 787A +9EE5 27F2E +9EE6 58A7 +9EE7 40BF +9EE8 567C +9EE9 9B8B +9EEA 5D74 +9EEB 7654 +9EEC 2A434 +9EED 9E85 +9EEE 4CE1 +9EF0 37FB +9EF1 6119 +9EF2 230DA +9EF3 243F2 +9EF5 565D +9EF6 212A9 +9EF7 57A7 +9EF8 24963 +9EF9 29E06 +9EFA 5234 +9EFB 270AE +9EFC 35AD +9EFE 9D7C +9F40 7C56 +9F41 9B39 +9F42 57DE +9F43 2176C +9F44 5C53 +9F45 64D3 +9F46 294D0 +9F47 26335 +9F48 27164 +9F49 86AD +9F4A 20D28 +9F4B 26D22 +9F4C 24AE2 +9F4D 20D71 +9F4F 51FE +9F50 21F0F +9F51 5D8E +9F52 9703 +9F53 21DD1 +9F54 9E81 +9F55 904C +9F56 7B1F +9F57 9B02 +9F58 5CD1 +9F59 7BA3 +9F5A 6268 +9F5B 6335 +9F5C 9AFF +9F5D 7BCF +9F5E 9B2A +9F5F 7C7E +9F61 7C42 +9F62 7C86 +9F63 9C15 +9F64 7BFC +9F65 9B09 +9F67 9C1B +9F68 2493E +9F69 9F5A +9F6A 5573 +9F6B 5BC3 +9F6C 4FFD +9F6D 9E98 +9F6E 4FF2 +9F6F 5260 +9F70 3E06 +9F71 52D1 +9F72 5767 +9F73 5056 +9F74 59B7 +9F75 5E12 +9F76 97C8 +9F77 9DAB +9F78 8F5C +9F79 5469 +9F7A 97B4 +9F7B 9940 +9F7C 97BA +9F7D 532C +9F7E 6130 +9FA1 692C +9FA2 53DA +9FA3 9C0A +9FA4 9D02 +9FA5 4C3B +9FA6 9641 +9FA7 6980 +9FA8 50A6 +9FA9 7546 +9FAA 2176D +9FAB 99DA +9FAC 5273 +9FAE 9159 +9FAF 9681 +9FB0 915C +9FB2 9151 +9FB3 28E97 +9FB4 637F +9FB5 26D23 +9FB6 6ACA +9FB7 5611 +9FB8 918E +9FB9 757A +9FBA 6285 +9FBB 203FC +9FBC 734F +9FBD 7C70 +9FBE 25C21 +9FBF 23CFD +9FC1 24919 +9FC2 76D6 +9FC3 9B9D +9FC4 4E2A +9FC5 20CD4 +9FC6 83BE +9FC7 8842 +9FC9 5C4A +9FCA 69C0 +9FCC 577A +9FCD 521F +9FCE 5DF5 +9FCF 4ECE +9FD0 6C31 +9FD1 201F2 +9FD2 4F39 +9FD3 549C +9FD4 54DA +9FD5 529A +9FD6 8D82 +9FD7 35FE +9FD9 35F3 +9FDB 6B52 +9FDC 917C +9FDD 9FA5 +9FDE 9B97 +9FDF 982E +9FE0 98B4 +9FE1 9ABA +9FE2 9EA8 +9FE3 9E84 +9FE4 717A +9FE5 7B14 +9FE7 6BFA +9FE8 8818 +9FE9 7F78 +9FEB 5620 +9FEC 2A64A +9FED 8E77 +9FEE 9F53 +9FF0 8DD4 +9FF1 8E4F +9FF2 9E1C +9FF3 8E01 +9FF4 6282 +9FF5 2837D +9FF6 8E28 +9FF7 8E75 +9FF8 7AD3 +9FF9 24A77 +9FFA 7A3E +9FFB 78D8 +9FFC 6CEA +9FFD 8A67 +9FFE 7607 +A040 28A5A +A041 9F26 +A042 6CCE +A043 87D6 +A044 75C3 +A045 2A2B2 +A046 7853 +A047 2F840 +A048 8D0C +A049 72E2 +A04A 7371 +A04B 8B2D +A04C 7302 +A04D 74F1 +A04E 8CEB +A04F 24ABB +A050 862F +A051 5FBA +A052 88A0 +A053 44B7 +A055 2183B +A056 26E05 +A058 8A7E +A059 2251B +A05B 60FD +A05C 7667 +A05D 9AD7 +A05E 9D44 +A05F 936E +A060 9B8F +A061 87F5 +A064 8CF7 +A065 732C +A066 9721 +A067 9BB0 +A068 35D6 +A069 72B2 +A06A 4C07 +A06B 7C51 +A06C 994A +A06D 26159 +A06E 6159 +A06F 4C04 +A070 9E96 +A071 617D +A073 575F +A074 616F +A075 62A6 +A076 6239 +A078 3A5C +A079 61E2 +A07A 53AA +A07B 233F5 +A07C 6364 +A07D 6802 +A07E 35D2 +A0A1 5D57 +A0A2 28BC2 +A0A3 8FDA +A0A4 28E39 +A0A6 50D9 +A0A7 21D46 +A0A8 7906 +A0A9 5332 +A0AA 9638 +A0AB 20F3B +A0AC 4065 +A0AE 77FE +A0B0 7CC2 +A0B1 25F1A +A0B2 7CDA +A0B3 7A2D +A0B4 8066 +A0B5 8063 +A0B6 7D4D +A0B7 7505 +A0B8 74F2 +A0B9 8994 +A0BA 821A +A0BB 670C +A0BC 8062 +A0BD 27486 +A0BE 805B +A0BF 74F0 +A0C0 8103 +A0C1 7724 +A0C2 8989 +A0C3 267CC +A0C4 7553 +A0C5 26ED1 +A0C6 87A9 +A0C7 87CE +A0C8 81C8 +A0C9 878C +A0CA 8A49 +A0CB 8CAD +A0CC 8B43 +A0CD 772B +A0CE 74F8 +A0CF 84DA +A0D0 3635 +A0D1 69B2 +A0D2 8DA6 +A0D4 89A9 +A0D6 6DB9 +A0D7 87C1 +A0D8 24011 +A0D9 74E7 +A0DA 3DDB +A0DB 7176 +A0DC 60A4 +A0DD 619C +A0DE 3CD1 +A0E0 6077 +A0E2 7F71 +A0E3 28B2D +A0E5 60E9 +A0E6 4B7E +A0E7 5220 +A0E8 3C18 +A0E9 23CC7 +A0EA 25ED7 +A0EB 27656 +A0EC 25531 +A0ED 21944 +A0EE 212FE +A0EF 29903 +A0F0 26DDC +A0F1 270AD +A0F2 5CC1 +A0F3 261AD +A0F4 28A0F +A0F5 23677 +A0F6 200EE +A0F7 26846 +A0F8 24F0E +A0F9 4562 +A0FA 5B1F +A0FB 2634C +A0FC 9F50 +A0FD 9EA6 +A0FE 2626B +C6A1 2460 +C6A2 2461 +C6A3 2462 +C6A4 2463 +C6A5 2464 +C6A6 2465 +C6A7 2466 +C6A8 2467 +C6A9 2468 +C6AA 2469 +C6AB 2474 +C6AC 2475 +C6AD 2476 +C6AE 2477 +C6AF 2478 +C6B0 2479 +C6B1 247A +C6B2 247B +C6B3 247C +C6B4 247D +C6B5 2170 +C6B6 2171 +C6B7 2172 +C6B8 2173 +C6B9 2174 +C6BA 2175 +C6BB 2176 +C6BC 2177 +C6BD 2178 +C6BE 2179 +C6BF 4E36 +C6C0 4E3F +C6C1 4E85 +C6C2 4EA0 +C6C3 5182 +C6C4 5196 +C6C5 51AB +C6C6 52F9 +C6C7 5338 +C6C8 5369 +C6C9 53B6 +C6CA 590A +C6CB 5B80 +C6CC 5DDB +C6CD 2F33 +C6CE 5E7F +C6D0 5F50 +C6D1 5F61 +C6D2 6534 +C6D4 7592 +C6D6 8FB5 +C6D8 00A8 +C6D9 02C6 +C6DA 30FD +C6DB 30FE +C6DC 309D +C6DD 309E +C6E0 3005 +C6E1 3006 +C6E2 3007 +C6E3 30FC +C6E4 FF3B +C6E5 FF3D +C6E6 273D +C6E7 3041 +C6E8 3042 +C6E9 3043 +C6EA 3044 +C6EB 3045 +C6EC 3046 +C6ED 3047 +C6EE 3048 +C6EF 3049 +C6F0 304A +C6F1 304B +C6F2 304C +C6F3 304D +C6F4 304E +C6F5 304F +C6F6 3050 +C6F7 3051 +C6F8 3052 +C6F9 3053 +C6FA 3054 +C6FB 3055 +C6FC 3056 +C6FD 3057 +C6FE 3058 +C740 3059 +C741 305A +C742 305B +C743 305C +C744 305D +C745 305E +C746 305F +C747 3060 +C748 3061 +C749 3062 +C74A 3063 +C74B 3064 +C74C 3065 +C74D 3066 +C74E 3067 +C74F 3068 +C750 3069 +C751 306A +C752 306B +C753 306C +C754 306D +C755 306E +C756 306F +C757 3070 +C758 3071 +C759 3072 +C75A 3073 +C75B 3074 +C75C 3075 +C75D 3076 +C75E 3077 +C75F 3078 +C760 3079 +C761 307A +C762 307B +C763 307C +C764 307D +C765 307E +C766 307F +C767 3080 +C768 3081 +C769 3082 +C76A 3083 +C76B 3084 +C76C 3085 +C76D 3086 +C76E 3087 +C76F 3088 +C770 3089 +C771 308A +C772 308B +C773 308C +C774 308D +C775 308E +C776 308F +C777 3090 +C778 3091 +C779 3092 +C77A 3093 +C77B 30A1 +C77C 30A2 +C77D 30A3 +C77E 30A4 +C7A1 30A5 +C7A2 30A6 +C7A3 30A7 +C7A4 30A8 +C7A5 30A9 +C7A6 30AA +C7A7 30AB +C7A8 30AC +C7A9 30AD +C7AA 30AE +C7AB 30AF +C7AC 30B0 +C7AD 30B1 +C7AE 30B2 +C7AF 30B3 +C7B0 30B4 +C7B1 30B5 +C7B2 30B6 +C7B3 30B7 +C7B4 30B8 +C7B5 30B9 +C7B6 30BA +C7B7 30BB +C7B8 30BC +C7B9 30BD +C7BA 30BE +C7BB 30BF +C7BC 30C0 +C7BD 30C1 +C7BE 30C2 +C7BF 30C3 +C7C0 30C4 +C7C1 30C5 +C7C2 30C6 +C7C3 30C7 +C7C4 30C8 +C7C5 30C9 +C7C6 30CA +C7C7 30CB +C7C8 30CC +C7C9 30CD +C7CA 30CE +C7CB 30CF +C7CC 30D0 +C7CD 30D1 +C7CE 30D2 +C7CF 30D3 +C7D0 30D4 +C7D1 30D5 +C7D2 30D6 +C7D3 30D7 +C7D4 30D8 +C7D5 30D9 +C7D6 30DA +C7D7 30DB +C7D8 30DC +C7D9 30DD +C7DA 30DE +C7DB 30DF +C7DC 30E0 +C7DD 30E1 +C7DE 30E2 +C7DF 30E3 +C7E0 30E4 +C7E1 30E5 +C7E2 30E6 +C7E3 30E7 +C7E4 30E8 +C7E5 30E9 +C7E6 30EA +C7E7 30EB +C7E8 30EC +C7E9 30ED +C7EA 30EE +C7EB 30EF +C7EC 30F0 +C7ED 30F1 +C7EE 30F2 +C7EF 30F3 +C7F0 30F4 +C7F1 30F5 +C7F2 30F6 +C7F3 0410 +C7F4 0411 +C7F5 0412 +C7F6 0413 +C7F7 0414 +C7F8 0415 +C7F9 0401 +C7FA 0416 +C7FB 0417 +C7FC 0418 +C7FD 0419 +C7FE 041A +C840 041B +C841 041C +C842 041D +C843 041E +C844 041F +C845 0420 +C846 0421 +C847 0422 +C848 0423 +C849 0424 +C84A 0425 +C84B 0426 +C84C 0427 +C84D 0428 +C84E 0429 +C84F 042A +C850 042B +C851 042C +C852 042D +C853 042E +C854 042F +C855 0430 +C856 0431 +C857 0432 +C858 0433 +C859 0434 +C85A 0435 +C85B 0451 +C85C 0436 +C85D 0437 +C85E 0438 +C85F 0439 +C860 043A +C861 043B +C862 043C +C863 043D +C864 043E +C865 043F +C866 0440 +C867 0441 +C868 0442 +C869 0443 +C86A 0444 +C86B 0445 +C86C 0446 +C86D 0447 +C86E 0448 +C86F 0449 +C870 044A +C871 044B +C872 044C +C873 044D +C874 044E +C875 044F +C876 21E7 +C877 21B8 +C878 21B9 +C879 31CF +C87A 200CC +C87B 4E5A +C87C 2008A +C87D 5202 +C87E 4491 +C8A1 9FB0 +C8A2 5188 +C8A3 9FB1 +C8A4 27607 +C8CD FFE2 +C8CE FFE4 +C8CF FF07 +C8D0 FF02 +C8D1 3231 +C8D2 2116 +C8D3 2121 +C8D4 309B +C8D5 309C +C8D6 2E80 +C8D7 2E84 +C8D8 2E86 +C8D9 2E87 +C8DA 2E88 +C8DB 2E8A +C8DC 2E8C +C8DD 2E8D +C8DE 2E95 +C8DF 2E9C +C8E0 2E9D +C8E1 2EA5 +C8E2 2EA7 +C8E3 2EAA +C8E4 2EAC +C8E5 2EAE +C8E6 2EB6 +C8E7 2EBC +C8E8 2EBE +C8E9 2EC6 +C8EA 2ECA +C8EB 2ECC +C8EC 2ECD +C8ED 2ECF +C8EE 2ED6 +C8EF 2ED7 +C8F0 2EDE +C8F1 2EE3 +C8F5 0283 +C8F6 0250 +C8F7 025B +C8F8 0254 +C8F9 0275 +C8FA 0153 +C8FB 00F8 +C8FC 014B +C8FD 028A +C8FE 026A +F9D6 7881 +F9D7 92B9 +F9D8 88CF +F9D9 58BB +F9DA 6052 +F9DB 7CA7 +F9DC 5AFA +F9DD 2554 +F9DE 2566 +F9DF 2557 +F9E0 2560 +F9E1 256C +F9E2 2563 +F9E3 255A +F9E4 2569 +F9E5 255D +F9E6 2552 +F9E7 2564 +F9E8 2555 +F9E9 255E +F9EA 256A +F9EB 2561 +F9EC 2558 +F9ED 2567 +F9EE 255B +F9EF 2553 +F9F0 2565 +F9F1 2556 +F9F2 255F +F9F3 256B +F9F4 2562 +F9F5 2559 +F9F6 2568 +F9F7 255C +F9F8 2551 +F9F9 2550 +F9FA 256D +F9FB 256E +F9FC 2570 +F9FD 256F +F9FE FFED +FA40 20547 +FA41 92DB +FA42 205DF +FA43 23FC5 +FA44 854C +FA45 42B5 +FA46 73EF +FA47 51B5 +FA48 3649 +FA49 24942 +FA4A 289E4 +FA4B 9344 +FA4C 219DB +FA4D 82EE +FA4E 23CC8 +FA4F 783C +FA50 6744 +FA51 62DF +FA52 24933 +FA53 289AA +FA54 202A0 +FA55 26BB3 +FA56 21305 +FA57 4FAB +FA58 224ED +FA59 5008 +FA5A 26D29 +FA5B 27A84 +FA5C 23600 +FA5D 24AB1 +FA5E 22513 +FA60 2037E +FA61 5FA4 +FA62 20380 +FA63 20347 +FA64 6EDB +FA65 2041F +FA67 5101 +FA68 347A +FA69 510E +FA6A 986C +FA6B 3743 +FA6C 8416 +FA6D 249A4 +FA6E 20487 +FA6F 5160 +FA70 233B4 +FA71 516A +FA72 20BFF +FA73 220FC +FA74 202E5 +FA75 22530 +FA76 2058E +FA77 23233 +FA78 21983 +FA79 5B82 +FA7A 877D +FA7B 205B3 +FA7C 23C99 +FA7D 51B2 +FA7E 51B8 +FAA1 9D34 +FAA2 51C9 +FAA3 51CF +FAA4 51D1 +FAA5 3CDC +FAA6 51D3 +FAA7 24AA6 +FAA8 51B3 +FAA9 51E2 +FAAA 5342 +FAAB 51ED +FAAC 83CD +FAAD 693E +FAAE 2372D +FAAF 5F7B +FAB0 520B +FAB1 5226 +FAB2 523C +FAB3 52B5 +FAB4 5257 +FAB5 5294 +FAB6 52B9 +FAB7 52C5 +FAB8 7C15 +FAB9 8542 +FABA 52E0 +FABB 860D +FABC 26B13 +FABE 28ADE +FABF 5549 +FAC0 6ED9 +FAC1 23F80 +FAC2 20954 +FAC3 23FEC +FAC4 5333 +FAC6 20BE2 +FAC7 6CCB +FAC8 21726 +FAC9 681B +FACA 73D5 +FACB 604A +FACC 3EAA +FACD 38CC +FACE 216E8 +FACF 71DD +FAD0 44A2 +FAD1 536D +FAD2 5374 +FAD3 286AB +FAD4 537E +FAD6 21596 +FAD7 21613 +FAD8 77E6 +FAD9 5393 +FADA 28A9B +FADB 53A0 +FADC 53AB +FADD 53AE +FADE 73A7 +FADF 25772 +FAE0 3F59 +FAE1 739C +FAE2 53C1 +FAE3 53C5 +FAE4 6C49 +FAE5 4E49 +FAE6 57FE +FAE7 53D9 +FAE8 3AAB +FAE9 20B8F +FAEA 53E0 +FAEB 23FEB +FAEC 22DA3 +FAED 53F6 +FAEE 20C77 +FAEF 5413 +FAF0 7079 +FAF1 552B +FAF2 6657 +FAF3 6D5B +FAF4 546D +FAF5 26B53 +FAF6 20D74 +FAF7 555D +FAF8 548F +FAF9 54A4 +FAFA 47A6 +FAFB 2170D +FAFC 20EDD +FAFD 3DB4 +FAFE 20D4D +FB40 289BC +FB41 22698 +FB42 5547 +FB43 4CED +FB44 542F +FB45 7417 +FB46 5586 +FB47 55A9 +FB49 218D7 +FB4A 2403A +FB4B 4552 +FB4C 24435 +FB4D 66B3 +FB4E 210B4 +FB4F 5637 +FB50 66CD +FB51 2328A +FB52 66A4 +FB53 66AD +FB54 564D +FB55 564F +FB56 78F1 +FB57 56F1 +FB58 9787 +FB59 53FE +FB5A 5700 +FB5B 56EF +FB5C 56ED +FB5D 28B66 +FB5E 3623 +FB5F 2124F +FB60 5746 +FB61 241A5 +FB62 6C6E +FB63 708B +FB64 5742 +FB65 36B1 +FB66 26C7E +FB67 57E6 +FB68 21416 +FB69 5803 +FB6A 21454 +FB6B 24363 +FB6C 5826 +FB6D 24BF5 +FB6E 585C +FB6F 58AA +FB70 3561 +FB71 58E0 +FB72 58DC +FB73 2123C +FB74 58FB +FB75 5BFF +FB76 5743 +FB77 2A150 +FB78 24278 +FB79 93D3 +FB7A 35A1 +FB7B 591F +FB7C 68A6 +FB7D 36C3 +FB7E 6E59 +FBA1 2163E +FBA2 5A24 +FBA3 5553 +FBA4 21692 +FBA5 8505 +FBA6 59C9 +FBA7 20D4E +FBA8 26C81 +FBA9 26D2A +FBAA 217DC +FBAB 59D9 +FBAC 217FB +FBAD 217B2 +FBAE 26DA6 +FBAF 6D71 +FBB0 21828 +FBB1 216D5 +FBB2 59F9 +FBB3 26E45 +FBB4 5AAB +FBB5 5A63 +FBB6 36E6 +FBB7 249A9 +FBB9 3708 +FBBA 5A96 +FBBB 7465 +FBBC 5AD3 +FBBD 26FA1 +FBBE 22554 +FBBF 3D85 +FBC0 21911 +FBC1 3732 +FBC2 216B8 +FBC3 5E83 +FBC4 52D0 +FBC5 5B76 +FBC6 6588 +FBC7 5B7C +FBC8 27A0E +FBC9 4004 +FBCA 485D +FBCB 20204 +FBCC 5BD5 +FBCD 6160 +FBCE 21A34 +FBCF 259CC +FBD0 205A5 +FBD1 5BF3 +FBD2 5B9D +FBD3 4D10 +FBD4 5C05 +FBD5 21B44 +FBD6 5C13 +FBD7 73CE +FBD8 5C14 +FBD9 21CA5 +FBDA 26B28 +FBDB 5C49 +FBDC 48DD +FBDD 5C85 +FBDE 5CE9 +FBDF 5CEF +FBE0 5D8B +FBE1 21DF9 +FBE2 21E37 +FBE3 5D10 +FBE4 5D18 +FBE5 5D46 +FBE6 21EA4 +FBE7 5CBA +FBE8 5DD7 +FBE9 82FC +FBEA 382D +FBEB 24901 +FBEC 22049 +FBED 22173 +FBEE 8287 +FBEF 3836 +FBF0 3BC2 +FBF1 5E2E +FBF2 6A8A +FBF4 5E7A +FBF5 244BC +FBF6 20CD3 +FBF7 53A6 +FBF8 4EB7 +FBFA 53A8 +FBFB 21771 +FBFC 5E09 +FBFD 5EF4 +FBFE 28482 +FC40 5EF9 +FC41 5EFB +FC42 38A0 +FC43 5EFC +FC44 683E +FC45 941B +FC46 5F0D +FC47 201C1 +FC48 2F894 +FC49 3ADE +FC4A 48AE +FC4B 2133A +FC4C 5F3A +FC4D 26888 +FC4E 223D0 +FC50 22471 +FC51 5F63 +FC52 97BD +FC53 26E6E +FC54 5F72 +FC55 9340 +FC56 28A36 +FC57 5FA7 +FC58 5DB6 +FC59 3D5F +FC5A 25250 +FC5B 21F6A +FC5C 270F8 +FC5D 22668 +FC5E 91D6 +FC5F 2029E +FC60 28A29 +FC61 6031 +FC62 6685 +FC63 21877 +FC64 3963 +FC65 3DC7 +FC66 3639 +FC67 5790 +FC68 227B4 +FC69 7971 +FC6A 3E40 +FC6B 609E +FC6D 60B3 +FC6E 24982 +FC6F 2498F +FC70 27A53 +FC71 74A4 +FC72 50E1 +FC73 5AA0 +FC74 6164 +FC75 8424 +FC76 6142 +FC77 2F8A6 +FC78 26ED2 +FC79 6181 +FC7A 51F4 +FC7B 20656 +FC7C 6187 +FC7D 5BAA +FC7E 23FB7 +FCA1 2285F +FCA2 61D3 +FCA3 28B9D +FCA4 2995D +FCA5 61D0 +FCA6 3932 +FCA7 22980 +FCA8 228C1 +FCA9 6023 +FCAA 615C +FCAB 651E +FCAC 638B +FCAD 20118 +FCAE 62C5 +FCAF 21770 +FCB0 62D5 +FCB1 22E0D +FCB2 636C +FCB3 249DF +FCB4 3A17 +FCB5 6438 +FCB6 63F8 +FCB7 2138E +FCB8 217FC +FCBA 6F8A +FCBB 22E36 +FCBC 9814 +FCBD 2408C +FCBE 2571D +FCBF 64E1 +FCC0 64E5 +FCC1 947B +FCC2 3A66 +FCC3 643A +FCC4 3A57 +FCC5 654D +FCC6 6F16 +FCC7 24A28 +FCC8 24A23 +FCC9 6585 +FCCA 656D +FCCB 655F +FCCC 2307E +FCCD 65B5 +FCCE 24940 +FCCF 4B37 +FCD0 65D1 +FCD1 40D8 +FCD2 21829 +FCD3 65E0 +FCD4 65E3 +FCD5 5FDF +FCD6 23400 +FCD7 6618 +FCD8 231F7 +FCD9 231F8 +FCDA 6644 +FCDB 231A4 +FCDC 231A5 +FCDD 664B +FCDE 20E75 +FCDF 6667 +FCE0 251E6 +FCE1 6673 +FCE3 21E3D +FCE4 23231 +FCE5 285F4 +FCE6 231C8 +FCE7 25313 +FCE8 77C5 +FCE9 228F7 +FCEA 99A4 +FCEB 6702 +FCEC 2439C +FCED 24A21 +FCEE 3B2B +FCEF 69FA +FCF0 237C2 +FCF2 6767 +FCF3 6762 +FCF4 241CD +FCF5 290ED +FCF6 67D7 +FCF7 44E9 +FCF8 6822 +FCF9 6E50 +FCFA 923C +FCFB 6801 +FCFC 233E6 +FCFD 26DA0 +FCFE 685D +FD40 2346F +FD41 69E1 +FD42 6A0B +FD43 28ADF +FD44 6973 +FD45 68C3 +FD46 235CD +FD47 6901 +FD48 6900 +FD49 3D32 +FD4A 3A01 +FD4B 2363C +FD4C 3B80 +FD4D 67AC +FD4E 6961 +FD4F 28A4A +FD50 42FC +FD51 6936 +FD52 6998 +FD53 3BA1 +FD54 203C9 +FD55 8363 +FD56 5090 +FD57 69F9 +FD58 23659 +FD59 2212A +FD5A 6A45 +FD5B 23703 +FD5C 6A9D +FD5D 3BF3 +FD5E 67B1 +FD5F 6AC8 +FD60 2919C +FD61 3C0D +FD62 6B1D +FD63 20923 +FD64 60DE +FD65 6B35 +FD66 6B74 +FD67 227CD +FD68 6EB5 +FD69 23ADB +FD6A 203B5 +FD6B 21958 +FD6C 3740 +FD6D 5421 +FD6E 23B5A +FD6F 6BE1 +FD70 23EFC +FD71 6BDC +FD72 6C37 +FD73 2248B +FD74 248F1 +FD75 26B51 +FD76 6C5A +FD77 8226 +FD78 6C79 +FD79 23DBC +FD7A 44C5 +FD7B 23DBD +FD7C 241A4 +FD7D 2490C +FD7E 24900 +FDA1 23CC9 +FDA2 36E5 +FDA3 3CEB +FDA4 20D32 +FDA5 9B83 +FDA6 231F9 +FDA7 22491 +FDA8 7F8F +FDA9 6837 +FDAA 26D25 +FDAB 26DA1 +FDAC 26DEB +FDAD 6D96 +FDAE 6D5C +FDAF 6E7C +FDB0 6F04 +FDB1 2497F +FDB2 24085 +FDB3 26E72 +FDB4 8533 +FDB5 26F74 +FDB6 51C7 +FDB9 842E +FDBA 28B21 +FDBC 23E2F +FDBD 7453 +FDBE 23F82 +FDBF 79CC +FDC0 6E4F +FDC1 5A91 +FDC2 2304B +FDC3 6FF8 +FDC4 370D +FDC5 6F9D +FDC6 23E30 +FDC7 6EFA +FDC8 21497 +FDC9 2403D +FDCA 4555 +FDCB 93F0 +FDCC 6F44 +FDCD 6F5C +FDCE 3D4E +FDCF 6F74 +FDD0 29170 +FDD1 3D3B +FDD2 6F9F +FDD3 24144 +FDD4 6FD3 +FDD5 24091 +FDD6 24155 +FDD7 24039 +FDD8 23FF0 +FDD9 23FB4 +FDDA 2413F +FDDB 51DF +FDDC 24156 +FDDD 24157 +FDDE 24140 +FDDF 261DD +FDE0 704B +FDE1 707E +FDE2 70A7 +FDE3 7081 +FDE4 70CC +FDE5 70D5 +FDE6 70D6 +FDE7 70DF +FDE8 4104 +FDE9 3DE8 +FDEA 71B4 +FDEB 7196 +FDEC 24277 +FDED 712B +FDEE 7145 +FDEF 5A88 +FDF0 714A +FDF2 5C9C +FDF3 24365 +FDF4 714F +FDF5 9362 +FDF6 242C1 +FDF7 712C +FDF8 2445A +FDF9 24A27 +FDFA 24A22 +FDFB 71BA +FDFC 28BE8 +FDFD 70BD +FDFE 720E +FE40 9442 +FE41 7215 +FE42 5911 +FE43 9443 +FE44 7224 +FE45 9341 +FE46 25605 +FE47 722E +FE48 7240 +FE49 24974 +FE4A 68BD +FE4B 7255 +FE4C 7257 +FE4D 3E55 +FE4E 23044 +FE4F 680D +FE50 6F3D +FE51 7282 +FE53 732B +FE54 24823 +FE55 2882B +FE56 48ED +FE57 28804 +FE58 7328 +FE59 732E +FE5A 73CF +FE5B 73AA +FE5C 20C3A +FE5D 26A2E +FE5E 73C9 +FE5F 7449 +FE60 241E2 +FE61 216E7 +FE62 24A24 +FE63 6623 +FE64 36C5 +FE65 249B7 +FE66 2498D +FE67 249FB +FE68 73F7 +FE69 7415 +FE6A 6903 +FE6B 24A26 +FE6C 7439 +FE6D 205C3 +FE6E 3ED7 +FE70 228AD +FE71 7460 +FE72 28EB2 +FE73 7447 +FE74 73E4 +FE75 7476 +FE76 83B9 +FE77 746C +FE78 3730 +FE79 7474 +FE7A 93F1 +FE7B 6A2C +FE7C 7482 +FE7D 4953 +FE7E 24A8C +FEA1 2415F +FEA2 24A79 +FEA3 28B8F +FEA4 5B46 +FEA5 28C03 +FEA6 2189E +FEA7 74C8 +FEA8 21988 +FEA9 750E +FEAB 751E +FEAC 28ED9 +FEAD 21A4B +FEAE 5BD7 +FEAF 28EAC +FEB0 9385 +FEB1 754D +FEB2 754A +FEB3 7567 +FEB4 756E +FEB5 24F82 +FEB6 3F04 +FEB7 24D13 +FEB8 758E +FEB9 745D +FEBA 759E +FEBB 75B4 +FEBC 7602 +FEBD 762C +FEBE 7651 +FEBF 764F +FEC0 766F +FEC1 7676 +FEC2 263F5 +FEC3 7690 +FEC4 81EF +FEC5 37F8 +FEC6 26911 +FEC7 2690E +FEC8 76A1 +FEC9 76A5 +FECA 76B7 +FECB 76CC +FECC 26F9F +FECD 8462 +FECE 2509D +FECF 2517D +FED0 21E1C +FED1 771E +FED2 7726 +FED3 7740 +FED4 64AF +FED5 25220 +FED6 7758 +FED7 232AC +FED8 77AF +FED9 28964 +FEDA 28968 +FEDB 216C1 +FEDC 77F4 +FEDE 21376 +FEDF 24A12 +FEE0 68CA +FEE1 78AF +FEE2 78C7 +FEE3 78D3 +FEE4 96A5 +FEE5 792E +FEE6 255E0 +FEE7 78D7 +FEE8 7934 +FEE9 78B1 +FEEA 2760C +FEEB 8FB8 +FEEC 8884 +FEED 28B2B +FEEE 26083 +FEEF 2261C +FEF0 7986 +FEF1 8900 +FEF2 6902 +FEF3 7980 +FEF4 25857 +FEF5 799D +FEF6 27B39 +FEF7 793C +FEF8 79A9 +FEF9 6E2A +FEFA 27126 +FEFB 3EA8 +FEFC 79C6 +FEFD 2910D +FEFE 79D4 diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index af37f12f39dc2..187320ca26ed4 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -539,6 +539,7 @@ $(BUILDDIR)/$(gcc_ver)/Makefile \ $(PATHPRE) $(ENVS) $(GCC_CFG) $(EXTRA_CFLAGS) \ $(CONFIG) \ --with-sysroot=$(SYSROOT) \ + --with-debug-prefix-map=$(OUTPUT_ROOT)=devkit \ --enable-languages=c,c++ \ --enable-shared \ --disable-nls \ diff --git a/make/devkit/createJMHBundle.sh b/make/devkit/createJMHBundle.sh index af29a0917d606..c3c97947dabf0 100644 --- a/make/devkit/createJMHBundle.sh +++ b/make/devkit/createJMHBundle.sh @@ -26,8 +26,8 @@ # Create a bundle in the build directory, containing what's needed to # build and run JMH microbenchmarks from the OpenJDK build. -JMH_VERSION=1.36 -COMMONS_MATH3_VERSION=3.2 +JMH_VERSION=1.37 +COMMONS_MATH3_VERSION=3.6.1 JOPT_SIMPLE_VERSION=5.0.4 BUNDLE_NAME=jmh-$JMH_VERSION.tar.gz diff --git a/make/hotspot/gensrc/GensrcAdlc.gmk b/make/hotspot/gensrc/GensrcAdlc.gmk index 427a0dfd34b79..0898d91e1c2a0 100644 --- a/make/hotspot/gensrc/GensrcAdlc.gmk +++ b/make/hotspot/gensrc/GensrcAdlc.gmk @@ -62,7 +62,7 @@ ifeq ($(call check-jvm-feature, compiler2), true) ADLC_CFLAGS += -I$(TOPDIR)/src/hotspot/share # Add file macro mappings - ADLC_CFLAGS += $(FILE_MACRO_CFLAGS) + ADLC_CFLAGS += $(FILE_MACRO_CFLAGS) $(REPRODUCIBLE_CFLAGS) ifeq ($(UBSAN_ENABLED), true) ADLC_CFLAGS += $(UBSAN_CFLAGS) @@ -133,6 +133,21 @@ ifeq ($(call check-jvm-feature, compiler2), true) ADLCFLAGS += -DARM=1 endif + # Set ASSERT, NDEBUG and PRODUCT flags just like in JvmFlags.gmk + ifeq ($(DEBUG_LEVEL), release) + # release builds disable uses of assert macro from . + ADLCFLAGS += -DNDEBUG + # For hotspot, release builds differ internally between "optimized" and "product" + # in that "optimize" does not define PRODUCT. + ifneq ($(HOTSPOT_DEBUG_LEVEL), optimized) + ADLCFLAGS += -DPRODUCT + endif + else ifeq ($(DEBUG_LEVEL), fastdebug) + ADLCFLAGS += -DASSERT + else ifeq ($(DEBUG_LEVEL), slowdebug) + ADLCFLAGS += -DASSERT + endif + ############################################################################## # Concatenate all ad source files into a single file, which will be fed to # adlc. Also include a #line directive at the start of every included file diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index adb964d05389a..d21e7f99c63a7 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -276,10 +276,10 @@ ifneq ($(GENERATE_COMPILE_COMMANDS_ONLY), true) define SetupOperatorNewDeleteCheck $1.op_check: $1 $$(call ExecuteWithLog, $1.op_check, \ - $$(NM) $$< 2>&1 | $$(GREP) $$(addprefix -e , $$(MANGLED_SYMS)) | $$(GREP) $$(UNDEF_PATTERN) > $1.op_check || true) + $$(NM) $$(NMFLAGS) $$< 2>&1 | $$(GREP) $$(addprefix -e , $$(MANGLED_SYMS)) | $$(GREP) $$(UNDEF_PATTERN) > $1.op_check || true) if [ -s $1.op_check ]; then \ $$(ECHO) "$$(notdir $$<): Error: Use of global operators new and delete is not allowed in Hotspot:"; \ - $$(NM) $$< | $$(CXXFILT) | $$(EGREP) '$$(DEMANGLED_REGEXP)' | $$(GREP) $$(UNDEF_PATTERN); \ + $$(NM) $$(NMFLAGS) $$< | $$(CXXFILT) | $$(EGREP) '$$(DEMANGLED_REGEXP)' | $$(GREP) $$(UNDEF_PATTERN); \ $$(ECHO) "See: $$(TOPDIR)/make/hotspot/lib/CompileJvm.gmk"; \ exit 1; \ fi diff --git a/make/hotspot/lib/JvmMapfile.gmk b/make/hotspot/lib/JvmMapfile.gmk index d80b804a2f6ca..2808ac2af0372 100644 --- a/make/hotspot/lib/JvmMapfile.gmk +++ b/make/hotspot/lib/JvmMapfile.gmk @@ -53,7 +53,7 @@ endif # platform dependent. ifeq ($(call isTargetOs, linux), true) - DUMP_SYMBOLS_CMD := $(NM) --defined-only *$(OBJ_SUFFIX) + DUMP_SYMBOLS_CMD := $(NM) $(NMFLAGS) --defined-only *$(OBJ_SUFFIX) ifneq ($(FILTER_SYMBOLS_PATTERN), ) FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)| endif @@ -67,7 +67,7 @@ ifeq ($(call isTargetOs, linux), true) else ifeq ($(call isTargetOs, macosx), true) # nm on macosx prints out "warning: nm: no name list" to stderr for # files without symbols. Hide this, even at the expense of hiding real errors. - DUMP_SYMBOLS_CMD := $(NM) -Uj *$(OBJ_SUFFIX) 2> /dev/null + DUMP_SYMBOLS_CMD := $(NM) $(NMFLAGS) -Uj *$(OBJ_SUFFIX) 2> /dev/null ifneq ($(FILTER_SYMBOLS_PATTERN), ) FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)| endif @@ -89,7 +89,7 @@ else ifeq ($(call isTargetOs, aix), true) # which may be installed under /opt/freeware/bin. So better use an absolute path here! # NM=/usr/bin/nm - DUMP_SYMBOLS_CMD := $(NM) -X64 -B -C *$(OBJ_SUFFIX) + DUMP_SYMBOLS_CMD := $(NM) $(NMFLAGS) -B -C *$(OBJ_SUFFIX) FILTER_SYMBOLS_AWK_SCRIPT := \ '{ \ if (($$2="d" || $$2="D") && ($$3 ~ /^__vft/ || $$3 ~ /^gHotSpotVM/)) print $$3; \ diff --git a/make/hotspot/test/GtestImage.gmk b/make/hotspot/test/GtestImage.gmk index d216328e5674e..9b2a37962cddd 100644 --- a/make/hotspot/test/GtestImage.gmk +++ b/make/hotspot/test/GtestImage.gmk @@ -61,7 +61,7 @@ ifeq ($(call isTargetOs, windows), true) $(eval $(call SetupCopyFiles, COPY_GTEST_PDB_$v, \ SRC := $(HOTSPOT_OUTPUTDIR)/variant-$v/libjvm/gtest, \ DEST := $(TEST_IMAGE_DIR)/hotspot/gtest/$v, \ - FILES := jvm.pdb gtestLauncher.pdb, \ + FILES := jvm.dll.pdb gtestLauncher.exe.pdb, \ )) \ $(eval TARGETS += $$(COPY_GTEST_PDB_$v)) \ ) \ diff --git a/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java b/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java index 092e5afd3e8fe..ed085dae09562 100644 --- a/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java +++ b/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java @@ -329,7 +329,7 @@ Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir) { addAttr(rv, "PrecompiledHeaderOutputFile", outDir+Util.sep+"vm.pch"); addAttr(rv, "AssemblerListingLocation", outDir); addAttr(rv, "ObjectFileName", outDir+Util.sep); - addAttr(rv, "ProgramDataBaseFileName", outDir+Util.sep+"jvm.pdb"); + addAttr(rv, "ProgramDataBaseFileName", outDir+Util.sep+"jvm.dll.pdb"); // Set /nologo option addAttr(rv, "SuppressStartupBanner", "true"); // Surpass the default /Tc or /Tp. @@ -409,7 +409,7 @@ Vector getBaseLinkerFlags(String outDir, String outDll, String platformName) { addAttr(rv, "OutputFile", outDll); addAttr(rv, "SuppressStartupBanner", "true"); addAttr(rv, "ModuleDefinitionFile", outDir+Util.sep+"vm.def"); - addAttr(rv, "ProgramDatabaseFile", outDir+Util.sep+"jvm.pdb"); + addAttr(rv, "ProgramDatabaseFile", outDir+Util.sep+"jvm.dll.pdb"); addAttr(rv, "SubSystem", "Windows"); addAttr(rv, "BaseAddress", "0x8000000"); addAttr(rv, "ImportLibrary", outDir+Util.sep+"jvm.lib"); diff --git a/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java b/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java index 561edbef0346a..9655e08016c5a 100644 --- a/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java +++ b/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.io.FileOutputStream; import java.io.InputStream; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.Locale; @@ -339,9 +340,15 @@ private static void buildOtherTables() { validCurrencyCodes.substring(i * 7 + 3, i * 7 + 6)); checkCurrencyCode(currencyCode); int tableEntry = mainTable[(currencyCode.charAt(0) - 'A') * A_TO_Z + (currencyCode.charAt(1) - 'A')]; - if (tableEntry == INVALID_COUNTRY_ENTRY || - (tableEntry & SPECIAL_CASE_COUNTRY_MASK) != 0 || - (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) != (currencyCode.charAt(2) - 'A')) { + + // Do not allow a future currency to be classified as an otherCurrency, + // otherwise it will leak out into Currency:getAvailableCurrencies + boolean futureCurrency = Arrays.asList(specialCaseNewCurrencies).contains(currencyCode); + boolean simpleCurrency = (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) == (currencyCode.charAt(2) - 'A'); + + // If neither a simple currency, or one defined in the future + // then the current currency is applicable to be added to the otherTable + if (!futureCurrency && !simpleCurrency) { if (otherCurrenciesCount == maxOtherCurrencies) { throw new RuntimeException("too many other currencies"); } diff --git a/make/langtools/tools/javacserver/client/Client.java b/make/langtools/tools/javacserver/client/Client.java index b3b4a8543a059..9576a9923a4e5 100644 --- a/make/langtools/tools/javacserver/client/Client.java +++ b/make/langtools/tools/javacserver/client/Client.java @@ -51,9 +51,9 @@ public class Client { private static final Log.Level LOG_LEVEL = Log.Level.INFO; - // Wait 2 seconds for response, before giving up on javac server. - private static final int CONNECTION_TIMEOUT = 2000; - private static final int MAX_CONNECT_ATTEMPTS = 3; + // Wait 4 seconds for response, before giving up on javac server. + private static final int CONNECTION_TIMEOUT = 4000; + private static final int MAX_CONNECT_ATTEMPTS = 10; private static final int WAIT_BETWEEN_CONNECT_ATTEMPTS = 2000; private final ClientConfiguration conf; @@ -130,7 +130,7 @@ private Socket tryConnect() throws IOException, InterruptedException { Log.error("Connection attempt failed: " + ex.getMessage()); if (attempt >= MAX_CONNECT_ATTEMPTS) { Log.error("Giving up"); - throw new IOException("Could not connect to server", ex); + throw new IOException("Could not connect to server after " + MAX_CONNECT_ATTEMPTS + " attempts with timeout " + CONNECTION_TIMEOUT, ex); } } Thread.sleep(WAIT_BETWEEN_CONNECT_ATTEMPTS); diff --git a/make/modules/java.base/gensrc/GensrcMisc.gmk b/make/modules/java.base/gensrc/GensrcMisc.gmk index e37aa50d41cb1..578adce4e9da6 100644 --- a/make/modules/java.base/gensrc/GensrcMisc.gmk +++ b/make/modules/java.base/gensrc/GensrcMisc.gmk @@ -52,9 +52,7 @@ $(eval $(call SetupTextFileProcessing, BUILD_VERSION_JAVA, \ # Normalize OPENJDK_TARGET_CPU name to match jdk.internal.util.Architecture enum -ifneq ($(filter $(OPENJDK_TARGET_CPU), ppc64le), ) - OPENJDK_TARGET_ARCH_CANONICAL = ppc64 -else ifneq ($(filter $(OPENJDK_TARGET_CPU), s390x), ) +ifneq ($(filter $(OPENJDK_TARGET_CPU), s390x), ) OPENJDK_TARGET_ARCH_CANONICAL = s390 else ifneq ($(filter $(OPENJDK_TARGET_CPU), x86_64 amd64), ) OPENJDK_TARGET_ARCH_CANONICAL = x64 diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk index 62b4477b8bfcf..d6a4e6df4fce3 100644 --- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk +++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk @@ -237,6 +237,8 @@ ifeq ($(call isTargetOs, windows macosx), false) DISABLED_WARNINGS_gcc_gtk3_interface.c := parentheses type-limits unused-function, \ DISABLED_WARNINGS_gcc_OGLBufImgOps.c := format-nonliteral, \ DISABLED_WARNINGS_gcc_OGLPaints.c := format-nonliteral, \ + DISABLED_WARNINGS_gcc_screencast_pipewire.c := undef, \ + DISABLED_WARNINGS_gcc_screencast_portal.c := undef, \ DISABLED_WARNINGS_gcc_sun_awt_X11_GtkFileDialogPeer.c := parentheses, \ DISABLED_WARNINGS_gcc_X11SurfaceData.c := implicit-fallthrough pointer-to-int-cast, \ DISABLED_WARNINGS_gcc_XlibWrapper.c := type-limits pointer-to-int-cast, \ @@ -465,11 +467,18 @@ else # hb-ft.cc is not presently needed, and requires freetype 2.4.2 or later. LIBFONTMANAGER_EXCLUDE_FILES += libharfbuzz/hb-ft.cc + # list of disabled warnings and the compilers for which it was specifically added. + # array-bounds -> GCC 12 on Alpine Linux + # parentheses -> GCC 6 + # range-loop-analysis -> clang on Xcode12 + HARFBUZZ_DISABLED_WARNINGS_gcc := missing-field-initializers strict-aliasing \ - unused-result array-bounds + unused-result array-bounds parentheses # noexcept-type required for GCC 7 builds. Not required for GCC 8+. # expansion-to-defined required for GCC 9 builds. Not required for GCC 10+. - HARFBUZZ_DISABLED_WARNINGS_CXX_gcc := class-memaccess noexcept-type expansion-to-defined dangling-reference + # maybe-uninitialized required for GCC 8 builds. Not required for GCC 9+. + HARFBUZZ_DISABLED_WARNINGS_CXX_gcc := class-memaccess noexcept-type \ + expansion-to-defined dangling-reference maybe-uninitialized HARFBUZZ_DISABLED_WARNINGS_clang := missing-field-initializers range-loop-analysis HARFBUZZ_DISABLED_WARNINGS_microsoft := 4267 4244 diff --git a/make/scripts/compare_exceptions.sh.incl b/make/scripts/compare_exceptions.sh.incl index d9f62aa113222..d5043637145b2 100644 --- a/make/scripts/compare_exceptions.sh.incl +++ b/make/scripts/compare_exceptions.sh.incl @@ -49,8 +49,8 @@ elif [ "$OPENJDK_TARGET_OS" = "windows" ]; then SKIP_BIN_DIFF="true" SKIP_FULLDUMP_DIFF="true" ACCEPTED_JARZIP_CONTENTS=" - /modules_libs/java.security.jgss/w2k_lsa_auth.pdb - /modules_libs/java.security.jgss/w2k_lsa_auth.map + /modules_libs/java.security.jgss/w2k_lsa_auth.dll.pdb + /modules_libs/java.security.jgss/w2k_lsa_auth.dll.map /modules_libs/java.security.jgss/w2k_lsa_auth.dll " elif [ "$OPENJDK_TARGET_OS" = "macosx" ]; then diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk index 5f945e90dd288..94c8810bba90c 100644 --- a/make/test/JtregNativeJdk.gmk +++ b/make/test/JtregNativeJdk.gmk @@ -132,6 +132,8 @@ ifeq ($(call isTargetOs, linux), true) # stripping during the test libraries' build. BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libFib := -g BUILD_JDK_JTREG_LIBRARIES_STRIP_SYMBOLS_libFib := false + # nio tests' libCreationTimeHelper native needs -ldl linker flag + BUILD_JDK_JTREG_LIBRARIES_LIBS_libCreationTimeHelper := -ldl endif ifeq ($(ASAN_ENABLED), true) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index fea6a3d7d115e..a9aa3cab3004e 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -3809,202 +3809,6 @@ encode %{ __ br(target_reg); %} - enc_class aarch64_enc_fast_lock(iRegP object, iRegP box, iRegP tmp, iRegP tmp2) %{ - C2_MacroAssembler _masm(&cbuf); - Register oop = as_Register($object$$reg); - Register box = as_Register($box$$reg); - Register disp_hdr = as_Register($tmp$$reg); - Register tmp = as_Register($tmp2$$reg); - Label cont; - Label object_has_monitor; - Label count, no_count; - - assert_different_registers(oop, box, tmp, disp_hdr); - - // Load markWord from object into displaced_header. - __ ldr(disp_hdr, Address(oop, oopDesc::mark_offset_in_bytes())); - - if (DiagnoseSyncOnValueBasedClasses != 0) { - __ load_klass(tmp, oop); - __ ldrw(tmp, Address(tmp, Klass::access_flags_offset())); - __ tstw(tmp, JVM_ACC_IS_VALUE_BASED_CLASS); - __ br(Assembler::NE, cont); - } - - // Check for existing monitor - __ tbnz(disp_hdr, exact_log2(markWord::monitor_value), object_has_monitor); - - if (LockingMode == LM_MONITOR) { - __ tst(oop, oop); // Set NE to indicate 'failure' -> take slow-path. We know that oop != 0. - __ b(cont); - } else if (LockingMode == LM_LEGACY) { - // Set tmp to be (markWord of object | UNLOCK_VALUE). - __ orr(tmp, disp_hdr, markWord::unlocked_value); - - // Initialize the box. (Must happen before we update the object mark!) - __ str(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); - - // Compare object markWord with an unlocked value (tmp) and if - // equal exchange the stack address of our box with object markWord. - // On failure disp_hdr contains the possibly locked markWord. - __ cmpxchg(oop, tmp, box, Assembler::xword, /*acquire*/ true, - /*release*/ true, /*weak*/ false, disp_hdr); - __ br(Assembler::EQ, cont); - - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - - // If the compare-and-exchange succeeded, then we found an unlocked - // object, will have now locked it will continue at label cont - - // Check if the owner is self by comparing the value in the - // markWord of object (disp_hdr) with the stack pointer. - __ mov(rscratch1, sp); - __ sub(disp_hdr, disp_hdr, rscratch1); - __ mov(tmp, (address) (~(os::vm_page_size()-1) | markWord::lock_mask_in_place)); - // If condition is true we are cont and hence we can store 0 as the - // displaced header in the box, which indicates that it is a recursive lock. - __ ands(tmp/*==0?*/, disp_hdr, tmp); // Sets flags for result - __ str(tmp/*==0, perhaps*/, Address(box, BasicLock::displaced_header_offset_in_bytes())); - __ b(cont); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ fast_lock(oop, disp_hdr, tmp, rscratch1, no_count); - __ b(count); - } - - // Handle existing monitor. - __ bind(object_has_monitor); - - // The object's monitor m is unlocked iff m->owner == NULL, - // otherwise m->owner may contain a thread or a stack address. - // - // Try to CAS m->owner from NULL to current thread. - __ add(tmp, disp_hdr, (in_bytes(ObjectMonitor::owner_offset())-markWord::monitor_value)); - __ cmpxchg(tmp, zr, rthread, Assembler::xword, /*acquire*/ true, - /*release*/ true, /*weak*/ false, rscratch1); // Sets flags for result - - if (LockingMode != LM_LIGHTWEIGHT) { - // Store a non-null value into the box to avoid looking like a re-entrant - // lock. The fast-path monitor unlock code checks for - // markWord::monitor_value so use markWord::unused_mark which has the - // relevant bit set, and also matches ObjectSynchronizer::enter. - __ mov(tmp, (address)markWord::unused_mark().value()); - __ str(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); - } - __ br(Assembler::EQ, cont); // CAS success means locking succeeded - - __ cmp(rscratch1, rthread); - __ br(Assembler::NE, cont); // Check for recursive locking - - // Recursive lock case - __ increment(Address(disp_hdr, in_bytes(ObjectMonitor::recursions_offset()) - markWord::monitor_value), 1); - // flag == EQ still from the cmp above, checking if this is a reentrant lock - - __ bind(cont); - // flag == EQ indicates success - // flag == NE indicates failure - __ br(Assembler::NE, no_count); - - __ bind(count); - __ increment(Address(rthread, JavaThread::held_monitor_count_offset())); - - __ bind(no_count); - %} - - enc_class aarch64_enc_fast_unlock(iRegP object, iRegP box, iRegP tmp, iRegP tmp2) %{ - C2_MacroAssembler _masm(&cbuf); - Register oop = as_Register($object$$reg); - Register box = as_Register($box$$reg); - Register disp_hdr = as_Register($tmp$$reg); - Register tmp = as_Register($tmp2$$reg); - Label cont; - Label object_has_monitor; - Label count, no_count; - - assert_different_registers(oop, box, tmp, disp_hdr); - - if (LockingMode == LM_LEGACY) { - // Find the lock address and load the displaced header from the stack. - __ ldr(disp_hdr, Address(box, BasicLock::displaced_header_offset_in_bytes())); - - // If the displaced header is 0, we have a recursive unlock. - __ cmp(disp_hdr, zr); - __ br(Assembler::EQ, cont); - } - - // Handle existing monitor. - __ ldr(tmp, Address(oop, oopDesc::mark_offset_in_bytes())); - __ tbnz(tmp, exact_log2(markWord::monitor_value), object_has_monitor); - - if (LockingMode == LM_MONITOR) { - __ tst(oop, oop); // Set NE to indicate 'failure' -> take slow-path. We know that oop != 0. - __ b(cont); - } else if (LockingMode == LM_LEGACY) { - // Check if it is still a light weight lock, this is is true if we - // see the stack address of the basicLock in the markWord of the - // object. - - __ cmpxchg(oop, box, disp_hdr, Assembler::xword, /*acquire*/ false, - /*release*/ true, /*weak*/ false, tmp); - __ b(cont); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ fast_unlock(oop, tmp, box, disp_hdr, no_count); - __ b(count); - } - - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - - // Handle existing monitor. - __ bind(object_has_monitor); - STATIC_ASSERT(markWord::monitor_value <= INT_MAX); - __ add(tmp, tmp, -(int)markWord::monitor_value); // monitor - - if (LockingMode == LM_LIGHTWEIGHT) { - // If the owner is anonymous, we need to fix it -- in an outline stub. - Register tmp2 = disp_hdr; - __ ldr(tmp2, Address(tmp, ObjectMonitor::owner_offset())); - // We cannot use tbnz here, the target might be too far away and cannot - // be encoded. - __ tst(tmp2, (uint64_t)ObjectMonitor::ANONYMOUS_OWNER); - C2HandleAnonOMOwnerStub* stub = new (Compile::current()->comp_arena()) C2HandleAnonOMOwnerStub(tmp, tmp2); - Compile::current()->output()->add_stub(stub); - __ br(Assembler::NE, stub->entry()); - __ bind(stub->continuation()); - } - - __ ldr(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset())); - - Label notRecursive; - __ cbz(disp_hdr, notRecursive); - - // Recursive lock - __ sub(disp_hdr, disp_hdr, 1u); - __ str(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset())); - __ cmp(disp_hdr, disp_hdr); // Sets flags for result - __ b(cont); - - __ bind(notRecursive); - __ ldr(rscratch1, Address(tmp, ObjectMonitor::EntryList_offset())); - __ ldr(disp_hdr, Address(tmp, ObjectMonitor::cxq_offset())); - __ orr(rscratch1, rscratch1, disp_hdr); // Will be 0 if both are 0. - __ cmp(rscratch1, zr); // Sets flags for result - __ cbnz(rscratch1, cont); - // need a release store here - __ lea(tmp, Address(tmp, ObjectMonitor::owner_offset())); - __ stlr(zr, tmp); // set unowned - - __ bind(cont); - // flag == EQ indicates success - // flag == NE indicates failure - __ br(Assembler::NE, no_count); - - __ bind(count); - __ decrement(Address(rthread, JavaThread::held_monitor_count_offset())); - - __ bind(no_count); - %} - %} //----------FRAME-------------------------------------------------------------- @@ -16609,17 +16413,19 @@ instruct branchLoopEnd(cmpOp cmp, rFlagsReg cr, label lbl) // ============================================================================ // inlined locking and unlocking -instruct cmpFastLock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp, iRegPNoSp tmp2) +instruct cmpFastLock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp, iRegPNoSp tmp2, iRegPNoSp tmp3) %{ match(Set cr (FastLock object box)); - effect(TEMP tmp, TEMP tmp2); + effect(TEMP tmp, TEMP tmp2, TEMP tmp3); // TODO // identify correct cost ins_cost(5 * INSN_COST); format %{ "fastlock $object,$box\t! kills $tmp,$tmp2" %} - ins_encode(aarch64_enc_fast_lock(object, box, tmp, tmp2)); + ins_encode %{ + __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register); + %} ins_pipe(pipe_serial); %} @@ -16632,7 +16438,9 @@ instruct cmpFastUnlock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp, iRe ins_cost(5 * INSN_COST); format %{ "fastunlock $object,$box\t! kills $tmp, $tmp2" %} - ins_encode(aarch64_enc_fast_unlock(object, box, tmp, tmp2)); + ins_encode %{ + __ fast_unlock($object$$Register, $box$$Register, $tmp$$Register, $tmp2$$Register); + %} ins_pipe(pipe_serial); %} diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 4bf7fee936bac..656dbdf7ae8cb 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -282,7 +282,8 @@ void LIR_Assembler::osr_entry() { __ bind(L); } #endif - __ ldp(r19, r20, Address(OSR_buf, slot_offset)); + __ ldr(r19, Address(OSR_buf, slot_offset)); + __ ldr(r20, Address(OSR_buf, slot_offset + BytesPerWord)); __ str(r19, frame_map()->address_for_monitor_lock(i)); __ str(r20, frame_map()->address_for_monitor_object(i)); } @@ -434,7 +435,7 @@ int LIR_Assembler::emit_unwind_handler() { if (LockingMode == LM_MONITOR) { __ b(*stub->entry()); } else { - __ unlock_object(r5, r4, r0, *stub->entry()); + __ unlock_object(r5, r4, r0, r6, *stub->entry()); } __ bind(*stub->continuation()); } @@ -2558,6 +2559,7 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register obj = op->obj_opr()->as_register(); // may not be an oop Register hdr = op->hdr_opr()->as_register(); Register lock = op->lock_opr()->as_register(); + Register temp = op->scratch_opr()->as_register(); if (LockingMode == LM_MONITOR) { if (op->info() != nullptr) { add_debug_info_for_null_check_here(op->info()); @@ -2567,14 +2569,14 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { } else if (op->code() == lir_lock) { assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); // add debug info for NullPointerException only if one is possible - int null_check_offset = __ lock_object(hdr, obj, lock, *op->stub()->entry()); + int null_check_offset = __ lock_object(hdr, obj, lock, temp, *op->stub()->entry()); if (op->info() != nullptr) { add_debug_info_for_null_check(null_check_offset, op->info()); } // done } else if (op->code() == lir_unlock) { assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); - __ unlock_object(hdr, obj, lock, *op->stub()->entry()); + __ unlock_object(hdr, obj, lock, temp, *op->stub()->entry()); } else { Unimplemented(); } @@ -2722,7 +2724,10 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { __ verify_oop(obj); if (tmp != obj) { + assert_different_registers(obj, tmp, rscratch1, rscratch2, mdo_addr.base(), mdo_addr.index()); __ mov(tmp, obj); + } else { + assert_different_registers(obj, rscratch1, rscratch2, mdo_addr.base(), mdo_addr.index()); } if (do_null) { __ cbnz(tmp, update); @@ -2779,10 +2784,11 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { __ cbz(rscratch2, none); __ cmp(rscratch2, (u1)TypeEntries::null_seen); __ br(Assembler::EQ, none); - // There is a chance that the checks above (re-reading profiling - // data from memory) fail if another thread has just set the + // There is a chance that the checks above + // fail if another thread has just set the // profiling to this obj's klass __ dmb(Assembler::ISHLD); + __ eor(tmp, tmp, rscratch2); // get back original value before XOR __ ldr(rscratch2, mdo_addr); __ eor(tmp, tmp, rscratch2); __ andr(rscratch1, tmp, TypeEntries::type_klass_mask); @@ -2807,6 +2813,10 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { __ bind(none); // first time here. Set profile type. __ str(tmp, mdo_addr); +#ifdef ASSERT + __ andr(tmp, tmp, TypeEntries::type_mask); + __ verify_klass_ptr(tmp); +#endif } } else { // There's a single possible klass at this profile point @@ -2838,6 +2848,10 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { #endif // first time here. Set profile type. __ str(tmp, mdo_addr); +#ifdef ASSERT + __ andr(tmp, tmp, TypeEntries::type_mask); + __ verify_klass_ptr(tmp); +#endif } else { assert(ciTypeEntries::valid_ciklass(current_klass) != nullptr && ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent"); diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp index c32f975946375..952e060ed212a 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp @@ -314,6 +314,7 @@ void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { // "lock" stores the address of the monitor stack slot, so this is not an oop LIR_Opr lock = new_register(T_INT); + LIR_Opr scratch = new_register(T_INT); CodeEmitInfo* info_for_exception = nullptr; if (x->needs_null_check()) { @@ -322,7 +323,7 @@ void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { // this CodeEmitInfo must not have the xhandlers because here the // object is already locked (xhandlers expect object to be unlocked) CodeEmitInfo* info = state_for(x, x->state(), true); - monitor_enter(obj.result(), lock, syncTempOpr(), LIR_OprFact::illegalOpr, + monitor_enter(obj.result(), lock, syncTempOpr(), scratch, x->monitor_no(), info_for_exception, info); } @@ -335,8 +336,9 @@ void LIRGenerator::do_MonitorExit(MonitorExit* x) { LIR_Opr lock = new_register(T_INT); LIR_Opr obj_temp = new_register(T_INT); + LIR_Opr scratch = new_register(T_INT); set_no_result(x); - monitor_exit(obj_temp, lock, syncTempOpr(), LIR_OprFact::illegalOpr, x->monitor_no()); + monitor_exit(obj_temp, lock, syncTempOpr(), scratch, x->monitor_no()); } void LIRGenerator::do_NegateOp(NegateOp* x) { diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp index a847289e3ab2f..d3a746178f14e 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp @@ -60,10 +60,10 @@ void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result, } } -int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { +int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { const int aligned_mask = BytesPerWord -1; const int hdr_offset = oopDesc::mark_offset_in_bytes(); - assert_different_registers(hdr, obj, disp_hdr); + assert_different_registers(hdr, obj, disp_hdr, temp, rscratch2); int null_check_offset = -1; verify_oop(obj); @@ -83,7 +83,7 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr // Load object header ldr(hdr, Address(obj, hdr_offset)); if (LockingMode == LM_LIGHTWEIGHT) { - fast_lock(obj, hdr, rscratch1, rscratch2, slow_case); + lightweight_lock(obj, hdr, temp, rscratch2, slow_case); } else if (LockingMode == LM_LEGACY) { Label done; // and mark it as unlocked @@ -125,10 +125,10 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr } -void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { +void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { const int aligned_mask = BytesPerWord -1; const int hdr_offset = oopDesc::mark_offset_in_bytes(); - assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different"); + assert_different_registers(hdr, obj, disp_hdr, temp, rscratch2); Label done; if (LockingMode != LM_LIGHTWEIGHT) { @@ -149,7 +149,7 @@ void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_ // be encoded. tst(hdr, markWord::monitor_value); br(Assembler::NE, slow_case); - fast_unlock(obj, hdr, rscratch1, rscratch2, slow_case); + lightweight_unlock(obj, hdr, temp, rscratch2, slow_case); } else if (LockingMode == LM_LEGACY) { // test if object header is pointing to the displaced header, and if so, restore // the displaced header in the object - if the object header is not pointing to diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp index 98cffb4552406..4aa6206aa6073 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp @@ -58,14 +58,16 @@ using MacroAssembler::null_check; // hdr : must be r0, contents destroyed // obj : must point to the object to lock, contents preserved // disp_hdr: must point to the displaced header location, contents preserved + // temp : temporary register, must not be rscratch1 or rscratch2 // returns code offset at which to add null check debug information - int lock_object (Register swap, Register obj, Register disp_hdr, Label& slow_case); + int lock_object (Register swap, Register obj, Register disp_hdr, Register temp, Label& slow_case); // unlocking // hdr : contents destroyed // obj : must point to the object to lock, contents preserved // disp_hdr: must be r0 & must point to the displaced header location, contents destroyed - void unlock_object(Register swap, Register obj, Register lock, Label& slow_case); + // temp : temporary register, must not be rscratch1 or rscratch2 + void unlock_object(Register swap, Register obj, Register lock, Register temp, Label& slow_case); void initialize_object( Register obj, // result: pointer to object after successful allocation diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp index bdba111f6df8b..4b7d2959a631a 100644 --- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp @@ -478,6 +478,15 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) { const Register exception_pc = r3; const Register handler_addr = r1; + if (AbortVMOnException) { + __ mov(rscratch1, exception_oop); + __ enter(); + save_live_registers(sasm); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, check_abort_on_vm_exception), rscratch1); + restore_live_registers(sasm); + __ leave(); + } + // verify that only r0, is valid at this time __ invalidate_registers(false, true, true, true, true, true); diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index dbe64f8f9ca74..cdf3ec7567ac9 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -45,6 +45,202 @@ typedef void (MacroAssembler::* chr_insn)(Register Rt, const Address &adr); +void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg, Register tmpReg, + Register tmp2Reg, Register tmp3Reg) { + Register oop = objectReg; + Register box = boxReg; + Register disp_hdr = tmpReg; + Register tmp = tmp2Reg; + Label cont; + Label object_has_monitor; + Label count, no_count; + + assert_different_registers(oop, box, tmp, disp_hdr); + + // Load markWord from object into displaced_header. + ldr(disp_hdr, Address(oop, oopDesc::mark_offset_in_bytes())); + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp, oop); + ldrw(tmp, Address(tmp, Klass::access_flags_offset())); + tstw(tmp, JVM_ACC_IS_VALUE_BASED_CLASS); + br(Assembler::NE, cont); + } + + // Check for existing monitor + tbnz(disp_hdr, exact_log2(markWord::monitor_value), object_has_monitor); + + if (LockingMode == LM_MONITOR) { + tst(oop, oop); // Set NE to indicate 'failure' -> take slow-path. We know that oop != 0. + b(cont); + } else if (LockingMode == LM_LEGACY) { + // Set tmp to be (markWord of object | UNLOCK_VALUE). + orr(tmp, disp_hdr, markWord::unlocked_value); + + // Initialize the box. (Must happen before we update the object mark!) + str(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); + + // Compare object markWord with an unlocked value (tmp) and if + // equal exchange the stack address of our box with object markWord. + // On failure disp_hdr contains the possibly locked markWord. + cmpxchg(oop, tmp, box, Assembler::xword, /*acquire*/ true, + /*release*/ true, /*weak*/ false, disp_hdr); + br(Assembler::EQ, cont); + + assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); + + // If the compare-and-exchange succeeded, then we found an unlocked + // object, will have now locked it will continue at label cont + + // Check if the owner is self by comparing the value in the + // markWord of object (disp_hdr) with the stack pointer. + mov(rscratch1, sp); + sub(disp_hdr, disp_hdr, rscratch1); + mov(tmp, (address) (~(os::vm_page_size()-1) | markWord::lock_mask_in_place)); + // If condition is true we are cont and hence we can store 0 as the + // displaced header in the box, which indicates that it is a recursive lock. + ands(tmp/*==0?*/, disp_hdr, tmp); // Sets flags for result + str(tmp/*==0, perhaps*/, Address(box, BasicLock::displaced_header_offset_in_bytes())); + b(cont); + } else { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + lightweight_lock(oop, disp_hdr, tmp, tmp3Reg, no_count); + b(count); + } + + // Handle existing monitor. + bind(object_has_monitor); + + // The object's monitor m is unlocked iff m->owner == NULL, + // otherwise m->owner may contain a thread or a stack address. + // + // Try to CAS m->owner from NULL to current thread. + add(tmp, disp_hdr, (in_bytes(ObjectMonitor::owner_offset())-markWord::monitor_value)); + cmpxchg(tmp, zr, rthread, Assembler::xword, /*acquire*/ true, + /*release*/ true, /*weak*/ false, rscratch1); // Sets flags for result + + if (LockingMode != LM_LIGHTWEIGHT) { + // Store a non-null value into the box to avoid looking like a re-entrant + // lock. The fast-path monitor unlock code checks for + // markWord::monitor_value so use markWord::unused_mark which has the + // relevant bit set, and also matches ObjectSynchronizer::enter. + mov(tmp, (address)markWord::unused_mark().value()); + str(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); + } + br(Assembler::EQ, cont); // CAS success means locking succeeded + + cmp(rscratch1, rthread); + br(Assembler::NE, cont); // Check for recursive locking + + // Recursive lock case + increment(Address(disp_hdr, in_bytes(ObjectMonitor::recursions_offset()) - markWord::monitor_value), 1); + // flag == EQ still from the cmp above, checking if this is a reentrant lock + + bind(cont); + // flag == EQ indicates success + // flag == NE indicates failure + br(Assembler::NE, no_count); + + bind(count); + increment(Address(rthread, JavaThread::held_monitor_count_offset())); + + bind(no_count); +} + +void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, Register tmpReg, + Register tmp2Reg) { + Register oop = objectReg; + Register box = boxReg; + Register disp_hdr = tmpReg; + Register tmp = tmp2Reg; + Label cont; + Label object_has_monitor; + Label count, no_count; + + assert_different_registers(oop, box, tmp, disp_hdr); + + if (LockingMode == LM_LEGACY) { + // Find the lock address and load the displaced header from the stack. + ldr(disp_hdr, Address(box, BasicLock::displaced_header_offset_in_bytes())); + + // If the displaced header is 0, we have a recursive unlock. + cmp(disp_hdr, zr); + br(Assembler::EQ, cont); + } + + // Handle existing monitor. + ldr(tmp, Address(oop, oopDesc::mark_offset_in_bytes())); + tbnz(tmp, exact_log2(markWord::monitor_value), object_has_monitor); + + if (LockingMode == LM_MONITOR) { + tst(oop, oop); // Set NE to indicate 'failure' -> take slow-path. We know that oop != 0. + b(cont); + } else if (LockingMode == LM_LEGACY) { + // Check if it is still a light weight lock, this is is true if we + // see the stack address of the basicLock in the markWord of the + // object. + + cmpxchg(oop, box, disp_hdr, Assembler::xword, /*acquire*/ false, + /*release*/ true, /*weak*/ false, tmp); + b(cont); + } else { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + lightweight_unlock(oop, tmp, box, disp_hdr, no_count); + b(count); + } + + assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); + + // Handle existing monitor. + bind(object_has_monitor); + STATIC_ASSERT(markWord::monitor_value <= INT_MAX); + add(tmp, tmp, -(int)markWord::monitor_value); // monitor + + if (LockingMode == LM_LIGHTWEIGHT) { + // If the owner is anonymous, we need to fix it -- in an outline stub. + Register tmp2 = disp_hdr; + ldr(tmp2, Address(tmp, ObjectMonitor::owner_offset())); + // We cannot use tbnz here, the target might be too far away and cannot + // be encoded. + tst(tmp2, (uint64_t)ObjectMonitor::ANONYMOUS_OWNER); + C2HandleAnonOMOwnerStub* stub = new (Compile::current()->comp_arena()) C2HandleAnonOMOwnerStub(tmp, tmp2); + Compile::current()->output()->add_stub(stub); + br(Assembler::NE, stub->entry()); + bind(stub->continuation()); + } + + ldr(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset())); + + Label notRecursive; + cbz(disp_hdr, notRecursive); + + // Recursive lock + sub(disp_hdr, disp_hdr, 1u); + str(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset())); + cmp(disp_hdr, disp_hdr); // Sets flags for result + b(cont); + + bind(notRecursive); + ldr(rscratch1, Address(tmp, ObjectMonitor::EntryList_offset())); + ldr(disp_hdr, Address(tmp, ObjectMonitor::cxq_offset())); + orr(rscratch1, rscratch1, disp_hdr); // Will be 0 if both are 0. + cmp(rscratch1, zr); // Sets flags for result + cbnz(rscratch1, cont); + // need a release store here + lea(tmp, Address(tmp, ObjectMonitor::owner_offset())); + stlr(zr, tmp); // set unowned + + bind(cont); + // flag == EQ indicates success + // flag == NE indicates failure + br(Assembler::NE, no_count); + + bind(count); + decrement(Address(rthread, JavaThread::held_monitor_count_offset())); + + bind(no_count); +} + // Search for str1 in str2 and return index or -1 // Clobbers: rscratch1, rscratch2, rflags. May also clobber v0-v1, when icnt1==-1. void C2_MacroAssembler::string_indexof(Register str2, Register str1, diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp index ccfd60b1a8b25..f342ca3c977b9 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp @@ -35,6 +35,11 @@ enum shift_kind kind = Assembler::LSL, unsigned shift = 0); public: + // Code used by cmpFastLock and cmpFastUnlock mach instructions in .ad file. + // See full description in macroAssembler_aarch64.cpp. + void fast_lock(Register object, Register box, Register tmp, Register tmp2, Register tmp3); + void fast_unlock(Register object, Register box, Register tmp, Register tmp2); + void string_compare(Register str1, Register str2, Register cnt1, Register cnt2, Register result, Register tmp1, Register tmp2, FloatRegister vtmp1, diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index ea76c9d20c158..2357721ed3d4c 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -508,7 +508,7 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { // first the method - Method* m = *interpreter_frame_method_addr(); + Method* m = safe_interpreter_frame_method(); // validate the method we'd find in this potential sender if (!Method::is_valid_method(m)) return false; diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.hpp index 3d1f588359fa8..e58d66d5cf50e 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.hpp @@ -165,7 +165,7 @@ frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc); - frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb); + frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, bool allow_cb_null = false); // used for fast frame construction by continuations frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, const ImmutableOopMap* oop_map, bool on_heap); diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp index b969e180e4ab9..39dc16d2748e6 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp @@ -92,7 +92,7 @@ inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) { init(sp, fp, pc); } -inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb) { +inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, bool allow_cb_null) { assert(pauth_ptr_is_raw(pc), "cannot be signed"); intptr_t a = intptr_t(sp); intptr_t b = intptr_t(fp); @@ -103,7 +103,7 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address assert(pc != nullptr, "no pc?"); _cb = cb; _oop_map = nullptr; - assert(_cb != nullptr, "pc: " INTPTR_FORMAT, p2i(pc)); + assert(_cb != nullptr || allow_cb_null, "pc: " INTPTR_FORMAT, p2i(pc)); _on_heap = false; DEBUG_ONLY(_frame_index = -1;) diff --git a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp index 3a9e5db2ef7ae..ebaf18299728d 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp @@ -1290,6 +1290,9 @@ static bool aarch64_test_and_branch_reachable(int branch_offset, int target_offs return test_and_branch_to_trampoline_delta < test_and_branch_delta_limit; } +ZLoadBarrierStubC2Aarch64::ZLoadBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register ref) + : ZLoadBarrierStubC2(node, ref_addr, ref), _test_and_branch_reachable_entry(), _offset(), _deferred_emit(false), _test_and_branch_reachable(false) {} + ZLoadBarrierStubC2Aarch64::ZLoadBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register ref, int offset) : ZLoadBarrierStubC2(node, ref_addr, ref), _test_and_branch_reachable_entry(), _offset(offset), _deferred_emit(false), _test_and_branch_reachable(false) { PhaseOutput* const output = Compile::current()->output(); @@ -1319,6 +1322,12 @@ int ZLoadBarrierStubC2Aarch64::get_stub_size() { return cb.insts_size(); } +ZLoadBarrierStubC2Aarch64* ZLoadBarrierStubC2Aarch64::create(const MachNode* node, Address ref_addr, Register ref) { + ZLoadBarrierStubC2Aarch64* const stub = new (Compile::current()->comp_arena()) ZLoadBarrierStubC2Aarch64(node, ref_addr, ref); + register_stub(stub); + return stub; +} + ZLoadBarrierStubC2Aarch64* ZLoadBarrierStubC2Aarch64::create(const MachNode* node, Address ref_addr, Register ref, int offset) { ZLoadBarrierStubC2Aarch64* const stub = new (Compile::current()->comp_arena()) ZLoadBarrierStubC2Aarch64(node, ref_addr, ref, offset); register_stub(stub); diff --git a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp index 00714e5c0c04b..82334b34adeca 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp @@ -265,10 +265,12 @@ class ZLoadBarrierStubC2Aarch64 : public ZLoadBarrierStubC2 { bool _deferred_emit; bool _test_and_branch_reachable; + ZLoadBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register ref); ZLoadBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register ref, int offset); int get_stub_size(); public: + static ZLoadBarrierStubC2Aarch64* create(const MachNode* node, Address ref_addr, Register ref); static ZLoadBarrierStubC2Aarch64* create(const MachNode* node, Address ref_addr, Register ref, int offset); virtual void emit_code(MacroAssembler& masm); diff --git a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad index 8c698635ad0f5..23564a3f23c38 100644 --- a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad +++ b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad @@ -48,7 +48,7 @@ static void z_keep_alive_load_barrier(MacroAssembler& _masm, const MachNode* nod __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatMarkBadBeforeMov); __ movzw(tmp, barrier_Relocation::unpatched); __ tst(ref, tmp); - ZLoadBarrierStubC2* const stub = ZLoadBarrierStubC2::create(node, ref_addr, ref); + ZLoadBarrierStubC2Aarch64* const stub = ZLoadBarrierStubC2Aarch64::create(node, ref_addr, ref); __ br(Assembler::NE, *stub->entry()); z_uncolor(_masm, node, ref); __ bind(*stub->continuation()); diff --git a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp index 94f26b6d062c6..1146324e19cb7 100644 --- a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp @@ -41,6 +41,8 @@ const bool CCallingConventionRequiresIntsAsLongs = false; // and Operational Models for ARMv8" #define CPU_MULTI_COPY_ATOMIC +#define DEFAULT_CACHE_LINE_SIZE 64 + // According to the ARMv8 ARM, "Concurrent modification and execution // of instructions can lead to the resulting instruction performing // any behavior that can be achieved by executing any sequence of diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp index bda7e4c1438b6..9e69c913a7b59 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp @@ -622,7 +622,7 @@ void InterpreterMacroAssembler::remove_activation( // Check that all monitors are unlocked { Label loop, exception, entry, restart; - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); const Address monitor_block_top( rfp, frame::interpreter_frame_monitor_block_top_offset * wordSize); const Address monitor_block_bot( @@ -692,6 +692,12 @@ void InterpreterMacroAssembler::remove_activation( // testing if reserved zone needs to be re-enabled Label no_reserved_zone_enabling; + // check if already enabled - if so no re-enabling needed + assert(sizeof(StackOverflow::StackGuardState) == 4, "unexpected size"); + ldrw(rscratch1, Address(rthread, JavaThread::stack_guard_state_offset())); + cmpw(rscratch1, (u1)StackOverflow::stack_guard_enabled); + br(Assembler::EQ, no_reserved_zone_enabling); + // look for an overflow into the stack reserved zone, i.e. // interpreter_frame_sender_sp <= JavaThread::reserved_stack_activation ldr(rscratch1, Address(rthread, JavaThread::reserved_stack_activation_offset())); @@ -725,7 +731,7 @@ void InterpreterMacroAssembler::remove_activation( // // Kills: // r0 -// c_rarg0, c_rarg1, c_rarg2, c_rarg3, .. (param regs) +// c_rarg0, c_rarg1, c_rarg2, c_rarg3, c_rarg4, .. (param regs) // rscratch1, rscratch2 (scratch regs) void InterpreterMacroAssembler::lock_object(Register lock_reg) { @@ -740,6 +746,8 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) const Register swap_reg = r0; const Register tmp = c_rarg2; const Register obj_reg = c_rarg3; // Will contain the oop + const Register tmp2 = c_rarg4; + const Register tmp3 = c_rarg5; const int obj_offset = in_bytes(BasicObjectLock::obj_offset()); const int lock_offset = in_bytes(BasicObjectLock::lock_offset()); @@ -760,7 +768,7 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) if (LockingMode == LM_LIGHTWEIGHT) { ldr(tmp, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - fast_lock(obj_reg, tmp, rscratch1, rscratch2, slow_case); + lightweight_lock(obj_reg, tmp, tmp2, tmp3, slow_case); b(count); } else if (LockingMode == LM_LEGACY) { // Load (object->mark() | 1) into swap_reg @@ -858,6 +866,7 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) const Register swap_reg = r0; const Register header_reg = c_rarg2; // Will contain the old oopMark const Register obj_reg = c_rarg3; // Will contain the oop + const Register tmp_reg = c_rarg4; // Temporary used by lightweight_unlock save_bcp(); // Save in case of exception @@ -891,7 +900,7 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) ldr(header_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); tbnz(header_reg, exact_log2(markWord::monitor_value), slow_case); - fast_unlock(obj_reg, header_reg, swap_reg, rscratch1, slow_case); + lightweight_unlock(obj_reg, header_reg, swap_reg, tmp_reg, slow_case); b(count); bind(slow_case); } else if (LockingMode == LM_LEGACY) { @@ -1660,7 +1669,7 @@ void InterpreterMacroAssembler::call_VM_base(Register oop_result, } void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { - assert_different_registers(obj, rscratch1); + assert_different_registers(obj, rscratch1, mdo_addr.base(), mdo_addr.index()); Label update, next, none; verify_oop(obj); @@ -1682,13 +1691,13 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& md tbnz(obj, exact_log2(TypeEntries::type_unknown), next); // already unknown. Nothing to do anymore. - ldr(rscratch1, mdo_addr); cbz(rscratch1, none); cmp(rscratch1, (u1)TypeEntries::null_seen); br(Assembler::EQ, none); - // There is a chance that the checks above (re-reading profiling - // data from memory) fail if another thread has just set the + // There is a chance that the checks above + // fail if another thread has just set the // profiling to this obj's klass + eor(obj, obj, rscratch1); // get back original value before XOR ldr(rscratch1, mdo_addr); eor(obj, obj, rscratch1); tst(obj, TypeEntries::type_klass_mask); @@ -1701,6 +1710,10 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& md bind(none); // first time here. Set profile type. str(obj, mdo_addr); +#ifdef ASSERT + andr(obj, obj, TypeEntries::type_mask); + verify_klass_ptr(obj); +#endif bind(next); } diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 3be34786f19c3..5a90cf189ce3d 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -2737,6 +2737,10 @@ void MacroAssembler::cmpxchg(Register addr, Register expected, mov(result, expected); lse_cas(result, new_val, addr, size, acquire, release, /*not_pair*/ true); compare_eq(result, expected, size); +#ifdef ASSERT + // Poison rscratch1 which is written on !UseLSE branch + mov(rscratch1, 0x1f1f1f1f1f1f1f1f); +#endif } else { Label retry_load, done; prfm(Address(addr), PSTL1STRM); @@ -4152,108 +4156,117 @@ void MacroAssembler::kernel_crc32_common_fold_using_crypto_pmull(Register crc, R } add(table, table, table_offset); + // Registers v0..v7 are used as data registers. + // Registers v16..v31 are used as tmp registers. sub(buf, buf, 0x10); - ldrq(v1, Address(buf, 0x10)); - ldrq(v2, Address(buf, 0x20)); - ldrq(v3, Address(buf, 0x30)); - ldrq(v4, Address(buf, 0x40)); - ldrq(v5, Address(buf, 0x50)); - ldrq(v6, Address(buf, 0x60)); - ldrq(v7, Address(buf, 0x70)); - ldrq(v8, Address(pre(buf, 0x80))); - - movi(v25, T4S, 0); - mov(v25, S, 0, crc); - eor(v1, T16B, v1, v25); - - ldrq(v0, Address(table)); + ldrq(v0, Address(buf, 0x10)); + ldrq(v1, Address(buf, 0x20)); + ldrq(v2, Address(buf, 0x30)); + ldrq(v3, Address(buf, 0x40)); + ldrq(v4, Address(buf, 0x50)); + ldrq(v5, Address(buf, 0x60)); + ldrq(v6, Address(buf, 0x70)); + ldrq(v7, Address(pre(buf, 0x80))); + + movi(v31, T4S, 0); + mov(v31, S, 0, crc); + eor(v0, T16B, v0, v31); + + // Register v16 contains constants from the crc table. + ldrq(v16, Address(table)); b(CRC_by128_loop); align(OptoLoopAlignment); BIND(CRC_by128_loop); - pmull (v9, T1Q, v1, v0, T1D); - pmull2(v10, T1Q, v1, v0, T2D); - ldrq(v1, Address(buf, 0x10)); - eor3(v1, T16B, v9, v10, v1); - - pmull (v11, T1Q, v2, v0, T1D); - pmull2(v12, T1Q, v2, v0, T2D); - ldrq(v2, Address(buf, 0x20)); - eor3(v2, T16B, v11, v12, v2); - - pmull (v13, T1Q, v3, v0, T1D); - pmull2(v14, T1Q, v3, v0, T2D); - ldrq(v3, Address(buf, 0x30)); - eor3(v3, T16B, v13, v14, v3); - - pmull (v15, T1Q, v4, v0, T1D); - pmull2(v16, T1Q, v4, v0, T2D); - ldrq(v4, Address(buf, 0x40)); - eor3(v4, T16B, v15, v16, v4); - - pmull (v17, T1Q, v5, v0, T1D); - pmull2(v18, T1Q, v5, v0, T2D); - ldrq(v5, Address(buf, 0x50)); - eor3(v5, T16B, v17, v18, v5); - - pmull (v19, T1Q, v6, v0, T1D); - pmull2(v20, T1Q, v6, v0, T2D); - ldrq(v6, Address(buf, 0x60)); - eor3(v6, T16B, v19, v20, v6); - - pmull (v21, T1Q, v7, v0, T1D); - pmull2(v22, T1Q, v7, v0, T2D); - ldrq(v7, Address(buf, 0x70)); - eor3(v7, T16B, v21, v22, v7); - - pmull (v23, T1Q, v8, v0, T1D); - pmull2(v24, T1Q, v8, v0, T2D); - ldrq(v8, Address(pre(buf, 0x80))); - eor3(v8, T16B, v23, v24, v8); + pmull (v17, T1Q, v0, v16, T1D); + pmull2(v18, T1Q, v0, v16, T2D); + ldrq(v0, Address(buf, 0x10)); + eor3(v0, T16B, v17, v18, v0); + + pmull (v19, T1Q, v1, v16, T1D); + pmull2(v20, T1Q, v1, v16, T2D); + ldrq(v1, Address(buf, 0x20)); + eor3(v1, T16B, v19, v20, v1); + + pmull (v21, T1Q, v2, v16, T1D); + pmull2(v22, T1Q, v2, v16, T2D); + ldrq(v2, Address(buf, 0x30)); + eor3(v2, T16B, v21, v22, v2); + + pmull (v23, T1Q, v3, v16, T1D); + pmull2(v24, T1Q, v3, v16, T2D); + ldrq(v3, Address(buf, 0x40)); + eor3(v3, T16B, v23, v24, v3); + + pmull (v25, T1Q, v4, v16, T1D); + pmull2(v26, T1Q, v4, v16, T2D); + ldrq(v4, Address(buf, 0x50)); + eor3(v4, T16B, v25, v26, v4); + + pmull (v27, T1Q, v5, v16, T1D); + pmull2(v28, T1Q, v5, v16, T2D); + ldrq(v5, Address(buf, 0x60)); + eor3(v5, T16B, v27, v28, v5); + + pmull (v29, T1Q, v6, v16, T1D); + pmull2(v30, T1Q, v6, v16, T2D); + ldrq(v6, Address(buf, 0x70)); + eor3(v6, T16B, v29, v30, v6); + + // Reuse registers v23, v24. + // Using them won't block the first instruction of the next iteration. + pmull (v23, T1Q, v7, v16, T1D); + pmull2(v24, T1Q, v7, v16, T2D); + ldrq(v7, Address(pre(buf, 0x80))); + eor3(v7, T16B, v23, v24, v7); subs(len, len, 0x80); br(Assembler::GE, CRC_by128_loop); // fold into 512 bits - ldrq(v0, Address(table, 0x10)); + // Use v31 for constants because v16 can be still in use. + ldrq(v31, Address(table, 0x10)); - pmull (v10, T1Q, v1, v0, T1D); - pmull2(v11, T1Q, v1, v0, T2D); - eor3(v1, T16B, v10, v11, v5); + pmull (v17, T1Q, v0, v31, T1D); + pmull2(v18, T1Q, v0, v31, T2D); + eor3(v0, T16B, v17, v18, v4); - pmull (v12, T1Q, v2, v0, T1D); - pmull2(v13, T1Q, v2, v0, T2D); - eor3(v2, T16B, v12, v13, v6); + pmull (v19, T1Q, v1, v31, T1D); + pmull2(v20, T1Q, v1, v31, T2D); + eor3(v1, T16B, v19, v20, v5); - pmull (v14, T1Q, v3, v0, T1D); - pmull2(v15, T1Q, v3, v0, T2D); - eor3(v3, T16B, v14, v15, v7); + pmull (v21, T1Q, v2, v31, T1D); + pmull2(v22, T1Q, v2, v31, T2D); + eor3(v2, T16B, v21, v22, v6); - pmull (v16, T1Q, v4, v0, T1D); - pmull2(v17, T1Q, v4, v0, T2D); - eor3(v4, T16B, v16, v17, v8); + pmull (v23, T1Q, v3, v31, T1D); + pmull2(v24, T1Q, v3, v31, T2D); + eor3(v3, T16B, v23, v24, v7); // fold into 128 bits - ldrq(v5, Address(table, 0x20)); - pmull (v10, T1Q, v1, v5, T1D); - pmull2(v11, T1Q, v1, v5, T2D); - eor3(v4, T16B, v4, v10, v11); - - ldrq(v6, Address(table, 0x30)); - pmull (v12, T1Q, v2, v6, T1D); - pmull2(v13, T1Q, v2, v6, T2D); - eor3(v4, T16B, v4, v12, v13); - - ldrq(v7, Address(table, 0x40)); - pmull (v14, T1Q, v3, v7, T1D); - pmull2(v15, T1Q, v3, v7, T2D); - eor3(v1, T16B, v4, v14, v15); + // Use v17 for constants because v31 can be still in use. + ldrq(v17, Address(table, 0x20)); + pmull (v25, T1Q, v0, v17, T1D); + pmull2(v26, T1Q, v0, v17, T2D); + eor3(v3, T16B, v3, v25, v26); + + // Use v18 for constants because v17 can be still in use. + ldrq(v18, Address(table, 0x30)); + pmull (v27, T1Q, v1, v18, T1D); + pmull2(v28, T1Q, v1, v18, T2D); + eor3(v3, T16B, v3, v27, v28); + + // Use v19 for constants because v18 can be still in use. + ldrq(v19, Address(table, 0x40)); + pmull (v29, T1Q, v2, v19, T1D); + pmull2(v30, T1Q, v2, v19, T2D); + eor3(v0, T16B, v3, v29, v30); add(len, len, 0x80); add(buf, buf, 0x10); - mov(tmp0, v1, D, 0); - mov(tmp1, v1, D, 1); + mov(tmp0, v0, D, 0); + mov(tmp1, v0, D, 1); } SkipIfEqual::SkipIfEqual( @@ -6212,16 +6225,16 @@ void MacroAssembler::double_move(VMRegPair src, VMRegPair dst, Register tmp) { } } -// Implements fast-locking. +// Implements lightweight-locking. // Branches to slow upon failure to lock the object, with ZF cleared. // Falls through upon success with ZF set. // // - obj: the object to be locked // - hdr: the header, already loaded from obj, will be destroyed // - t1, t2: temporary registers, will be destroyed -void MacroAssembler::fast_lock(Register obj, Register hdr, Register t1, Register t2, Label& slow) { +void MacroAssembler::lightweight_lock(Register obj, Register hdr, Register t1, Register t2, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); - assert_different_registers(obj, hdr, t1, t2); + assert_different_registers(obj, hdr, t1, t2, rscratch1); // Check if we would have space on lock-stack for the object. ldrw(t1, Address(rthread, JavaThread::lock_stack_top_offset())); @@ -6233,6 +6246,7 @@ void MacroAssembler::fast_lock(Register obj, Register hdr, Register t1, Register // Clear lock-bits, into t2 eor(t2, hdr, markWord::unlocked_value); // Try to swing header from unlocked to locked + // Clobbers rscratch1 when UseLSE is false cmpxchg(/*addr*/ obj, /*expected*/ hdr, /*new*/ t2, Assembler::xword, /*acquire*/ true, /*release*/ true, /*weak*/ false, t1); br(Assembler::NE, slow); @@ -6244,16 +6258,16 @@ void MacroAssembler::fast_lock(Register obj, Register hdr, Register t1, Register strw(t1, Address(rthread, JavaThread::lock_stack_top_offset())); } -// Implements fast-unlocking. +// Implements lightweight-unlocking. // Branches to slow upon failure, with ZF cleared. // Falls through upon success, with ZF set. // // - obj: the object to be unlocked // - hdr: the (pre-loaded) header of the object // - t1, t2: temporary registers -void MacroAssembler::fast_unlock(Register obj, Register hdr, Register t1, Register t2, Label& slow) { +void MacroAssembler::lightweight_unlock(Register obj, Register hdr, Register t1, Register t2, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); - assert_different_registers(obj, hdr, t1, t2); + assert_different_registers(obj, hdr, t1, t2, rscratch1); #ifdef ASSERT { @@ -6293,6 +6307,7 @@ void MacroAssembler::fast_unlock(Register obj, Register hdr, Register t1, Regist orr(t1, hdr, markWord::unlocked_value); // Try to swing header from locked to unlocked + // Clobbers rscratch1 when UseLSE is false cmpxchg(obj, hdr, t1, Assembler::xword, /*acquire*/ true, /*release*/ true, /*weak*/ false, t2); br(Assembler::NE, slow); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 6b45be8ce43ad..81146c5449979 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1582,8 +1582,8 @@ class MacroAssembler: public Assembler { // Code for java.lang.Thread::onSpinWait() intrinsic. void spin_wait(); - void fast_lock(Register obj, Register hdr, Register t1, Register t2, Label& slow); - void fast_unlock(Register obj, Register hdr, Register t1, Register t2, Label& slow); + void lightweight_lock(Register obj, Register hdr, Register t1, Register t2, Label& slow); + void lightweight_unlock(Register obj, Register hdr, Register t1, Register t2, Label& slow); private: // Check the current thread doesn't need a cross modify fence. diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 47dbe0cd97a24..2335a70c9feeb 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1759,6 +1759,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, const Register obj_reg = r19; // Will contain the oop const Register lock_reg = r13; // Address of compiler lock object (BasicLock) const Register old_hdr = r13; // value of old header at unlock time + const Register lock_tmp = r14; // Temporary used by lightweight_lock/unlock const Register tmp = lr; Label slow_path_lock; @@ -1812,7 +1813,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); __ ldr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ fast_lock(obj_reg, swap_reg, tmp, rscratch1, slow_path_lock); + __ lightweight_lock(obj_reg, swap_reg, tmp, lock_tmp, slow_path_lock); } __ bind(count); __ increment(Address(rthread, JavaThread::held_monitor_count_offset())); @@ -1953,7 +1954,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, assert(LockingMode == LM_LIGHTWEIGHT, ""); __ ldr(old_hdr, Address(obj_reg, oopDesc::mark_offset_in_bytes())); __ tbnz(old_hdr, exact_log2(markWord::monitor_value), slow_path_unlock); - __ fast_unlock(obj_reg, old_hdr, swap_reg, rscratch1, slow_path_unlock); + __ lightweight_unlock(obj_reg, old_hdr, swap_reg, lock_tmp, slow_path_unlock); __ decrement(Address(rthread, JavaThread::held_monitor_count_offset())); } diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index 5384af5f215c8..469edaef233ce 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -688,7 +688,7 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { // monitor entry size: see picture of stack set // (generate_method_entry) and frame_amd64.hpp - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); // total overhead size: entry_size + (saved rbp through expr stack // bottom). be sure to change this if you add/subtract anything @@ -769,7 +769,7 @@ void TemplateInterpreterGenerator::lock_method() { const Address monitor_block_top( rfp, frame::interpreter_frame_monitor_block_top_offset * wordSize); - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); #ifdef ASSERT { diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp index 46c649d77b910..5d3585a5e5a43 100644 --- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp @@ -3813,7 +3813,7 @@ void TemplateTable::monitorenter() rfp, frame::interpreter_frame_monitor_block_top_offset * wordSize); const Address monitor_block_bot( rfp, frame::interpreter_frame_initial_sp_offset * wordSize); - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); Label allocated; @@ -3916,7 +3916,7 @@ void TemplateTable::monitorexit() rfp, frame::interpreter_frame_monitor_block_top_offset * wordSize); const Address monitor_block_bot( rfp, frame::interpreter_frame_initial_sp_offset * wordSize); - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); Label found; diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp index cbe9057f6a22c..c09e54e0e57ad 100644 --- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp @@ -219,7 +219,7 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr Register t2 = hdr; // blow Register t3 = Rtemp; // blow - fast_lock_2(obj /* obj */, t1, t2, t3, 1 /* savemask - save t1 */, slow_case); + lightweight_lock(obj /* obj */, t1, t2, t3, 1 /* savemask - save t1 */, slow_case); // Success: fall through } else if (LockingMode == LM_LEGACY) { @@ -282,8 +282,8 @@ void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_ Register t2 = hdr; // blow Register t3 = Rtemp; // blow - fast_unlock_2(obj /* object */, t1, t2, t3, 1 /* savemask (save t1) */, - slow_case); + lightweight_unlock(obj /* object */, t1, t2, t3, 1 /* savemask (save t1) */, + slow_case); // Success: Fall through } else if (LockingMode == LM_LEGACY) { diff --git a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp index 537bf98c3e443..62faa6170833b 100644 --- a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp +++ b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp @@ -350,6 +350,13 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) { void Runtime1::generate_unwind_exception(StubAssembler* sasm) { + + if (AbortVMOnException) { + save_live_registers(sasm); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, check_abort_on_vm_exception), Rexception_obj); + restore_live_registers(sasm); + } + // FP no longer used to find the frame start // on entry, remove_frame() has already been called (restoring FP and LR) diff --git a/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp index f887f5d889cc8..1db30ce5c685d 100644 --- a/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp @@ -93,8 +93,8 @@ void C2_MacroAssembler::fast_lock(Register Roop, Register Rbox, Register Rscratc if (LockingMode == LM_LIGHTWEIGHT) { - fast_lock_2(Roop /* obj */, Rbox /* t1 */, Rscratch /* t2 */, Rscratch2 /* t3 */, - 1 /* savemask (save t1) */, done); + lightweight_lock(Roop /* obj */, Rbox /* t1 */, Rscratch /* t2 */, Rscratch2 /* t3 */, + 1 /* savemask (save t1) */, done); // Success: set Z cmp(Roop, Roop); @@ -143,8 +143,8 @@ void C2_MacroAssembler::fast_unlock(Register Roop, Register Rbox, Register Rscra if (LockingMode == LM_LIGHTWEIGHT) { - fast_unlock_2(Roop /* obj */, Rbox /* t1 */, Rscratch /* t2 */, Rscratch2 /* t3 */, - 1 /* savemask (save t1) */, done); + lightweight_unlock(Roop /* obj */, Rbox /* t1 */, Rscratch /* t2 */, Rscratch2 /* t3 */, + 1 /* savemask (save t1) */, done); cmp(Roop, Roop); // Success: Set Z // Fall through diff --git a/src/hotspot/cpu/arm/frame_arm.cpp b/src/hotspot/cpu/arm/frame_arm.cpp index de2df56f59df2..d923e1f43ad43 100644 --- a/src/hotspot/cpu/arm/frame_arm.cpp +++ b/src/hotspot/cpu/arm/frame_arm.cpp @@ -279,7 +279,6 @@ BasicObjectLock* frame::interpreter_frame_monitor_begin() const { return (BasicObjectLock*) addr_at(interpreter_frame_monitor_block_bottom_offset); } -// Pointer beyond the "oldest/deepest" BasicObjectLock on stack. BasicObjectLock* frame::interpreter_frame_monitor_end() const { BasicObjectLock* result = (BasicObjectLock*) *addr_at(interpreter_frame_monitor_block_top_offset); // make sure the pointer points inside the frame @@ -421,7 +420,7 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { // first the method - Method* m = *interpreter_frame_method_addr(); + Method* m = safe_interpreter_frame_method(); // validate the method we'd find in this potential sender if (!Method::is_valid_method(m)) return false; diff --git a/src/hotspot/cpu/arm/globalDefinitions_arm.hpp b/src/hotspot/cpu/arm/globalDefinitions_arm.hpp index 0a400d0086477..ba180fb0f8718 100644 --- a/src/hotspot/cpu/arm/globalDefinitions_arm.hpp +++ b/src/hotspot/cpu/arm/globalDefinitions_arm.hpp @@ -48,6 +48,8 @@ const bool HaveVFP = true; // arm32 is not specified as multi-copy-atomic // So we must not #define CPU_MULTI_COPY_ATOMIC +#define DEFAULT_CACHE_LINE_SIZE 64 + #define STUBROUTINES_MD_HPP "stubRoutines_arm.hpp" #define INTERP_MASM_MD_HPP "interp_masm_arm.hpp" #define TEMPLATETABLE_MD_HPP "templateTable_arm.hpp" diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp index 2dc0960cd8291..f49b6ed06ecec 100644 --- a/src/hotspot/cpu/arm/interp_masm_arm.cpp +++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp @@ -814,7 +814,7 @@ void InterpreterMacroAssembler::remove_activation(TosState state, Register ret_a { Label loop; - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); const Register Rbottom = R3; const Register Rcur_obj = Rtemp; @@ -911,7 +911,7 @@ void InterpreterMacroAssembler::lock_object(Register Rlock) { } if (LockingMode == LM_LIGHTWEIGHT) { - fast_lock_2(Robj, R0 /* t1 */, Rmark /* t2 */, Rtemp /* t3 */, 0 /* savemask */, slow_case); + lightweight_lock(Robj, R0 /* t1 */, Rmark /* t2 */, Rtemp /* t3 */, 0 /* savemask */, slow_case); b(done); } else if (LockingMode == LM_LEGACY) { // On MP platforms the next load could return a 'stale' value if the memory location has been modified by another thread. @@ -1033,8 +1033,8 @@ void InterpreterMacroAssembler::unlock_object(Register Rlock) { cmpoop(Rtemp, Robj); b(slow_case, ne); - fast_unlock_2(Robj /* obj */, Rlock /* t1 */, Rmark /* t2 */, Rtemp /* t3 */, - 1 /* savemask (save t1) */, slow_case); + lightweight_unlock(Robj /* obj */, Rlock /* t1 */, Rmark /* t2 */, Rtemp /* t3 */, + 1 /* savemask (save t1) */, slow_case); b(done); diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.cpp b/src/hotspot/cpu/arm/macroAssembler_arm.cpp index 9a7735a94b8c4..b827e69d02233 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp @@ -1748,14 +1748,14 @@ void MacroAssembler::read_polling_page(Register dest, relocInfo::relocType rtype POISON_REG(mask, 1, R2, poison) \ POISON_REG(mask, 2, R3, poison) -// Attempt to fast-lock an object +// Attempt to lightweight-lock an object // Registers: // - obj: the object to be locked // - t1, t2, t3: temp registers. If corresponding bit in savemask is set, they get saved, otherwise blown. // Result: // - Success: fallthrough // - Error: break to slow, Z cleared. -void MacroAssembler::fast_lock_2(Register obj, Register t1, Register t2, Register t3, unsigned savemask, Label& slow) { +void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, Register t3, unsigned savemask, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); assert_different_registers(obj, t1, t2, t3); @@ -1806,14 +1806,14 @@ void MacroAssembler::fast_lock_2(Register obj, Register t1, Register t2, Registe // Success: fall through } -// Attempt to fast-unlock an object +// Attempt to lightweight-unlock an object // Registers: // - obj: the object to be unlocked // - t1, t2, t3: temp registers. If corresponding bit in savemask is set, they get saved, otherwise blown. // Result: // - Success: fallthrough // - Error: break to slow, Z cleared. -void MacroAssembler::fast_unlock_2(Register obj, Register t1, Register t2, Register t3, unsigned savemask, Label& slow) { +void MacroAssembler::lightweight_unlock(Register obj, Register t1, Register t2, Register t3, unsigned savemask, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); assert_different_registers(obj, t1, t2, t3); diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.hpp b/src/hotspot/cpu/arm/macroAssembler_arm.hpp index 359ad93b91bd2..9a855dee8f668 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.hpp @@ -1009,23 +1009,23 @@ class MacroAssembler: public Assembler { void cas_for_lock_acquire(Register oldval, Register newval, Register base, Register tmp, Label &slow_case, bool allow_fallthrough_on_failure = false, bool one_shot = false); void cas_for_lock_release(Register oldval, Register newval, Register base, Register tmp, Label &slow_case, bool allow_fallthrough_on_failure = false, bool one_shot = false); - // Attempt to fast-lock an object + // Attempt to lightweight-lock an object // Registers: // - obj: the object to be locked // - t1, t2, t3: temp registers. If corresponding bit in savemask is set, they get saved, otherwise blown. // Result: // - Success: fallthrough // - Error: break to slow, Z cleared. - void fast_lock_2(Register obj, Register t1, Register t2, Register t3, unsigned savemask, Label& slow); + void lightweight_lock(Register obj, Register t1, Register t2, Register t3, unsigned savemask, Label& slow); - // Attempt to fast-unlock an object + // Attempt to lightweight-unlock an object // Registers: // - obj: the object to be unlocked // - t1, t2, t3: temp registers. If corresponding bit in savemask is set, they get saved, otherwise blown. // Result: // - Success: fallthrough // - Error: break to slow, Z cleared. - void fast_unlock_2(Register obj, Register t1, Register t2, Register t3, unsigned savemask, Label& slow); + void lightweight_unlock(Register obj, Register t1, Register t2, Register t3, unsigned savemask, Label& slow); #ifndef PRODUCT // Preserves flags and all registers. diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 5916305a9d27c..e4f4107da0fb6 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -1155,8 +1155,8 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, if (LockingMode == LM_LIGHTWEIGHT) { log_trace(fastlock)("SharedRuntime lock fast"); - __ fast_lock_2(sync_obj /* object */, disp_hdr /* t1 */, tmp /* t2 */, Rtemp /* t3 */, - 0x7 /* savemask */, slow_lock); + __ lightweight_lock(sync_obj /* object */, disp_hdr /* t1 */, tmp /* t2 */, Rtemp /* t3 */, + 0x7 /* savemask */, slow_lock); // Fall through to lock_done } else if (LockingMode == LM_LEGACY) { const Register mark = tmp; @@ -1242,8 +1242,8 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, if (method->is_synchronized()) { if (LockingMode == LM_LIGHTWEIGHT) { log_trace(fastlock)("SharedRuntime unlock fast"); - __ fast_unlock_2(sync_obj, R2 /* t1 */, tmp /* t2 */, Rtemp /* t3 */, - 7 /* savemask */, slow_unlock); + __ lightweight_unlock(sync_obj, R2 /* t1 */, tmp /* t2 */, Rtemp /* t3 */, + 7 /* savemask */, slow_unlock); // Fall through } else if (LockingMode == LM_LEGACY) { // See C1_MacroAssembler::unlock_object() for more comments diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp index d1963ebfd6902..848a265263391 100644 --- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp @@ -530,7 +530,7 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { const Register RmaxStack = R2; // monitor entry size - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); // total overhead size: entry_size + (saved registers, thru expr stack bottom). // be sure to change this if you add/subtract anything to/from the overhead area @@ -569,7 +569,7 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { void TemplateInterpreterGenerator::lock_method() { // synchronize method - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); assert ((entry_size % StackAlignmentInBytes) == 0, "should keep stack alignment"); #ifdef ASSERT diff --git a/src/hotspot/cpu/arm/templateTable_arm.cpp b/src/hotspot/cpu/arm/templateTable_arm.cpp index f52875af6e38c..1bb92092e7a1d 100644 --- a/src/hotspot/cpu/arm/templateTable_arm.cpp +++ b/src/hotspot/cpu/arm/templateTable_arm.cpp @@ -4270,7 +4270,7 @@ void TemplateTable::monitorenter() { // check for null object __ null_check(Robj, Rtemp); - const int entry_size = (frame::interpreter_frame_monitor_size() * wordSize); + const int entry_size = (frame::interpreter_frame_monitor_size_in_bytes()); assert (entry_size % StackAlignmentInBytes == 0, "keep stack alignment"); Label allocate_monitor, allocated; @@ -4381,7 +4381,7 @@ void TemplateTable::monitorexit() { // check for null object __ null_check(Robj, Rtemp); - const int entry_size = (frame::interpreter_frame_monitor_size() * wordSize); + const int entry_size = (frame::interpreter_frame_monitor_size_in_bytes()); Label found, throw_exception; // find matching slot diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index ce347fe66d974..3f4b8520b9fef 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -2635,6 +2635,13 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { Unimplemented(); } + // There might be a volatile load before this Unsafe CAS. + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ sync(); + } else { + __ lwsync(); + } + if (is_64bit) { __ cmpxchgd(BOOL_RESULT, /*current_value=*/R0, cmp_value, new_value, addr, MacroAssembler::MemBarNone, @@ -2996,9 +3003,24 @@ void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr assert(addr->disp() == 0 && addr->index()->is_illegal(), "use leal!"); const Register Rptr = addr->base()->as_pointer_register(), Rtmp = tmp->as_register(); - Register Rco = noreg; - if (UseCompressedOops && data->is_oop()) { - Rco = __ encode_heap_oop(Rtmp, data->as_register()); + Register Robj = noreg; + if (data->is_oop()) { + if (UseCompressedOops) { + Robj = __ encode_heap_oop(Rtmp, data->as_register()); + } else { + Robj = data->as_register(); + if (Robj == dest->as_register()) { // May happen with ZGC. + __ mr(Rtmp, Robj); + Robj = Rtmp; + } + } + } + + // There might be a volatile load before this Unsafe OP. + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ sync(); + } else { + __ lwsync(); } Label Lretry; @@ -3018,18 +3040,11 @@ void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr } else if (data->is_oop()) { assert(code == lir_xchg, "xadd for oops"); const Register Rold = dest->as_register(); + assert_different_registers(Rptr, Rold, Robj); if (UseCompressedOops) { - assert_different_registers(Rptr, Rold, Rco); __ lwarx(Rold, Rptr, MacroAssembler::cmpxchgx_hint_atomic_update()); - __ stwcx_(Rco, Rptr); + __ stwcx_(Robj, Rptr); } else { - Register Robj = data->as_register(); - assert_different_registers(Rptr, Rold, Rtmp); - assert_different_registers(Rptr, Robj, Rtmp); - if (Robj == Rold) { // May happen with ZGC. - __ mr(Rtmp, Robj); - Robj = Rtmp; - } __ ldarx(Rold, Rptr, MacroAssembler::cmpxchgx_hint_atomic_update()); __ stdcx_(Robj, Rptr); } @@ -3057,6 +3072,12 @@ void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr if (UseCompressedOops && data->is_oop()) { __ decode_heap_oop(dest->as_register()); } + + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + __ sync(); + } } @@ -3141,7 +3162,7 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { // Klass seen before, nothing to do (regardless of unknown bit). //beq(CCR1, do_nothing); - __ andi_(R0, klass, TypeEntries::type_unknown); + __ andi_(R0, tmp, TypeEntries::type_unknown); // Already unknown. Nothing to do anymore. //bne(CCR0, do_nothing); __ crorc(CCR0, Assembler::equal, CCR1, Assembler::equal); // cr0 eq = cr1 eq or cr0 ne diff --git a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp index ecc40d6fde7c1..32aab91c7d374 100644 --- a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp @@ -639,13 +639,6 @@ LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_ cmp_value.load_item(); new_value.load_item(); - // Volatile load may be followed by Unsafe CAS. - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ membar(); - } else { - __ membar_release(); - } - if (is_reference_type(type)) { if (UseCompressedOops) { t1 = new_register(T_OBJECT); @@ -670,21 +663,7 @@ LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) LIR_Opr tmp = FrameMap::R0_opr; value.load_item(); - - // Volatile load may be followed by Unsafe CAS. - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ membar(); - } else { - __ membar_release(); - } - __ xchg(addr, value.result(), result, tmp); - - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ membar_acquire(); - } else { - __ membar(); - } return result; } @@ -694,21 +673,7 @@ LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) { LIR_Opr tmp = FrameMap::R0_opr; value.load_item(); - - // Volatile load may be followed by Unsafe CAS. - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ membar(); // To be safe. Unsafe semantics are unclear. - } else { - __ membar_release(); - } - __ xadd(addr, value.result(), result, tmp); - - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ membar_acquire(); - } else { - __ membar(); - } return result; } diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index bf0122ee737c1..577dcae25f4bc 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -115,7 +115,7 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox } if (LockingMode == LM_LIGHTWEIGHT) { - fast_lock(Roop, Rmark, Rscratch, slow_int); + lightweight_lock(Roop, Rmark, Rscratch, slow_int); } else if (LockingMode == LM_LEGACY) { // ... and mark it unlocked. ori(Rmark, Rmark, markWord::unlocked_value); @@ -181,7 +181,7 @@ void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rb ld(Rmark, oopDesc::mark_offset_in_bytes(), Roop); andi_(R0, Rmark, markWord::monitor_value); bne(CCR0, slow_int); - fast_unlock(Roop, Rmark, slow_int); + lightweight_unlock(Roop, Rmark, slow_int); } else if (LockingMode == LM_LEGACY) { // Check if it is still a light weight lock, this is is true if we see // the stack address of the basicLock in the markWord of the object. diff --git a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp index 348de609901ca..2ba6a6bca4e03 100644 --- a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp @@ -552,6 +552,12 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Rexception_save = R31, Rcaller_sp = R30; __ set_info("unwind_exception", dont_gc_arguments); + if (AbortVMOnException) { + save_live_registers(sasm); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, check_abort_on_vm_exception), Rexception); + restore_live_registers(sasm, noreg, noreg); + } + __ ld(Rcaller_sp, 0, R1_SP); __ push_frame_reg_args(0, R0); // dummy frame for C call __ mr(Rexception_save, Rexception); // save over C call diff --git a/src/hotspot/cpu/ppc/frame_ppc.cpp b/src/hotspot/cpu/ppc/frame_ppc.cpp index 2dcf9975477e8..316db829b58a5 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.cpp +++ b/src/hotspot/cpu/ppc/frame_ppc.cpp @@ -324,7 +324,7 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { // first the method - Method* m = *interpreter_frame_method_addr(); + Method* m = safe_interpreter_frame_method(); // validate the method we'd find in this potential sender if (!Method::is_valid_method(m)) return false; @@ -454,7 +454,6 @@ intptr_t *frame::initial_deoptimization_info() { frame::frame(void* sp, void* fp, void* pc) : frame((intptr_t*)sp, (address)pc) {} #endif -// Pointer beyond the "oldest/deepest" BasicObjectLock on stack. BasicObjectLock* frame::interpreter_frame_monitor_end() const { BasicObjectLock* result = (BasicObjectLock*) at(ijava_idx(monitors)); // make sure the pointer points inside the frame diff --git a/src/hotspot/cpu/ppc/frame_ppc.hpp b/src/hotspot/cpu/ppc/frame_ppc.hpp index a4ec15d5aa075..e2e2b9d015dde 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.hpp +++ b/src/hotspot/cpu/ppc/frame_ppc.hpp @@ -424,9 +424,6 @@ template static void update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr); - // Size of a monitor in bytes. - static int interpreter_frame_monitor_size_in_bytes(); - // The size of a cInterpreter object. static inline int interpreter_frame_cinterpreterstate_size_in_bytes(); diff --git a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp index 478c0a9081aef..c711882189a12 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp @@ -250,10 +250,6 @@ inline int frame::interpreter_frame_monitor_size() { WordsPerLong); // number of stack slots for a Java long } -inline int frame::interpreter_frame_monitor_size_in_bytes() { - return frame::interpreter_frame_monitor_size() * wordSize; -} - // entry frames inline intptr_t* frame::entry_frame_argument_at(int offset) const { 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 fc06e1b71e0b8..6d9a1db1ed4b8 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved. - * Copyright (c) 2012, 2021 SAP SE. All rights reserved. + * Copyright (c) 2018, 2023, Red Hat, Inc. All rights reserved. + * Copyright (c) 2012, 2023 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 @@ -53,8 +53,13 @@ void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler *masm) { __ encode_heap_oop(new_val, new_val); } - // Due to the memory barriers emitted in ShenandoahBarrierSetC1::atomic_cmpxchg_at_resolved, - // there is no need to specify stronger memory semantics. + // There might be a volatile load before this Unsafe CAS. + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ sync(); + } else { + __ lwsync(); + } + ShenandoahBarrierSet::assembler()->cmpxchg_oop(masm->masm(), addr, cmp_val, new_val, tmp1, tmp2, false, result); @@ -63,6 +68,12 @@ void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler *masm) { __ decode_heap_oop(new_val); } + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + __ sync(); + } + __ block_comment("} LIR_OpShenandoahCompareAndSwap (shenandaohgc)"); } @@ -80,14 +91,6 @@ LIR_Opr ShenandoahBarrierSetC1::atomic_cmpxchg_at_resolved(LIRAccess &access, LI if (access.is_oop()) { LIRGenerator* gen = access.gen(); - if (ShenandoahCASBarrier) { - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ membar(); - } else { - __ membar_release(); - } - } - if (ShenandoahSATBBarrier) { pre_barrier(gen, access.access_emit_info(), access.decorators(), access.resolved_addr(), LIR_OprFact::illegalOpr); @@ -104,12 +107,6 @@ LIR_Opr ShenandoahBarrierSetC1::atomic_cmpxchg_at_resolved(LIRAccess &access, LI __ append(new LIR_OpShenandoahCompareAndSwap(addr, cmp_value.result(), new_value.result(), t1, t2, result)); - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ membar_acquire(); - } else { - __ membar(); - } - return result; } } @@ -125,12 +122,6 @@ LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess &access, LIRIt value.load_item(); LIR_Opr value_opr = value.result(); - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ membar(); - } else { - __ membar_release(); - } - if (access.is_oop()) { value_opr = iu_barrier(access.gen(), value_opr, access.access_emit_info(), access.decorators()); } @@ -152,11 +143,5 @@ LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess &access, LIRIt } } - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ membar_acquire(); - } else { - __ membar(); - } - return result; } diff --git a/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp index 1d07c6d573a17..9ed47b688ff26 100644 --- a/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp @@ -340,11 +340,12 @@ void ZBarrierSetAssembler::store_barrier_medium(MacroAssembler* masm, } __ ld(R0, in_bytes(ZThreadLocalData::store_good_mask_offset()), R16_thread); __ cmpxchgd(CCR0, tmp, (intptr_t)0, R0, ref_base, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update()); + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, need_restore ? nullptr : &slow_path); if (need_restore) { __ subf(ref_base, ind_or_offs, ref_base); + __ bne(CCR0, slow_path); } - __ bne(CCR0, slow_path); } else { // A non-atomic relocatable object won't get to the medium fast path due to a // raw null in the young generation. We only get here because the field is bad. diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index 97eb07dec7348..2627ca1ad3446 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -887,6 +887,12 @@ void InterpreterMacroAssembler::remove_activation(TosState state, // Test if reserved zone needs to be enabled. Label no_reserved_zone_enabling; + // check if already enabled - if so no re-enabling needed + assert(sizeof(StackOverflow::StackGuardState) == 4, "unexpected size"); + lwz(R0, in_bytes(JavaThread::stack_guard_state_offset()), R16_thread); + cmpwi(CCR0, R0, StackOverflow::stack_guard_enabled); + beq_predict_taken(CCR0, no_reserved_zone_enabling); + // Compare frame pointers. There is no good stack pointer, as with stack // frame compression we can get different SPs when we do calls. A subsequent // call could have a smaller SP, so that this compare succeeds for an @@ -961,7 +967,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { } if (LockingMode == LM_LIGHTWEIGHT) { - fast_lock(object, /* mark word */ header, tmp, slow_case); + lightweight_lock(object, /* mark word */ header, tmp, slow_case); b(count_locking); } else if (LockingMode == LM_LEGACY) { @@ -1111,7 +1117,7 @@ void InterpreterMacroAssembler::unlock_object(Register monitor) { ld(header, oopDesc::mark_offset_in_bytes(), object); andi_(R0, header, markWord::monitor_value); bne(CCR0, slow_case); - fast_unlock(object, header, slow_case); + lightweight_unlock(object, header, slow_case); } else { addi(object_mark_addr, object, oopDesc::mark_offset_in_bytes()); @@ -1777,7 +1783,7 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, Register mdo_addr // Klass seen before, nothing to do (regardless of unknown bit). //beq(CCR1, do_nothing); - andi_(R0, klass, TypeEntries::type_unknown); + andi_(R0, tmp, TypeEntries::type_unknown); // Already unknown. Nothing to do anymore. //bne(CCR0, do_nothing); crorc(CCR0, Assembler::equal, CCR1, Assembler::equal); // cr0 eq = cr1 eq or cr0 ne @@ -1976,7 +1982,7 @@ void InterpreterMacroAssembler::profile_parameters_type(Register tmp1, Register } } -// Add a InterpMonitorElem to stack (see frame_sparc.hpp). +// Add a monitor (see frame_ppc.hpp). void InterpreterMacroAssembler::add_monitor_to_stack(bool stack_is_empty, Register Rtemp1, Register Rtemp2) { // Very-local scratch registers. diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 027c6fe4ce833..bb8711c6aa68a 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2707,7 +2707,7 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register b(failure); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - fast_lock(oop, displaced_header, temp, failure); + lightweight_lock(oop, displaced_header, temp, failure); b(success); } @@ -2819,7 +2819,7 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe b(success); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - fast_unlock(oop, current_header, failure); + lightweight_unlock(oop, current_header, failure); b(success); } @@ -4491,14 +4491,14 @@ void MacroAssembler::atomically_flip_locked_state(bool is_unlock, Register obj, } } -// Implements fast-locking. +// Implements lightweight-locking. // Branches to slow upon failure to lock the object, with CCR0 NE. // Falls through upon success with CCR0 EQ. // // - obj: the object to be locked // - hdr: the header, already loaded from obj, will be destroyed // - t1: temporary register -void MacroAssembler::fast_lock(Register obj, Register hdr, Register t1, Label& slow) { +void MacroAssembler::lightweight_lock(Register obj, Register hdr, Register t1, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); assert_different_registers(obj, hdr, t1); @@ -4524,13 +4524,13 @@ void MacroAssembler::fast_lock(Register obj, Register hdr, Register t1, Label& s stw(t1, in_bytes(JavaThread::lock_stack_top_offset()), R16_thread); } -// Implements fast-unlocking. +// Implements lightweight-unlocking. // Branches to slow upon failure, with CCR0 NE. // Falls through upon success, with CCR0 EQ. // // - obj: the object to be unlocked // - hdr: the (pre-loaded) header of the object, will be destroyed -void MacroAssembler::fast_unlock(Register obj, Register hdr, Label& slow) { +void MacroAssembler::lightweight_unlock(Register obj, Register hdr, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); assert_different_registers(obj, hdr); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 902edda0039ed..9947644475ec0 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -607,8 +607,8 @@ class MacroAssembler: public Assembler { void inc_held_monitor_count(Register tmp); void dec_held_monitor_count(Register tmp); void atomically_flip_locked_state(bool is_unlock, Register obj, Register tmp, Label& failed, int semantics); - void fast_lock(Register obj, Register hdr, Register t1, Label& slow); - void fast_unlock(Register obj, Register hdr, Label& slow); + void lightweight_lock(Register obj, Register hdr, Register t1, Label& slow); + void lightweight_unlock(Register obj, Register hdr, Label& slow); // allocation (for C1) void tlab_allocate( diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 542856c144416..401d4f4efa840 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -2457,7 +2457,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // -------------------------------------------------------------------------- if (method->is_synchronized()) { - ConditionRegister r_flag = CCR1; Register r_oop = r_temp_4; const Register r_box = r_temp_5; Label done, locked; @@ -2472,8 +2471,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // Try fastpath for locking. // fast_lock kills r_temp_1, r_temp_2, r_temp_3. - __ compiler_fast_lock_object(r_flag, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); - __ beq(r_flag, locked); + __ compiler_fast_lock_object(CCR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); + __ beq(CCR0, locked); // None of the above fast optimizations worked so we have to get into the // slow case of monitor enter. Inline a special case of call_VM that @@ -2666,8 +2665,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // -------------------------------------------------------------------------- if (method->is_synchronized()) { - - ConditionRegister r_flag = CCR1; const Register r_oop = r_temp_4; const Register r_box = r_temp_5; const Register r_exception = r_temp_6; @@ -2684,8 +2681,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ addi(r_box, R1_SP, lock_offset); // Try fastpath for unlocking. - __ compiler_fast_unlock_object(r_flag, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); - __ beq(r_flag, done); + __ compiler_fast_unlock_object(CCR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); + __ beq(CCR0, done); // Save and restore any potential method result value around the unlocking operation. save_native_result(masm, ret_type, workspace_slot_offset); diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp index 006896c9f9b86..2ed731926b6dd 100644 --- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp @@ -4106,79 +4106,67 @@ void TemplateTable::athrow() { // at next monitor exit. void TemplateTable::monitorenter() { transition(atos, vtos); - __ verify_oop(R17_tos); - Register Rcurrent_monitor = R11_scratch1, - Rcurrent_obj = R12_scratch2, + Register Rcurrent_monitor = R3_ARG1, + Rcurrent_obj = R4_ARG2, Robj_to_lock = R17_tos, - Rscratch1 = R3_ARG1, - Rscratch2 = R4_ARG2, - Rscratch3 = R5_ARG3, - Rcurrent_obj_addr = R6_ARG4; + Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2, + Rbot = R5_ARG3, + Rfree_slot = R6_ARG4; + + Label Lfound, Lallocate_new; + + __ ld(Rscratch1, _abi0(callers_sp), R1_SP); // load FP + __ li(Rfree_slot, 0); // Points to free slot or null. + + // Set up search loop - start with topmost monitor. + __ mr(Rcurrent_monitor, R26_monitor); + __ addi(Rbot, Rscratch1, -frame::ijava_state_size); // ------------------------------------------------------------------------------ // Null pointer exception. - __ null_check_throw(Robj_to_lock, -1, R11_scratch1); + __ null_check_throw(Robj_to_lock, -1, Rscratch1); - // Try to acquire a lock on the object. - // Repeat until succeeded (i.e., until monitorenter returns true). + // Check if any slot is present => short cut to allocation if not. + __ cmpld(CCR0, Rcurrent_monitor, Rbot); + __ beq(CCR0, Lallocate_new); // ------------------------------------------------------------------------------ // Find a free slot in the monitor block. - Label Lfound, Lexit, Lallocate_new; - ConditionRegister found_free_slot = CCR0, - found_same_obj = CCR1, - reached_limit = CCR6; + // Note: The order of the monitors is important for C2 OSR which derives the + // unlock order from it (see comments for interpreter_frame_monitor_*). { - Label Lloop; - Register Rlimit = Rcurrent_monitor; - - // Set up search loop - start with topmost monitor. - __ addi(Rcurrent_obj_addr, R26_monitor, in_bytes(BasicObjectLock::obj_offset())); + Label Lloop, LnotFree, Lexit; - __ ld(Rlimit, 0, R1_SP); - __ addi(Rlimit, Rlimit, - (frame::ijava_state_size + frame::interpreter_frame_monitor_size_in_bytes() - in_bytes(BasicObjectLock::obj_offset()))); // Monitor base + __ bind(Lloop); + __ ld(Rcurrent_obj, in_bytes(BasicObjectLock::obj_offset()), Rcurrent_monitor); + // Exit if current entry is for same object; this guarantees, that new monitor + // used for recursive lock is above the older one. + __ cmpd(CCR0, Rcurrent_obj, Robj_to_lock); + __ beq(CCR0, Lexit); // recursive locking - // Check if any slot is present => short cut to allocation if not. - __ cmpld(reached_limit, Rcurrent_obj_addr, Rlimit); - __ bgt(reached_limit, Lallocate_new); + __ cmpdi(CCR0, Rcurrent_obj, 0); + __ bne(CCR0, LnotFree); + __ mr(Rfree_slot, Rcurrent_monitor); // remember free slot closest to the bottom + __ bind(LnotFree); - // Pre-load topmost slot. - __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr); - __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize); - // The search loop. - __ bind(Lloop); - // Found free slot? - __ cmpdi(found_free_slot, Rcurrent_obj, 0); - // Is this entry for same obj? If so, stop the search and take the found - // free slot or allocate a new one to enable recursive locking. - __ cmpd(found_same_obj, Rcurrent_obj, Robj_to_lock); - __ cmpld(reached_limit, Rcurrent_obj_addr, Rlimit); - __ beq(found_free_slot, Lexit); - __ beq(found_same_obj, Lallocate_new); - __ bgt(reached_limit, Lallocate_new); - // Check if last allocated BasicLockObj reached. - __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr); - __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize); - // Next iteration if unchecked BasicObjectLocks exist on the stack. - __ b(Lloop); + __ addi(Rcurrent_monitor, Rcurrent_monitor, frame::interpreter_frame_monitor_size_in_bytes()); + __ cmpld(CCR0, Rcurrent_monitor, Rbot); + __ bne(CCR0, Lloop); + __ bind(Lexit); } // ------------------------------------------------------------------------------ // Check if we found a free slot. - __ bind(Lexit); - - __ addi(Rcurrent_monitor, Rcurrent_obj_addr, -(frame::interpreter_frame_monitor_size() * wordSize) - in_bytes(BasicObjectLock::obj_offset())); - __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, - frame::interpreter_frame_monitor_size() * wordSize); - __ b(Lfound); + __ cmpdi(CCR0, Rfree_slot, 0); + __ bne(CCR0, Lfound); // We didn't find a free BasicObjLock => allocate one. - __ align(32, 12); __ bind(Lallocate_new); __ add_monitor_to_stack(false, Rscratch1, Rscratch2); - __ mr(Rcurrent_monitor, R26_monitor); - __ addi(Rcurrent_obj_addr, R26_monitor, in_bytes(BasicObjectLock::obj_offset())); + __ mr(Rfree_slot, R26_monitor); // ------------------------------------------------------------------------------ // We now have a slot to lock. @@ -4188,8 +4176,8 @@ void TemplateTable::monitorenter() { // The object has already been popped from the stack, so the expression stack looks correct. __ addi(R14_bcp, R14_bcp, 1); - __ std(Robj_to_lock, 0, Rcurrent_obj_addr); - __ lock_object(Rcurrent_monitor, Robj_to_lock); + __ std(Robj_to_lock, in_bytes(BasicObjectLock::obj_offset()), Rfree_slot); + __ lock_object(Rfree_slot, Robj_to_lock); // Check if there's enough space on the stack for the monitors after locking. // This emits a single store. @@ -4203,46 +4191,40 @@ void TemplateTable::monitorexit() { transition(atos, vtos); __ verify_oop(R17_tos); - Register Rcurrent_monitor = R11_scratch1, - Rcurrent_obj = R12_scratch2, + Register Rcurrent_monitor = R3_ARG1, + Rcurrent_obj = R4_ARG2, Robj_to_lock = R17_tos, - Rcurrent_obj_addr = R3_ARG1, - Rlimit = R4_ARG2; + Rscratch = R11_scratch1, + Rbot = R12_scratch2; + Label Lfound, Lillegal_monitor_state; - // Check corner case: unbalanced monitorEnter / Exit. - __ ld(Rlimit, 0, R1_SP); - __ addi(Rlimit, Rlimit, - (frame::ijava_state_size + frame::interpreter_frame_monitor_size_in_bytes())); // Monitor base + __ ld(Rscratch, _abi0(callers_sp), R1_SP); // load FP + + // Set up search loop - start with topmost monitor. + __ mr(Rcurrent_monitor, R26_monitor); + __ addi(Rbot, Rscratch, -frame::ijava_state_size); // Null pointer check. - __ null_check_throw(Robj_to_lock, -1, R11_scratch1); + __ null_check_throw(Robj_to_lock, -1, Rscratch); - __ cmpld(CCR0, R26_monitor, Rlimit); - __ bgt(CCR0, Lillegal_monitor_state); + // Check corner case: unbalanced monitorEnter / Exit. + __ cmpld(CCR0, Rcurrent_monitor, Rbot); + __ beq(CCR0, Lillegal_monitor_state); // Find the corresponding slot in the monitors stack section. { Label Lloop; - // Start with topmost monitor. - __ addi(Rcurrent_obj_addr, R26_monitor, in_bytes(BasicObjectLock::obj_offset())); - __ addi(Rlimit, Rlimit, in_bytes(BasicObjectLock::obj_offset())); - __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr); - __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize); - __ bind(Lloop); + __ ld(Rcurrent_obj, in_bytes(BasicObjectLock::obj_offset()), Rcurrent_monitor); // Is this entry for same obj? __ cmpd(CCR0, Rcurrent_obj, Robj_to_lock); __ beq(CCR0, Lfound); - // Check if last allocated BasicLockObj reached. - - __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr); - __ cmpld(CCR0, Rcurrent_obj_addr, Rlimit); - __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize); - - // Next iteration if unchecked BasicObjectLocks exist on the stack. - __ ble(CCR0, Lloop); + __ addi(Rcurrent_monitor, Rcurrent_monitor, frame::interpreter_frame_monitor_size_in_bytes()); + __ cmpld(CCR0, Rcurrent_monitor, Rbot); + __ bne(CCR0, Lloop); } // Fell through without finding the basic obj lock => throw up! @@ -4252,8 +4234,6 @@ void TemplateTable::monitorexit() { __ align(32, 12); __ bind(Lfound); - __ addi(Rcurrent_monitor, Rcurrent_obj_addr, - -(frame::interpreter_frame_monitor_size() * wordSize) - in_bytes(BasicObjectLock::obj_offset())); __ unlock_object(Rcurrent_monitor); } diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 02fbf5bfbf7d8..0988056f15aeb 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -2787,7 +2787,13 @@ enum Nf { c_slli(Rd, shamt); \ return; \ } \ - _slli(Rd, Rs1, shamt); \ + if (shamt != 0) { \ + _slli(Rd, Rs1, shamt); \ + } else { \ + if (Rd != Rs1) { \ + addi(Rd, Rs1, 0); \ + } \ + } \ } INSN(slli); @@ -2802,7 +2808,13 @@ enum Nf { C_NAME(Rd, shamt); \ return; \ } \ - NORMAL_NAME(Rd, Rs1, shamt); \ + if (shamt != 0) { \ + NORMAL_NAME(Rd, Rs1, shamt); \ + } else { \ + if (Rd != Rs1) { \ + addi(Rd, Rs1, 0); \ + } \ + } \ } INSN(srai, c_srai, _srai); @@ -2902,6 +2914,17 @@ enum Nf { return uabs(target - branch) < branch_range; } + // Decode the given instruction, checking if it's a 16-bit compressed + // instruction and return the address of the next instruction. + static address locate_next_instruction(address inst) { + // Instruction wider than 16 bits has the two least-significant bits set. + if ((0x3 & *inst) == 0x3) { + return inst + instruction_size; + } else { + return inst + compressed_instruction_size; + } + } + Assembler(CodeBuffer* code) : AbstractAssembler(code), _in_compressible_region(true) {} }; diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 99c683c2f4d1d..8e52a6775254e 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -363,7 +363,7 @@ int LIR_Assembler::emit_unwind_handler() { if (LockingMode == LM_MONITOR) { __ j(*stub->entry()); } else { - __ unlock_object(x15, x14, x10, *stub->entry()); + __ unlock_object(x15, x14, x10, x16, *stub->entry()); } __ bind(*stub->continuation()); } @@ -1506,22 +1506,23 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register obj = op->obj_opr()->as_register(); // may not be an oop Register hdr = op->hdr_opr()->as_register(); Register lock = op->lock_opr()->as_register(); + Register temp = op->scratch_opr()->as_register(); if (LockingMode == LM_MONITOR) { if (op->info() != nullptr) { add_debug_info_for_null_check_here(op->info()); - __ null_check(obj); + __ null_check(obj, -1); } __ j(*op->stub()->entry()); } else if (op->code() == lir_lock) { assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); // add debug info for NullPointerException only if one is possible - int null_check_offset = __ lock_object(hdr, obj, lock, *op->stub()->entry()); + int null_check_offset = __ lock_object(hdr, obj, lock, temp, *op->stub()->entry()); if (op->info() != nullptr) { add_debug_info_for_null_check(null_check_offset, op->info()); } } else if (op->code() == lir_unlock) { assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); - __ unlock_object(hdr, obj, lock, *op->stub()->entry()); + __ unlock_object(hdr, obj, lock, temp, *op->stub()->entry()); } else { Unimplemented(); } @@ -1647,10 +1648,11 @@ void LIR_Assembler::check_conflict(ciKlass* exact_klass, intptr_t current_klass, __ beqz(t1, none); __ mv(t0, (u1)TypeEntries::null_seen); __ beq(t0, t1, none); - // There is a chance that the checks above (re-reading profiling - // data from memory) fail if another thread has just set the + // There is a chance that the checks above + // fail if another thread has just set the // profiling to this obj's klass __ membar(MacroAssembler::LoadLoad); + __ xorr(tmp, tmp, t1); // get back original value before XOR __ ld(t1, mdo_addr); __ xorr(tmp, tmp, t1); __ andi(t0, tmp, TypeEntries::type_klass_mask); @@ -1677,6 +1679,10 @@ void LIR_Assembler::check_conflict(ciKlass* exact_klass, intptr_t current_klass, __ bind(none); // first time here. Set profile type. __ sd(tmp, mdo_addr); +#ifdef ASSERT + __ andi(tmp, tmp, TypeEntries::type_mask); + __ verify_klass_ptr(tmp); +#endif } } @@ -1711,6 +1717,10 @@ void LIR_Assembler::check_no_conflict(ciKlass* exact_klass, intptr_t current_kla #endif // first time here. Set profile type. __ sd(tmp, mdo_addr); +#ifdef ASSERT + __ andi(tmp, tmp, TypeEntries::type_mask); + __ verify_klass_ptr(tmp); +#endif } else { assert(ciTypeEntries::valid_ciklass(current_klass) != nullptr && ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent"); diff --git a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp index 12df04749fab0..c3928b8b318dc 100644 --- a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp @@ -274,6 +274,7 @@ void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { // "lock" stores the address of the monitor stack slot, so this is not an oop LIR_Opr lock = new_register(T_INT); + LIR_Opr scratch = new_register(T_INT); CodeEmitInfo* info_for_exception = nullptr; if (x->needs_null_check()) { @@ -282,7 +283,7 @@ void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { // this CodeEmitInfo must not have the xhandlers because here the // object is already locked (xhandlers expect object to be unlocked) CodeEmitInfo* info = state_for(x, x->state(), true); - monitor_enter(obj.result(), lock, syncTempOpr(), LIR_OprFact::illegalOpr, + monitor_enter(obj.result(), lock, syncTempOpr(), scratch, x->monitor_no(), info_for_exception, info); } @@ -294,8 +295,9 @@ void LIRGenerator::do_MonitorExit(MonitorExit* x) { LIR_Opr lock = new_register(T_INT); LIR_Opr obj_temp = new_register(T_INT); + LIR_Opr scratch = new_register(T_INT); set_no_result(x); - monitor_exit(obj_temp, lock, syncTempOpr(), LIR_OprFact::illegalOpr, x->monitor_no()); + monitor_exit(obj_temp, lock, syncTempOpr(), scratch, x->monitor_no()); } // neg @@ -801,7 +803,7 @@ void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) { } void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) { - fatal("vectorizedMismatch intrinsic is not implemented on this platform"); + ShouldNotReachHere(); } // _i2l, _i2f, _i2d, _l2i, _l2f, _l2d, _f2i, _f2l, _f2d, _d2i, _d2l, _d2f diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp index 2af629a67cd07..6c1dce0de1598 100644 --- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp @@ -49,10 +49,10 @@ void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result, } } -int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { +int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { const int aligned_mask = BytesPerWord - 1; const int hdr_offset = oopDesc::mark_offset_in_bytes(); - assert_different_registers(hdr, obj, disp_hdr); + assert_different_registers(hdr, obj, disp_hdr, temp, t0, t1); int null_check_offset = -1; verify_oop(obj); @@ -65,15 +65,15 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(hdr, obj); lwu(hdr, Address(hdr, Klass::access_flags_offset())); - test_bit(t0, hdr, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); - bnez(t0, slow_case, true /* is_far */); + test_bit(temp, hdr, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); + bnez(temp, slow_case, true /* is_far */); } // Load object header ld(hdr, Address(obj, hdr_offset)); if (LockingMode == LM_LIGHTWEIGHT) { - fast_lock(obj, hdr, t0, t1, slow_case); + lightweight_lock(obj, hdr, temp, t1, slow_case); } else if (LockingMode == LM_LEGACY) { Label done; // and mark it as unlocked @@ -83,8 +83,8 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr // test if object header is still the same (i.e. unlocked), and if so, store the // displaced header address in the object header - if it is not the same, get the // object header instead - la(t1, Address(obj, hdr_offset)); - cmpxchgptr(hdr, disp_hdr, t1, t0, done, /*fallthough*/nullptr); + la(temp, Address(obj, hdr_offset)); + cmpxchgptr(hdr, disp_hdr, temp, t1, done, /*fallthough*/nullptr); // if the object header was the same, we're done // if the object header was not the same, it is now in the hdr register // => test if it is a stack pointer into the same stack (recursive locking), i.e.: @@ -100,8 +100,8 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr // assuming both the stack pointer and page_size have their least // significant 2 bits cleared and page_size is a power of 2 sub(hdr, hdr, sp); - mv(t0, aligned_mask - (int)os::vm_page_size()); - andr(hdr, hdr, t0); + mv(temp, aligned_mask - (int)os::vm_page_size()); + andr(hdr, hdr, temp); // for recursive locking, the result is zero => save it in the displaced header // location (null in the displaced hdr location indicates recursive locking) sd(hdr, Address(disp_hdr, 0)); @@ -115,10 +115,10 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr return null_check_offset; } -void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { +void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { const int aligned_mask = BytesPerWord - 1; const int hdr_offset = oopDesc::mark_offset_in_bytes(); - assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different"); + assert_different_registers(hdr, obj, disp_hdr, temp, t0, t1); Label done; if (LockingMode != LM_LIGHTWEIGHT) { @@ -135,9 +135,9 @@ void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_ if (LockingMode == LM_LIGHTWEIGHT) { ld(hdr, Address(obj, oopDesc::mark_offset_in_bytes())); - test_bit(t0, hdr, exact_log2(markWord::monitor_value)); - bnez(t0, slow_case, /* is_far */ true); - fast_unlock(obj, hdr, t0, t1, slow_case); + test_bit(temp, hdr, exact_log2(markWord::monitor_value)); + bnez(temp, slow_case, /* is_far */ true); + lightweight_unlock(obj, hdr, temp, t1, slow_case); } else if (LockingMode == LM_LEGACY) { // test if object header is pointing to the displaced header, and if so, restore // the displaced header in the object - if the object header is not pointing to @@ -145,8 +145,8 @@ void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_ // if the object header was not pointing to the displaced header, // we do unlocking via runtime call if (hdr_offset) { - la(t0, Address(obj, hdr_offset)); - cmpxchgptr(disp_hdr, hdr, t0, t1, done, &slow_case); + la(temp, Address(obj, hdr_offset)); + cmpxchgptr(disp_hdr, hdr, temp, t1, done, &slow_case); } else { cmpxchgptr(disp_hdr, hdr, obj, t1, done, &slow_case); } diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp index 738dac78f9df3..b737a438511c8 100644 --- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp @@ -59,14 +59,16 @@ using MacroAssembler::null_check; // hdr : must be x10, contents destroyed // obj : must point to the object to lock, contents preserved // disp_hdr: must point to the displaced header location, contents preserved + // temp : temporary register, must not be scratch register t0 or t1 // returns code offset at which to add null check debug information - int lock_object (Register swap, Register obj, Register disp_hdr, Label& slow_case); + int lock_object(Register swap, Register obj, Register disp_hdr, Register temp, Label& slow_case); // unlocking // hdr : contents destroyed // obj : must point to the object to lock, contents preserved // disp_hdr: must be x10 & must point to the displaced header location, contents destroyed - void unlock_object(Register swap, Register obj, Register lock, Label& slow_case); + // temp : temporary register, must not be scratch register t0 or t1 + void unlock_object(Register swap, Register obj, Register lock, Register temp, Label& slow_case); void initialize_object( Register obj, // result: pointer to object after successful allocation diff --git a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp index 80555b87729bb..ea086d46bdac2 100644 --- a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp @@ -498,6 +498,14 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) { // other registers used in this stub const Register handler_addr = x11; + if (AbortVMOnException) { + __ enter(); + save_live_registers(sasm); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, check_abort_on_vm_exception), x10); + restore_live_registers(sasm); + __ leave(); + } + // verify that only x10, is valid at this time __ invalidate_registers(false, true, true, true, true, true); diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index a45fe0538ea44..a83be3b8f7548 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -43,6 +43,223 @@ #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") +void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg, + Register tmp1Reg, Register tmp2Reg, Register tmp3Reg) { + // Use cr register to indicate the fast_lock result: zero for success; non-zero for failure. + Register flag = t1; + Register oop = objectReg; + Register box = boxReg; + Register disp_hdr = tmp1Reg; + Register tmp = tmp2Reg; + Label cont; + Label object_has_monitor; + Label count, no_count; + + assert_different_registers(oop, box, tmp, disp_hdr, flag, tmp3Reg, t0); + + // Load markWord from object into displaced_header. + ld(disp_hdr, Address(oop, oopDesc::mark_offset_in_bytes())); + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(flag, oop); + lwu(flag, Address(flag, Klass::access_flags_offset())); + test_bit(flag, flag, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); + bnez(flag, cont, true /* is_far */); + } + + // Check for existing monitor + test_bit(t0, disp_hdr, exact_log2(markWord::monitor_value)); + bnez(t0, object_has_monitor); + + if (LockingMode == LM_MONITOR) { + mv(flag, 1); // Set non-zero flag to indicate 'failure' -> take slow-path + j(cont); + } else if (LockingMode == LM_LEGACY) { + // Set tmp to be (markWord of object | UNLOCK_VALUE). + ori(tmp, disp_hdr, markWord::unlocked_value); + + // Initialize the box. (Must happen before we update the object mark!) + sd(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); + + // Compare object markWord with an unlocked value (tmp) and if + // equal exchange the stack address of our box with object markWord. + // On failure disp_hdr contains the possibly locked markWord. + cmpxchg(/*memory address*/oop, /*expected value*/tmp, /*new value*/box, Assembler::int64, Assembler::aq, + Assembler::rl, /*result*/disp_hdr); + mv(flag, zr); + beq(disp_hdr, tmp, cont); // prepare zero flag and goto cont if we won the cas + + assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); + + // If the compare-and-exchange succeeded, then we found an unlocked + // object, will have now locked it will continue at label cont + // We did not see an unlocked object so try the fast recursive case. + + // Check if the owner is self by comparing the value in the + // markWord of object (disp_hdr) with the stack pointer. + sub(disp_hdr, disp_hdr, sp); + mv(tmp, (intptr_t) (~(os::vm_page_size()-1) | (uintptr_t)markWord::lock_mask_in_place)); + // If (mark & lock_mask) == 0 and mark - sp < page_size, we are stack-locking and goto cont, + // hence we can store 0 as the displaced header in the box, which indicates that it is a + // recursive lock. + andr(tmp/*==0?*/, disp_hdr, tmp); + sd(tmp/*==0, perhaps*/, Address(box, BasicLock::displaced_header_offset_in_bytes())); + mv(flag, tmp); // we can use the value of tmp as the result here + j(cont); + } else { + assert(LockingMode == LM_LIGHTWEIGHT, ""); + Label slow; + lightweight_lock(oop, disp_hdr, tmp, tmp3Reg, slow); + + // Indicate success on completion. + mv(flag, zr); + j(count); + bind(slow); + mv(flag, 1); // Set non-zero flag to indicate 'failure' -> take slow-path + j(no_count); + } + + // Handle existing monitor. + bind(object_has_monitor); + // The object's monitor m is unlocked iff m->owner == NULL, + // otherwise m->owner may contain a thread or a stack address. + // + // Try to CAS m->owner from NULL to current thread. + add(tmp, disp_hdr, (in_bytes(ObjectMonitor::owner_offset()) - markWord::monitor_value)); + cmpxchg(/*memory address*/tmp, /*expected value*/zr, /*new value*/xthread, Assembler::int64, Assembler::aq, + Assembler::rl, /*result*/flag); // cas succeeds if flag == zr(expected) + + if (LockingMode != LM_LIGHTWEIGHT) { + // Store a non-null value into the box to avoid looking like a re-entrant + // lock. The fast-path monitor unlock code checks for + // markWord::monitor_value so use markWord::unused_mark which has the + // relevant bit set, and also matches ObjectSynchronizer::slow_enter. + mv(tmp, (address)markWord::unused_mark().value()); + sd(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); + } + + beqz(flag, cont); // CAS success means locking succeeded + + bne(flag, xthread, cont); // Check for recursive locking + + // Recursive lock case + mv(flag, zr); + increment(Address(disp_hdr, in_bytes(ObjectMonitor::recursions_offset()) - markWord::monitor_value), 1, t0, tmp); + + bind(cont); + // zero flag indicates success + // non-zero flag indicates failure + bnez(flag, no_count); + + bind(count); + increment(Address(xthread, JavaThread::held_monitor_count_offset()), 1, t0, tmp); + + bind(no_count); +} + +void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, + Register tmp1Reg, Register tmp2Reg) { + // Use cr register to indicate the fast_unlock result: zero for success; non-zero for failure. + Register flag = t1; + Register oop = objectReg; + Register box = boxReg; + Register disp_hdr = tmp1Reg; + Register tmp = tmp2Reg; + Label cont; + Label object_has_monitor; + Label count, no_count; + + assert_different_registers(oop, box, tmp, disp_hdr, flag, t0); + + if (LockingMode == LM_LEGACY) { + // Find the lock address and load the displaced header from the stack. + ld(disp_hdr, Address(box, BasicLock::displaced_header_offset_in_bytes())); + + // If the displaced header is 0, we have a recursive unlock. + mv(flag, disp_hdr); + beqz(disp_hdr, cont); + } + + // Handle existing monitor. + ld(tmp, Address(oop, oopDesc::mark_offset_in_bytes())); + test_bit(t0, tmp, exact_log2(markWord::monitor_value)); + bnez(t0, object_has_monitor); + + if (LockingMode == LM_MONITOR) { + mv(flag, 1); // Set non-zero flag to indicate 'failure' -> take slow path + j(cont); + } else if (LockingMode == LM_LEGACY) { + // Check if it is still a light weight lock, this is true if we + // see the stack address of the basicLock in the markWord of the + // object. + + cmpxchg(/*memory address*/oop, /*expected value*/box, /*new value*/disp_hdr, Assembler::int64, Assembler::relaxed, + Assembler::rl, /*result*/tmp); + xorr(flag, box, tmp); // box == tmp if cas succeeds + j(cont); + } else { + assert(LockingMode == LM_LIGHTWEIGHT, ""); + Label slow; + lightweight_unlock(oop, tmp, box, disp_hdr, slow); + + // Indicate success on completion. + mv(flag, zr); + j(count); + bind(slow); + mv(flag, 1); // Set non-zero flag to indicate 'failure' -> take slow path + j(no_count); + } + + assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); + + // Handle existing monitor. + bind(object_has_monitor); + STATIC_ASSERT(markWord::monitor_value <= INT_MAX); + add(tmp, tmp, -(int)markWord::monitor_value); // monitor + + if (LockingMode == LM_LIGHTWEIGHT) { + // If the owner is anonymous, we need to fix it -- in an outline stub. + Register tmp2 = disp_hdr; + ld(tmp2, Address(tmp, ObjectMonitor::owner_offset())); + test_bit(t0, tmp2, exact_log2(ObjectMonitor::ANONYMOUS_OWNER)); + C2HandleAnonOMOwnerStub* stub = new (Compile::current()->comp_arena()) C2HandleAnonOMOwnerStub(tmp, tmp2); + Compile::current()->output()->add_stub(stub); + bnez(t0, stub->entry(), /* is_far */ true); + bind(stub->continuation()); + } + + ld(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset())); + + Label notRecursive; + beqz(disp_hdr, notRecursive); // Will be 0 if not recursive. + + // Recursive lock + addi(disp_hdr, disp_hdr, -1); + sd(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset())); + mv(flag, zr); + j(cont); + + bind(notRecursive); + ld(flag, Address(tmp, ObjectMonitor::EntryList_offset())); + ld(disp_hdr, Address(tmp, ObjectMonitor::cxq_offset())); + orr(flag, flag, disp_hdr); // Will be 0 if both are 0. + bnez(flag, cont); + // need a release store here + la(tmp, Address(tmp, ObjectMonitor::owner_offset())); + membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + sd(zr, Address(tmp)); // set unowned + + bind(cont); + // zero flag indicates success + // non-zero flag indicates failure + bnez(flag, no_count); + + bind(count); + decrement(Address(xthread, JavaThread::held_monitor_count_offset()), 1, t0, tmp); + + bind(no_count); +} + // short string // StringUTF16.indexOfChar // StringLatin1.indexOfChar @@ -491,7 +708,9 @@ void C2_MacroAssembler::string_indexof(Register haystack, Register needle, } bne(tmp3, skipch, BMSKIP); // if not equal, skipch is bad char add(result, haystack, isLL ? nlen_tmp : ch2); - ld(ch2, Address(result)); // load 8 bytes from source string + // load 8 bytes from source string + // if isLL is false then read granularity can be 2 + load_long_misaligned(ch2, Address(result), ch1, isLL ? 1 : 2); // can use ch1 as temp register here as it will be trashed by next mv anyway mv(ch1, tmp6); if (isLL) { j(BMLOOPSTR1_AFTER_LOAD); @@ -679,10 +898,30 @@ void C2_MacroAssembler::string_indexof_linearscan(Register haystack, Register ne slli(tmp3, result_tmp, haystack_chr_shift); // result as tmp add(haystack, haystack, tmp3); neg(hlen_neg, tmp3); + if (AvoidUnalignedAccesses) { + // preload first value, then we will read by 1 character per loop, instead of four + // just shifting previous ch2 right by size of character in bits + add(tmp3, haystack, hlen_neg); + (this->*load_4chr)(ch2, Address(tmp3), noreg); + if (isLL) { + // need to erase 1 most significant byte in 32-bit value of ch2 + slli(ch2, ch2, 40); + srli(ch2, ch2, 32); + } else { + slli(ch2, ch2, 16); // 2 most significant bytes will be erased by this operation + } + } bind(CH1_LOOP); - add(ch2, haystack, hlen_neg); - (this->*load_4chr)(ch2, Address(ch2), noreg); + add(tmp3, haystack, hlen_neg); + if (AvoidUnalignedAccesses) { + srli(ch2, ch2, isLL ? 8 : 16); + (this->*haystack_load_1chr)(tmp3, Address(tmp3, isLL ? 3 : 6), noreg); + slli(tmp3, tmp3, isLL ? 24 : 48); + add(ch2, ch2, tmp3); + } else { + (this->*load_4chr)(ch2, Address(tmp3), noreg); + } beq(ch1, ch2, MATCH); add(hlen_neg, hlen_neg, haystack_chr_size); blez(hlen_neg, CH1_LOOP); @@ -700,10 +939,23 @@ void C2_MacroAssembler::string_indexof_linearscan(Register haystack, Register ne slli(tmp3, result_tmp, haystack_chr_shift); add(haystack, haystack, tmp3); neg(hlen_neg, tmp3); - + if (AvoidUnalignedAccesses) { + // preload first value, then we will read by 1 character per loop, instead of two + // just shifting previous ch2 right by size of character in bits + add(tmp3, haystack, hlen_neg); + (this->*haystack_load_1chr)(ch2, Address(tmp3), noreg); + slli(ch2, ch2, isLL ? 8 : 16); + } bind(CH1_LOOP); add(tmp3, haystack, hlen_neg); - (this->*load_2chr)(ch2, Address(tmp3), noreg); + if (AvoidUnalignedAccesses) { + srli(ch2, ch2, isLL ? 8 : 16); + (this->*haystack_load_1chr)(tmp3, Address(tmp3, isLL ? 1 : 2), noreg); + slli(tmp3, tmp3, isLL ? 8 : 16); + add(ch2, ch2, tmp3); + } else { + (this->*load_2chr)(ch2, Address(tmp3), noreg); + } beq(ch1, ch2, MATCH); add(hlen_neg, hlen_neg, haystack_chr_size); blez(hlen_neg, CH1_LOOP); @@ -727,7 +979,14 @@ void C2_MacroAssembler::string_indexof_linearscan(Register haystack, Register ne bind(FIRST_LOOP); add(ch2, haystack, hlen_neg); - (this->*load_2chr)(ch2, Address(ch2), noreg); + if (AvoidUnalignedAccesses) { + (this->*haystack_load_1chr)(tmp2, Address(ch2, isLL ? 1 : 2), noreg); // we need a temp register, we can safely use hlen_tmp here, which is a synonym for tmp2 + (this->*haystack_load_1chr)(ch2, Address(ch2), noreg); + slli(tmp2, tmp2, isLL ? 8 : 16); + add(ch2, ch2, tmp2); + } else { + (this->*load_2chr)(ch2, Address(ch2), noreg); + } beq(first, ch2, STR1_LOOP); bind(STR2_NEXT); @@ -751,10 +1010,7 @@ void C2_MacroAssembler::string_indexof_linearscan(Register haystack, Register ne bind(DO1); (this->*needle_load_1chr)(ch1, Address(needle), noreg); sub(result_tmp, haystack_len, 1); - mv(tmp3, result_tmp); - if (haystack_chr_shift) { - slli(tmp3, result_tmp, haystack_chr_shift); - } + slli(tmp3, result_tmp, haystack_chr_shift); add(haystack, haystack, tmp3); neg(hlen_neg, tmp3); @@ -829,9 +1085,10 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, // load first parts of strings and finish initialization while loading { if (str1_isL == str2_isL) { // LL or UU + // check if str1 and str2 is same pointer + beq(str1, str2, DONE); // load 8 bytes once to compare ld(tmp1, Address(str1)); - beq(str1, str2, DONE); ld(tmp2, Address(str2)); mv(t0, STUB_THRESHOLD); bge(cnt2, t0, STUB); @@ -874,9 +1131,8 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, addi(cnt1, cnt1, 8); } addi(cnt2, cnt2, isUL ? 4 : 8); + bne(tmp1, tmp2, DIFFERENCE); bgez(cnt2, TAIL); - xorr(tmp3, tmp1, tmp2); - bnez(tmp3, DIFFERENCE); // main loop bind(NEXT_WORD); @@ -905,38 +1161,30 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, addi(cnt1, cnt1, 8); addi(cnt2, cnt2, 4); } - bgez(cnt2, TAIL); - - xorr(tmp3, tmp1, tmp2); - beqz(tmp3, NEXT_WORD); - j(DIFFERENCE); + bne(tmp1, tmp2, DIFFERENCE); + bltz(cnt2, NEXT_WORD); bind(TAIL); - xorr(tmp3, tmp1, tmp2); - bnez(tmp3, DIFFERENCE); - // Last longword. In the case where length == 4 we compare the - // same longword twice, but that's still faster than another - // conditional branch. if (str1_isL == str2_isL) { // LL or UU - ld(tmp1, Address(str1)); - ld(tmp2, Address(str2)); + load_long_misaligned(tmp1, Address(str1), tmp3, isLL ? 1 : 2); + load_long_misaligned(tmp2, Address(str2), tmp3, isLL ? 1 : 2); } else if (isLU) { // LU case - lwu(tmp1, Address(str1)); - ld(tmp2, Address(str2)); + load_int_misaligned(tmp1, Address(str1), tmp3, false); + load_long_misaligned(tmp2, Address(str2), tmp3, 2); inflate_lo32(tmp3, tmp1); mv(tmp1, tmp3); } else { // UL case - lwu(tmp2, Address(str2)); - ld(tmp1, Address(str1)); + load_int_misaligned(tmp2, Address(str2), tmp3, false); + load_long_misaligned(tmp1, Address(str1), tmp3, 2); inflate_lo32(tmp3, tmp2); mv(tmp2, tmp3); } bind(TAIL_CHECK); - xorr(tmp3, tmp1, tmp2); - beqz(tmp3, DONE); + beq(tmp1, tmp2, DONE); // Find the first different characters in the longwords and // compute their difference. bind(DIFFERENCE); + xorr(tmp3, tmp1, tmp2); ctzc_bit(result, tmp3, isLL); // count zero from lsb to msb srl(tmp1, tmp1, result); srl(tmp2, tmp2, result); @@ -1867,13 +2115,13 @@ void C2_MacroAssembler::integer_narrow_v(VectorRegister dst, BasicType dst_bt, i } } } else if (src_bt == T_INT) { - // T_SHORT - vsetvli(t0, t0, Assembler::e16, Assembler::mf2); - vncvt_x_x_w(dst, src); - if (dst_bt == T_BYTE) { - vsetvli(t0, t0, Assembler::e8, Assembler::mf2); - vncvt_x_x_w(dst, dst); - } + // T_SHORT + vsetvli(t0, t0, Assembler::e16, Assembler::mf2); + vncvt_x_x_w(dst, src); + if (dst_bt == T_BYTE) { + vsetvli(t0, t0, Assembler::e8, Assembler::mf2); + vncvt_x_x_w(dst, dst); + } } else if (src_bt == T_SHORT) { vsetvli(t0, t0, Assembler::e8, Assembler::mf2); vncvt_x_x_w(dst, src); @@ -1889,8 +2137,6 @@ void C2_MacroAssembler::VFLOATCVT##_safe(VectorRegister dst, VectorRegister src) } VFCVT_SAFE(vfcvt_rtz_x_f_v); -VFCVT_SAFE(vfwcvt_rtz_x_f_v); -VFCVT_SAFE(vfncvt_rtz_x_f_w); #undef VFCVT_SAFE @@ -1932,4 +2178,4 @@ void C2_MacroAssembler::extract_fp_v(FloatRegister dst, VectorRegister src, Basi vslidedown_vx(tmp, src, t0); vfmv_f_s(dst, tmp); } -} \ No newline at end of file +} diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index c0de12c320571..f14f572be8570 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -39,6 +39,11 @@ VectorRegister vrs, bool is_latin, Label& DONE); public: + // Code used by cmpFastLock and cmpFastUnlock mach instructions in .ad file. + // See full description in macroAssembler_riscv.cpp. + void fast_lock(Register object, Register box, Register tmp1, Register tmp2, Register tmp3); + void fast_unlock(Register object, Register box, Register tmp1, Register tmp2); + void string_compare(Register str1, Register str2, Register cnt1, Register cnt2, Register result, Register tmp1, Register tmp2, Register tmp3, @@ -242,8 +247,6 @@ VectorRegister src, BasicType src_bt); void vfcvt_rtz_x_f_v_safe(VectorRegister dst, VectorRegister src); - void vfwcvt_rtz_x_f_v_safe(VectorRegister dst, VectorRegister src); - void vfncvt_rtz_x_f_w_safe(VectorRegister dst, VectorRegister src); void extract_v(Register dst, VectorRegister src, BasicType bt, int idx, VectorRegister tmp); void extract_fp_v(FloatRegister dst, VectorRegister src, BasicType bt, int idx, VectorRegister tmp); diff --git a/src/hotspot/cpu/riscv/frame_riscv.cpp b/src/hotspot/cpu/riscv/frame_riscv.cpp index 54e59d2d0f48f..f1518724608a5 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.cpp +++ b/src/hotspot/cpu/riscv/frame_riscv.cpp @@ -478,7 +478,7 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { // do some validation of frame elements // first the method - Method* m = *interpreter_frame_method_addr(); + Method* m = safe_interpreter_frame_method(); // validate the method we'd find in this potential sender if (!Method::is_valid_method(m)) { return false; diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoah_riscv64.ad b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoah_riscv.ad similarity index 100% rename from src/hotspot/cpu/riscv/gc/shenandoah/shenandoah_riscv64.ad rename to src/hotspot/cpu/riscv/gc/shenandoah/shenandoah_riscv.ad diff --git a/src/hotspot/cpu/riscv/gc/x/x_riscv64.ad b/src/hotspot/cpu/riscv/gc/x/x_riscv.ad similarity index 100% rename from src/hotspot/cpu/riscv/gc/x/x_riscv64.ad rename to src/hotspot/cpu/riscv/gc/x/x_riscv.ad diff --git a/src/hotspot/cpu/riscv/gc/z/z_riscv64.ad b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad similarity index 100% rename from src/hotspot/cpu/riscv/gc/z/z_riscv64.ad rename to src/hotspot/cpu/riscv/gc/z/z_riscv.ad diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp index 34d6eb87564c2..b5c834dc1d0d5 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp @@ -690,7 +690,7 @@ void InterpreterMacroAssembler::remove_activation( // Check that all monitors are unlocked { Label loop, exception, entry, restart; - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); const Address monitor_block_top( fp, frame::interpreter_frame_monitor_block_top_offset * wordSize); const Address monitor_block_bot( @@ -763,6 +763,12 @@ void InterpreterMacroAssembler::remove_activation( // testing if reserved zone needs to be re-enabled Label no_reserved_zone_enabling; + // check if already enabled - if so no re-enabling needed + assert(sizeof(StackOverflow::StackGuardState) == 4, "unexpected size"); + lw(t0, Address(xthread, JavaThread::stack_guard_state_offset())); + subw(t0, t0, StackOverflow::stack_guard_enabled); + beqz(t0, no_reserved_zone_enabling); + ld(t0, Address(xthread, JavaThread::reserved_stack_activation_offset())); ble(t1, t0, no_reserved_zone_enabling); @@ -794,7 +800,7 @@ void InterpreterMacroAssembler::remove_activation( // // Kills: // x10 -// c_rarg0, c_rarg1, c_rarg2, c_rarg3, .. (param regs) +// c_rarg0, c_rarg1, c_rarg2, c_rarg3, c_rarg4, c_rarg5, .. (param regs) // t0, t1 (temp regs) void InterpreterMacroAssembler::lock_object(Register lock_reg) { @@ -809,6 +815,8 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) const Register swap_reg = x10; const Register tmp = c_rarg2; const Register obj_reg = c_rarg3; // Will contain the oop + const Register tmp2 = c_rarg4; + const Register tmp3 = c_rarg5; const int obj_offset = in_bytes(BasicObjectLock::obj_offset()); const int lock_offset = in_bytes(BasicObjectLock::lock_offset()); @@ -829,7 +837,7 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) if (LockingMode == LM_LIGHTWEIGHT) { ld(tmp, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - fast_lock(obj_reg, tmp, t0, t1, slow_case); + lightweight_lock(obj_reg, tmp, tmp2, tmp3, slow_case); j(count); } else if (LockingMode == LM_LEGACY) { // Load (object->mark() | 1) into swap_reg @@ -893,7 +901,7 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) // // Kills: // x10 -// c_rarg0, c_rarg1, c_rarg2, c_rarg3, ... (param regs) +// c_rarg0, c_rarg1, c_rarg2, c_rarg3, c_rarg4, ... (param regs) // t0, t1 (temp regs) void InterpreterMacroAssembler::unlock_object(Register lock_reg) { @@ -907,6 +915,7 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) const Register swap_reg = x10; const Register header_reg = c_rarg2; // Will contain the old oopMark const Register obj_reg = c_rarg3; // Will contain the oop + const Register tmp_reg = c_rarg4; // Temporary used by lightweight_unlock save_bcp(); // Save in case of exception @@ -942,7 +951,7 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) ld(header_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); test_bit(t0, header_reg, exact_log2(markWord::monitor_value)); bnez(t0, slow_case); - fast_unlock(obj_reg, header_reg, swap_reg, t0, slow_case); + lightweight_unlock(obj_reg, header_reg, swap_reg, tmp_reg, slow_case); j(count); bind(slow_case); @@ -1723,8 +1732,8 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& md bind(update); load_klass(obj, obj); - ld(t0, mdo_addr); - xorr(obj, obj, t0); + ld(tmp, mdo_addr); + xorr(obj, obj, tmp); andi(t0, obj, TypeEntries::type_klass_mask); beqz(t0, next); // klass seen before, nothing to // do. The unknown bit may have been @@ -1734,15 +1743,15 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& md bnez(t0, next); // already unknown. Nothing to do anymore. - ld(t0, mdo_addr); - beqz(t0, none); - mv(tmp, (u1)TypeEntries::null_seen); - beq(t0, tmp, none); - // There is a chance that the checks above (re-reading profiling - // data from memory) fail if another thread has just set the + beqz(tmp, none); + mv(t0, (u1)TypeEntries::null_seen); + beq(tmp, t0, none); + // There is a chance that the checks above + // fail if another thread has just set the // profiling to this obj's klass - ld(t0, mdo_addr); - xorr(obj, obj, t0); + xorr(obj, obj, tmp); // get back original value before XOR + ld(tmp, mdo_addr); + xorr(obj, obj, tmp); andi(t0, obj, TypeEntries::type_klass_mask); beqz(t0, next); @@ -1753,6 +1762,10 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& md bind(none); // first time here. Set profile type. sd(obj, mdo_addr); +#ifdef ASSERT + andi(obj, obj, TypeEntries::type_mask); + verify_klass_ptr(obj); +#endif bind(next); } diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index eb82ae2adeb30..fd5739d3d405f 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1655,6 +1655,28 @@ void MacroAssembler::xorrw(Register Rd, Register Rs1, Register Rs2) { sign_extend(Rd, Rd, 32); } +// Rd = Rs1 & (~Rd2) +void MacroAssembler::andn(Register Rd, Register Rs1, Register Rs2) { + if (UseZbb) { + Assembler::andn(Rd, Rs1, Rs2); + return; + } + + notr(Rd, Rs2); + andr(Rd, Rs1, Rd); +} + +// Rd = Rs1 | (~Rd2) +void MacroAssembler::orn(Register Rd, Register Rs1, Register Rs2) { + if (UseZbb) { + Assembler::orn(Rd, Rs1, Rs2); + return; + } + + notr(Rd, Rs2); + orr(Rd, Rs1, Rd); +} + // Note: load_unsigned_short used to be called load_unsigned_word. int MacroAssembler::load_unsigned_short(Register dst, Address src) { int off = offset(); @@ -1700,12 +1722,29 @@ void MacroAssembler::store_sized_value(Address dst, Register src, size_t size_in } } -// granularity is 1, 2 bytes per load +// granularity is 1 OR 2 bytes per load. dst and src.base() allowed to be the same register +void MacroAssembler::load_short_misaligned(Register dst, Address src, Register tmp, bool is_signed, int granularity) { + if (granularity != 1 && granularity != 2) { + ShouldNotReachHere(); + } + if (AvoidUnalignedAccesses && (granularity != 2)) { + assert_different_registers(dst, tmp); + assert_different_registers(tmp, src.base()); + is_signed ? lb(tmp, Address(src.base(), src.offset() + 1)) : lbu(tmp, Address(src.base(), src.offset() + 1)); + slli(tmp, tmp, 8); + lbu(dst, src); + add(dst, dst, tmp); + } else { + is_signed ? lh(dst, src) : lhu(dst, src); + } +} + +// granularity is 1, 2 OR 4 bytes per load, if granularity 2 or 4 then dst and src.base() allowed to be the same register void MacroAssembler::load_int_misaligned(Register dst, Address src, Register tmp, bool is_signed, int granularity) { if (AvoidUnalignedAccesses && (granularity != 4)) { - assert_different_registers(dst, tmp, src.base()); switch(granularity) { case 1: + assert_different_registers(dst, tmp, src.base()); lbu(dst, src); lbu(tmp, Address(src.base(), src.offset() + 1)); slli(tmp, tmp, 8); @@ -1718,9 +1757,11 @@ void MacroAssembler::load_int_misaligned(Register dst, Address src, Register tmp add(dst, dst, tmp); break; case 2: - lhu(dst, src); + assert_different_registers(dst, tmp); + assert_different_registers(tmp, src.base()); is_signed ? lh(tmp, Address(src.base(), src.offset() + 2)) : lhu(tmp, Address(src.base(), src.offset() + 2)); slli(tmp, tmp, 16); + lhu(dst, src); add(dst, dst, tmp); break; default: @@ -1731,12 +1772,12 @@ void MacroAssembler::load_int_misaligned(Register dst, Address src, Register tmp } } -// granularity is 1, 2 or 4 bytes per load +// granularity is 1, 2, 4 or 8 bytes per load, if granularity 4 or 8 then dst and src.base() allowed to be same register void MacroAssembler::load_long_misaligned(Register dst, Address src, Register tmp, int granularity) { if (AvoidUnalignedAccesses && (granularity != 8)) { - assert_different_registers(dst, tmp, src.base()); switch(granularity){ case 1: + assert_different_registers(dst, tmp, src.base()); lbu(dst, src); lbu(tmp, Address(src.base(), src.offset() + 1)); slli(tmp, tmp, 8); @@ -1761,6 +1802,7 @@ void MacroAssembler::load_long_misaligned(Register dst, Address src, Register tm add(dst, dst, tmp); break; case 2: + assert_different_registers(dst, tmp, src.base()); lhu(dst, src); lhu(tmp, Address(src.base(), src.offset() + 2)); slli(tmp, tmp, 16); @@ -1773,9 +1815,11 @@ void MacroAssembler::load_long_misaligned(Register dst, Address src, Register tm add(dst, dst, tmp); break; case 4: - lwu(dst, src); + assert_different_registers(dst, tmp); + assert_different_registers(tmp, src.base()); lwu(tmp, Address(src.base(), src.offset() + 4)); slli(tmp, tmp, 32); + lwu(dst, src); add(dst, dst, tmp); break; default: @@ -1947,6 +1991,22 @@ void MacroAssembler::ror_imm(Register dst, Register src, uint32_t shift, Registe orr(dst, dst, tmp); } +// rotate left with shift bits, 32-bit version +void MacroAssembler::rolw_imm(Register dst, Register src, uint32_t shift, Register tmp) { + if (UseZbb) { + // no roliw available + roriw(dst, src, 32 - shift); + return; + } + + assert_different_registers(dst, tmp); + assert_different_registers(src, tmp); + assert(shift < 32, "shift amount must be < 32"); + srliw(tmp, src, 32 - shift); + slliw(dst, src, shift); + orr(dst, dst, tmp); +} + void MacroAssembler::andi(Register Rd, Register Rn, int64_t imm, Register tmp) { if (is_simm12(imm)) { and_imm12(Rd, Rn, imm); @@ -3946,18 +4006,17 @@ void MacroAssembler::ctzc_bit(Register Rd, Register Rs, bool isLL, Register tmp1 void MacroAssembler::inflate_lo32(Register Rd, Register Rs, Register tmp1, Register tmp2) { assert_different_registers(Rd, Rs, tmp1, tmp2); - mv(tmp1, 0xFF); - mv(Rd, zr); - for (int i = 0; i <= 3; i++) { + mv(tmp1, 0xFF000000); // first byte mask at lower word + andr(Rd, Rs, tmp1); + for (int i = 0; i < 2; i++) { + slli(Rd, Rd, wordSize); + srli(tmp1, tmp1, wordSize); andr(tmp2, Rs, tmp1); - if (i) { - slli(tmp2, tmp2, i * 8); - } orr(Rd, Rd, tmp2); - if (i != 3) { - slli(tmp1, tmp1, 8); - } } + slli(Rd, Rd, wordSize); + andi(tmp2, Rs, 0xFF); // last byte mask at lower word + orr(Rd, Rd, tmp2); } // This instruction reads adjacent 4 bytes from the upper half of source register, @@ -3966,17 +4025,8 @@ void MacroAssembler::inflate_lo32(Register Rd, Register Rs, Register tmp1, Regis // Rd: 00A700A600A500A4 void MacroAssembler::inflate_hi32(Register Rd, Register Rs, Register tmp1, Register tmp2) { assert_different_registers(Rd, Rs, tmp1, tmp2); - - mv(tmp1, 0xFF00000000); - mv(Rd, zr); - for (int i = 0; i <= 3; i++) { - andr(tmp2, Rs, tmp1); - orr(Rd, Rd, tmp2); - srli(Rd, Rd, 8); - if (i != 3) { - slli(tmp1, tmp1, 8); - } - } + srli(Rs, Rs, 32); // only upper 32 bits are needed + inflate_lo32(Rd, Rs, tmp1, tmp2); } // The size of the blocks erased by the zero_blocks stub. We must @@ -4170,6 +4220,57 @@ void MacroAssembler::zero_dcache_blocks(Register base, Register cnt, Register tm bge(cnt, tmp1, loop); } +// java.lang.Math.round(float a) +// Returns the closest int to the argument, with ties rounding to positive infinity. +void MacroAssembler::java_round_float(Register dst, FloatRegister src, FloatRegister ftmp) { + // this instructions calling sequence provides performance improvement on all tested devices; + // don't change it without re-verification + Label done; + mv(t0, jint_cast(0.5f)); + fmv_w_x(ftmp, t0); + + // dst = 0 if NaN + feq_s(t0, src, src); // replacing fclass with feq as performance optimization + mv(dst, zr); + beqz(t0, done); + + // dst = (src + 0.5f) rounded down towards negative infinity + // Adding 0.5f to some floats exceeds the precision limits for a float and rounding takes place. + // RDN is required for fadd_s, RNE gives incorrect results: + // -------------------------------------------------------------------- + // fadd.s rne (src + 0.5f): src = 8388609.000000 ftmp = 8388610.000000 + // fcvt.w.s rdn: ftmp = 8388610.000000 dst = 8388610 + // -------------------------------------------------------------------- + // fadd.s rdn (src + 0.5f): src = 8388609.000000 ftmp = 8388609.000000 + // fcvt.w.s rdn: ftmp = 8388609.000000 dst = 8388609 + // -------------------------------------------------------------------- + fadd_s(ftmp, src, ftmp, RoundingMode::rdn); + fcvt_w_s(dst, ftmp, RoundingMode::rdn); + + bind(done); +} + +// java.lang.Math.round(double a) +// Returns the closest long to the argument, with ties rounding to positive infinity. +void MacroAssembler::java_round_double(Register dst, FloatRegister src, FloatRegister ftmp) { + // this instructions calling sequence provides performance improvement on all tested devices; + // don't change it without re-verification + Label done; + mv(t0, julong_cast(0.5)); + fmv_d_x(ftmp, t0); + + // dst = 0 if NaN + feq_d(t0, src, src); // replacing fclass with feq as performance optimization + mv(dst, zr); + beqz(t0, done); + + // dst = (src + 0.5) rounded down towards negative infinity + fadd_d(ftmp, src, ftmp, RoundingMode::rdn); // RDN is required here otherwise some inputs produce incorrect results + fcvt_l_d(dst, ftmp, RoundingMode::rdn); + + bind(done); +} + #define FCVT_SAFE(FLOATCVT, FLOATSIG) \ void MacroAssembler::FLOATCVT##_safe(Register dst, FloatRegister src, Register tmp) { \ Label done; \ @@ -4586,25 +4687,31 @@ void MacroAssembler::rt_call(address dest, Register tmp) { } } -void MacroAssembler::test_bit(Register Rd, Register Rs, uint32_t bit_pos, Register tmp) { +void MacroAssembler::test_bit(Register Rd, Register Rs, uint32_t bit_pos) { assert(bit_pos < 64, "invalid bit range"); if (UseZbs) { bexti(Rd, Rs, bit_pos); return; } - andi(Rd, Rs, 1UL << bit_pos, tmp); + int64_t imm = (int64_t)(1UL << bit_pos); + if (is_simm12(imm)) { + and_imm12(Rd, Rs, imm); + } else { + srli(Rd, Rs, bit_pos); + and_imm12(Rd, Rd, 1); + } } -// Implements fast-locking. +// Implements lightweight-locking. // Branches to slow upon failure to lock the object. // Falls through upon success. // // - obj: the object to be locked // - hdr: the header, already loaded from obj, will be destroyed // - tmp1, tmp2: temporary registers, will be destroyed -void MacroAssembler::fast_lock(Register obj, Register hdr, Register tmp1, Register tmp2, Label& slow) { +void MacroAssembler::lightweight_lock(Register obj, Register hdr, Register tmp1, Register tmp2, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); - assert_different_registers(obj, hdr, tmp1, tmp2); + assert_different_registers(obj, hdr, tmp1, tmp2, t0); // Check if we would have space on lock-stack for the object. lwu(tmp1, Address(xthread, JavaThread::lock_stack_top_offset())); @@ -4629,16 +4736,16 @@ void MacroAssembler::fast_lock(Register obj, Register hdr, Register tmp1, Regist sw(tmp1, Address(xthread, JavaThread::lock_stack_top_offset())); } -// Implements fast-unlocking. +// Implements ligthweight-unlocking. // Branches to slow upon failure. // Falls through upon success. // // - obj: the object to be unlocked // - hdr: the (pre-loaded) header of the object // - tmp1, tmp2: temporary registers -void MacroAssembler::fast_unlock(Register obj, Register hdr, Register tmp1, Register tmp2, Label& slow) { +void MacroAssembler::lightweight_unlock(Register obj, Register hdr, Register tmp1, Register tmp2, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); - assert_different_registers(obj, hdr, tmp1, tmp2); + assert_different_registers(obj, hdr, tmp1, tmp2, t0); #ifdef ASSERT { diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 83688b88846c6..21f64f4b20e45 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -431,6 +431,7 @@ class MacroAssembler: public Assembler { void store_sized_value(Address dst, Register src, size_t size_in_bytes); // Misaligned loads, will use the best way, according to the AvoidUnalignedAccess flag + void load_short_misaligned(Register dst, Address src, Register tmp, bool is_signed, int granularity = 1); void load_int_misaligned(Register dst, Address src, Register tmp, bool is_signed, int granularity = 1); void load_long_misaligned(Register dst, Address src, Register tmp, int granularity = 1); @@ -595,7 +596,9 @@ class MacroAssembler: public Assembler { void NAME(Register Rs1, Register Rs2, const address dest) { \ assert_cond(dest != nullptr); \ int64_t offset = dest - pc(); \ - guarantee(is_simm13(offset) && ((offset % 2) == 0), "offset is invalid."); \ + guarantee(is_simm13(offset) && is_even(offset), \ + "offset is invalid: is_simm_13: %s offset: " INT64_FORMAT, \ + BOOL_TO_STR(is_simm13(offset)), offset); \ Assembler::NAME(Rs1, Rs2, offset); \ } \ INSN_ENTRY_RELOC(void, NAME(Register Rs1, Register Rs2, address dest, relocInfo::relocType rtype)) \ @@ -760,6 +763,10 @@ class MacroAssembler: public Assembler { void orrw(Register Rd, Register Rs1, Register Rs2); void xorrw(Register Rd, Register Rs1, Register Rs2); + // logic with negate + void andn(Register Rd, Register Rs1, Register Rs2); + void orn(Register Rd, Register Rs1, Register Rs2); + // revb void revb_h_h(Register Rd, Register Rs, Register tmp = t0); // reverse bytes in halfword in lower 16 bits, sign-extend void revb_w_w(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2 = t1); // reverse bytes in lower word, sign-extend @@ -771,6 +778,7 @@ class MacroAssembler: public Assembler { void revb(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2 = t1); // reverse bytes in doubleword void ror_imm(Register dst, Register src, uint32_t shift, Register tmp = t0); + void rolw_imm(Register dst, Register src, uint32_t, Register tmp = t0); void andi(Register Rd, Register Rn, int64_t imm, Register tmp = t0); void orptr(Address adr, RegisterOrConstant src, Register tmp1 = t0, Register tmp2 = t1); @@ -1216,7 +1224,7 @@ class MacroAssembler: public Assembler { void shadd(Register Rd, Register Rs1, Register Rs2, Register tmp, int shamt); // test single bit in Rs, result is set to Rd - void test_bit(Register Rd, Register Rs, uint32_t bit_pos, Register tmp = t0); + void test_bit(Register Rd, Register Rs, uint32_t bit_pos); // Here the float instructions with safe deal with some exceptions. // e.g. convert from NaN, +Inf, -Inf to int, float, double @@ -1227,6 +1235,9 @@ class MacroAssembler: public Assembler { void fcvt_w_d_safe(Register dst, FloatRegister src, Register tmp = t0); void fcvt_l_d_safe(Register dst, FloatRegister src, Register tmp = t0); + void java_round_float(Register dst, FloatRegister src, FloatRegister ftmp); + void java_round_double(Register dst, FloatRegister src, FloatRegister ftmp); + // vector load/store unit-stride instructions void vlex_v(VectorRegister vd, Register base, Assembler::SEW sew, VectorMask vm = unmasked) { switch (sew) { @@ -1433,8 +1444,8 @@ class MacroAssembler: public Assembler { void store_conditional(Register addr, Register new_val, enum operand_size size, Assembler::Aqrl release); public: - void fast_lock(Register obj, Register hdr, Register tmp1, Register tmp2, Label& slow); - void fast_unlock(Register obj, Register hdr, Register tmp1, Register tmp2, Label& slow); + void lightweight_lock(Register obj, Register hdr, Register tmp1, Register tmp2, Label& slow); + void lightweight_unlock(Register obj, Register hdr, Register tmp1, Register tmp2, Label& slow); }; #ifdef ASSERT diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 6678d591625f5..e63ff695a86c7 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -981,6 +981,7 @@ definitions %{ int_def LOAD_COST ( 300, 3 * DEFAULT_COST); // load, fpload int_def STORE_COST ( 100, 1 * DEFAULT_COST); // store, fpstore int_def XFER_COST ( 300, 3 * DEFAULT_COST); // mfc, mtc, fcvt, fmove, fcmp + int_def FMVX_COST ( 100, 1 * DEFAULT_COST); // shuffles with no conversion int_def BRANCH_COST ( 200, 2 * DEFAULT_COST); // branch, jmp, call int_def IMUL_COST ( 1000, 10 * DEFAULT_COST); // imul int_def IDIVSI_COST ( 3400, 34 * DEFAULT_COST); // idivdi @@ -2176,7 +2177,7 @@ bool Matcher::pd_clone_address_expressions(AddPNode* m, Matcher::MStack& mstack, encode %{ // BEGIN Non-volatile memory access - enc_class riscv_enc_li_imm(iRegIorL dst, immIorL src) %{ + enc_class riscv_enc_mov_imm(iRegIorL dst, immIorL src) %{ C2_MacroAssembler _masm(&cbuf); int64_t con = (int64_t)$src$$constant; Register dst_reg = as_Register($dst$$reg); @@ -2352,6 +2353,11 @@ encode %{ ciEnv::current()->record_failure("CodeCache is full"); return; } + } else if (_method->intrinsic_id() == vmIntrinsicID::_ensureMaterializedForStackWalk) { + // The NOP here is purely to ensure that eliding a call to + // JVM_EnsureMaterializedForStackWalk doesn't change the code size. + __ nop(); + __ block_comment("call JVM_EnsureMaterializedForStackWalk (elided)"); } else { int method_index = resolved_method_index(cbuf); RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) @@ -2431,223 +2437,6 @@ encode %{ } %} - // Use cr register to indicate the fast_lock result: zero for success; non-zero for failure. - enc_class riscv_enc_fast_lock(iRegP object, iRegP box, iRegPNoSp tmp1, iRegPNoSp tmp2) %{ - C2_MacroAssembler _masm(&cbuf); - Register flag = t1; - Register oop = as_Register($object$$reg); - Register box = as_Register($box$$reg); - Register disp_hdr = as_Register($tmp1$$reg); - Register tmp = as_Register($tmp2$$reg); - Label cont; - Label object_has_monitor; - Label count, no_count; - - assert_different_registers(oop, box, tmp, disp_hdr, t0); - - // Load markWord from object into displaced_header. - __ ld(disp_hdr, Address(oop, oopDesc::mark_offset_in_bytes())); - - if (DiagnoseSyncOnValueBasedClasses != 0) { - __ load_klass(flag, oop); - __ lwu(flag, Address(flag, Klass::access_flags_offset())); - __ test_bit(flag, flag, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS), tmp /* tmp */); - __ bnez(flag, cont, true /* is_far */); - } - - // Check for existing monitor - __ test_bit(t0, disp_hdr, exact_log2(markWord::monitor_value)); - __ bnez(t0, object_has_monitor); - - if (LockingMode == LM_MONITOR) { - __ mv(flag, 1); // Set non-zero flag to indicate 'failure' -> take slow-path - __ j(cont); - } else if (LockingMode == LM_LEGACY) { - // Set tmp to be (markWord of object | UNLOCK_VALUE). - __ ori(tmp, disp_hdr, markWord::unlocked_value); - - // Initialize the box. (Must happen before we update the object mark!) - __ sd(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); - - // Compare object markWord with an unlocked value (tmp) and if - // equal exchange the stack address of our box with object markWord. - // On failure disp_hdr contains the possibly locked markWord. - __ cmpxchg(/*memory address*/oop, /*expected value*/tmp, /*new value*/box, Assembler::int64, Assembler::aq, - Assembler::rl, /*result*/disp_hdr); - __ mv(flag, zr); - __ beq(disp_hdr, tmp, cont); // prepare zero flag and goto cont if we won the cas - - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - - // If the compare-and-exchange succeeded, then we found an unlocked - // object, will have now locked it will continue at label cont - // We did not see an unlocked object so try the fast recursive case. - - // Check if the owner is self by comparing the value in the - // markWord of object (disp_hdr) with the stack pointer. - __ sub(disp_hdr, disp_hdr, sp); - __ mv(tmp, (intptr_t) (~(os::vm_page_size()-1) | (uintptr_t)markWord::lock_mask_in_place)); - // If (mark & lock_mask) == 0 and mark - sp < page_size, we are stack-locking and goto cont, - // hence we can store 0 as the displaced header in the box, which indicates that it is a - // recursive lock. - __ andr(tmp/*==0?*/, disp_hdr, tmp); - __ sd(tmp/*==0, perhaps*/, Address(box, BasicLock::displaced_header_offset_in_bytes())); - __ mv(flag, tmp); // we can use the value of tmp as the result here - __ j(cont); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, ""); - Label slow; - __ fast_lock(oop, disp_hdr, tmp, t0, slow); - - // Indicate success on completion. - __ mv(flag, zr); - __ j(count); - __ bind(slow); - __ mv(flag, 1); // Set non-zero flag to indicate 'failure' -> take slow-path - __ j(no_count); - } - - // Handle existing monitor. - __ bind(object_has_monitor); - // The object's monitor m is unlocked iff m->owner == NULL, - // otherwise m->owner may contain a thread or a stack address. - // - // Try to CAS m->owner from NULL to current thread. - __ add(tmp, disp_hdr, (in_bytes(ObjectMonitor::owner_offset()) - markWord::monitor_value)); - __ cmpxchg(/*memory address*/tmp, /*expected value*/zr, /*new value*/xthread, Assembler::int64, Assembler::aq, - Assembler::rl, /*result*/flag); // cas succeeds if flag == zr(expected) - - if (LockingMode != LM_LIGHTWEIGHT) { - // Store a non-null value into the box to avoid looking like a re-entrant - // lock. The fast-path monitor unlock code checks for - // markWord::monitor_value so use markWord::unused_mark which has the - // relevant bit set, and also matches ObjectSynchronizer::slow_enter. - __ mv(tmp, (address)markWord::unused_mark().value()); - __ sd(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); - } - - __ beqz(flag, cont); // CAS success means locking succeeded - - __ bne(flag, xthread, cont); // Check for recursive locking - - // Recursive lock case - __ mv(flag, zr); - __ increment(Address(disp_hdr, in_bytes(ObjectMonitor::recursions_offset()) - markWord::monitor_value), 1, t0, tmp); - - __ bind(cont); - // zero flag indicates success - // non-zero flag indicates failure - __ bnez(flag, no_count); - - __ bind(count); - __ increment(Address(xthread, JavaThread::held_monitor_count_offset()), 1, t0, tmp); - - __ bind(no_count); - %} - - // Use cr register to indicate the fast_unlock result: zero for success; non-zero for failure. - enc_class riscv_enc_fast_unlock(iRegP object, iRegP box, iRegPNoSp tmp1, iRegPNoSp tmp2) %{ - C2_MacroAssembler _masm(&cbuf); - Register flag = t1; - Register oop = as_Register($object$$reg); - Register box = as_Register($box$$reg); - Register disp_hdr = as_Register($tmp1$$reg); - Register tmp = as_Register($tmp2$$reg); - Label cont; - Label object_has_monitor; - Label count, no_count; - - assert_different_registers(oop, box, tmp, disp_hdr, flag); - - if (LockingMode == LM_LEGACY) { - // Find the lock address and load the displaced header from the stack. - __ ld(disp_hdr, Address(box, BasicLock::displaced_header_offset_in_bytes())); - - // If the displaced header is 0, we have a recursive unlock. - __ mv(flag, disp_hdr); - __ beqz(disp_hdr, cont); - } - - // Handle existing monitor. - __ ld(tmp, Address(oop, oopDesc::mark_offset_in_bytes())); - __ test_bit(t0, tmp, exact_log2(markWord::monitor_value)); - __ bnez(t0, object_has_monitor); - - if (LockingMode == LM_MONITOR) { - __ mv(flag, 1); // Set non-zero flag to indicate 'failure' -> take slow path - __ j(cont); - } else if (LockingMode == LM_LEGACY) { - // Check if it is still a light weight lock, this is true if we - // see the stack address of the basicLock in the markWord of the - // object. - - __ cmpxchg(/*memory address*/oop, /*expected value*/box, /*new value*/disp_hdr, Assembler::int64, Assembler::relaxed, - Assembler::rl, /*result*/tmp); - __ xorr(flag, box, tmp); // box == tmp if cas succeeds - __ j(cont); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, ""); - Label slow; - __ fast_unlock(oop, tmp, box, disp_hdr, slow); - - // Indicate success on completion. - __ mv(flag, zr); - __ j(count); - __ bind(slow); - __ mv(flag, 1); // Set non-zero flag to indicate 'failure' -> take slow path - __ j(no_count); - } - - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - - // Handle existing monitor. - __ bind(object_has_monitor); - STATIC_ASSERT(markWord::monitor_value <= INT_MAX); - __ add(tmp, tmp, -(int)markWord::monitor_value); // monitor - - if (LockingMode == LM_LIGHTWEIGHT) { - // If the owner is anonymous, we need to fix it -- in an outline stub. - Register tmp2 = disp_hdr; - __ ld(tmp2, Address(tmp, ObjectMonitor::owner_offset())); - __ test_bit(t0, tmp2, exact_log2(ObjectMonitor::ANONYMOUS_OWNER)); - C2HandleAnonOMOwnerStub* stub = new (Compile::current()->comp_arena()) C2HandleAnonOMOwnerStub(tmp, tmp2); - Compile::current()->output()->add_stub(stub); - __ bnez(t0, stub->entry(), /* is_far */ true); - __ bind(stub->continuation()); - } - - __ ld(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset())); - - Label notRecursive; - __ beqz(disp_hdr, notRecursive); // Will be 0 if not recursive. - - // Recursive lock - __ addi(disp_hdr, disp_hdr, -1); - __ sd(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset())); - __ mv(flag, zr); - __ j(cont); - - __ bind(notRecursive); - __ ld(flag, Address(tmp, ObjectMonitor::EntryList_offset())); - __ ld(disp_hdr, Address(tmp, ObjectMonitor::cxq_offset())); - __ orr(flag, flag, disp_hdr); // Will be 0 if both are 0. - __ bnez(flag, cont); - // need a release store here - __ la(tmp, Address(tmp, ObjectMonitor::owner_offset())); - __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - __ sd(zr, Address(tmp)); // set unowned - - __ bind(cont); - // zero flag indicates success - // non-zero flag indicates failure - __ bnez(flag, no_count); - - __ bind(count); - __ decrement(Address(xthread, JavaThread::held_monitor_count_offset()), 1, t0, tmp); - - __ bind(no_count); - %} - // arithmetic encodings enc_class riscv_enc_divw(iRegI dst, iRegI src1, iRegI src2) %{ @@ -4965,9 +4754,9 @@ instruct loadConI(iRegINoSp dst, immI src) match(Set dst src); ins_cost(ALU_COST); - format %{ "li $dst, $src\t# int, #@loadConI" %} + format %{ "mv $dst, $src\t# int, #@loadConI" %} - ins_encode(riscv_enc_li_imm(dst, src)); + ins_encode(riscv_enc_mov_imm(dst, src)); ins_pipe(ialu_imm); %} @@ -4978,9 +4767,9 @@ instruct loadConL(iRegLNoSp dst, immL src) match(Set dst src); ins_cost(ALU_COST); - format %{ "li $dst, $src\t# long, #@loadConL" %} + format %{ "mv $dst, $src\t# long, #@loadConL" %} - ins_encode(riscv_enc_li_imm(dst, src)); + ins_encode(riscv_enc_mov_imm(dst, src)); ins_pipe(ialu_imm); %} @@ -6859,6 +6648,21 @@ instruct mulHiL_rReg(iRegLNoSp dst, iRegL src1, iRegL src2) ins_pipe(lmul_reg_reg); %} +instruct umulHiL_rReg(iRegLNoSp dst, iRegL src1, iRegL src2) +%{ + match(Set dst (UMulHiL src1 src2)); + ins_cost(IMUL_COST); + format %{ "mulhu $dst, $src1, $src2\t# umulhi, #@umulHiL_rReg" %} + + ins_encode %{ + __ mulhu(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(lmul_reg_reg); +%} + // Integer Divide instruct divI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ @@ -8423,6 +8227,34 @@ instruct convN2I(iRegINoSp dst, iRegN src) ins_pipe(ialu_reg); %} +instruct round_double_reg(iRegLNoSp dst, fRegD src, fRegD ftmp) %{ + match(Set dst (RoundD src)); + + ins_cost(XFER_COST + BRANCH_COST); + effect(TEMP ftmp); + format %{ "java_round_double $dst, $src\t#@round_double_reg" %} + + ins_encode %{ + __ java_round_double($dst$$Register, as_FloatRegister($src$$reg), as_FloatRegister($ftmp$$reg)); + %} + + ins_pipe(pipe_slow); +%} + +instruct round_float_reg(iRegINoSp dst, fRegF src, fRegF ftmp) %{ + match(Set dst (RoundF src)); + + ins_cost(XFER_COST + BRANCH_COST); + effect(TEMP ftmp); + format %{ "java_round_float $dst, $src\t#@round_float_reg" %} + + ins_encode %{ + __ java_round_float($dst$$Register, as_FloatRegister($src$$reg), as_FloatRegister($ftmp$$reg)); + %} + + ins_pipe(pipe_slow); +%} + // Convert oop pointer into compressed form instruct encodeHeapOop(iRegNNoSp dst, iRegP src) %{ match(Set dst (EncodeP src)); @@ -8652,7 +8484,7 @@ instruct MoveF2I_reg_reg(iRegINoSp dst, fRegF src) %{ effect(DEF dst, USE src); - ins_cost(XFER_COST); + ins_cost(FMVX_COST); format %{ "fmv.x.w $dst, $src\t#@MoveL2D_reg_stack" %} @@ -8670,7 +8502,7 @@ instruct MoveI2F_reg_reg(fRegF dst, iRegI src) %{ effect(DEF dst, USE src); - ins_cost(XFER_COST); + ins_cost(FMVX_COST); format %{ "fmv.w.x $dst, $src\t#@MoveI2F_reg_reg" %} @@ -8688,7 +8520,7 @@ instruct MoveD2L_reg_reg(iRegLNoSp dst, fRegD src) %{ effect(DEF dst, USE src); - ins_cost(XFER_COST); + ins_cost(FMVX_COST); format %{ "fmv.x.d $dst, $src\t#@MoveD2L_reg_reg" %} @@ -8706,7 +8538,7 @@ instruct MoveL2D_reg_reg(fRegD dst, iRegL src) %{ effect(DEF dst, USE src); - ins_cost(XFER_COST); + ins_cost(FMVX_COST); format %{ "fmv.d.x $dst, $src\t#@MoveD2L_reg_reg" %} @@ -10374,15 +10206,17 @@ instruct tlsLoadP(javaThread_RegP dst) // inlined locking and unlocking // using t1 as the 'flag' register to bridge the BoolNode producers and consumers -instruct cmpFastLock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp1, iRegPNoSp tmp2) +instruct cmpFastLock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3) %{ match(Set cr (FastLock object box)); - effect(TEMP tmp1, TEMP tmp2); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); ins_cost(LOAD_COST * 2 + STORE_COST * 3 + ALU_COST * 6 + BRANCH_COST * 3); - format %{ "fastlock $object,$box\t! kills $tmp1,$tmp2, #@cmpFastLock" %} + format %{ "fastlock $object,$box\t! kills $tmp1,$tmp2,$tmp3, #@cmpFastLock" %} - ins_encode(riscv_enc_fast_lock(object, box, tmp1, tmp2)); + ins_encode %{ + __ fast_lock($object$$Register, $box$$Register, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); + %} ins_pipe(pipe_serial); %} @@ -10396,7 +10230,9 @@ instruct cmpFastUnlock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp1, iR ins_cost(LOAD_COST * 2 + STORE_COST + ALU_COST * 2 + BRANCH_COST * 4); format %{ "fastunlock $object,$box\t! kills $tmp1, $tmp2, #@cmpFastUnlock" %} - ins_encode(riscv_enc_fast_unlock(object, box, tmp1, tmp2)); + ins_encode %{ + __ fast_unlock($object$$Register, $box$$Register, $tmp1$$Register, $tmp2$$Register); + %} ins_pipe(pipe_serial); %} diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 81a9b8a011481..06826ecf04601 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -934,7 +934,7 @@ instruct vmla(vReg dst_src1, vReg src2, vReg 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" %} + format %{ "vmla $dst_src1, $dst_src1, $src2, $src3" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -970,7 +970,7 @@ instruct vmls(vReg dst_src1, vReg src2, vReg 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" %} + format %{ "vmls $dst_src1, $dst_src1, $src2, $src3" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -2954,11 +2954,9 @@ instruct vmask_gen_I(vRegMask dst, iRegI src) %{ format %{ "vmask_gen_I $dst, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); - Assembler::SEW sew = Assembler::elemtype_to_sew(bt); __ vsetvli_helper(bt, Matcher::vector_length(this)); - __ vmclr_m(as_VectorRegister($dst$$reg)); - __ vsetvli(t0, $src$$Register, sew); - __ vmset_m(as_VectorRegister($dst$$reg)); + __ vid_v(as_VectorRegister($dst$$reg)); + __ vmsltu_vx(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), $src$$Register); %} ins_pipe(pipe_slow); %} @@ -2968,26 +2966,30 @@ instruct vmask_gen_L(vRegMask dst, iRegL src) %{ format %{ "vmask_gen_L $dst, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); - Assembler::SEW sew = Assembler::elemtype_to_sew(bt); __ vsetvli_helper(bt, Matcher::vector_length(this)); - __ vmclr_m(as_VectorRegister($dst$$reg)); - __ vsetvli(t0, $src$$Register, sew); - __ vmset_m(as_VectorRegister($dst$$reg)); + __ vid_v(as_VectorRegister($dst$$reg)); + __ vmsltu_vx(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), $src$$Register); %} ins_pipe(pipe_slow); %} instruct vmask_gen_imm(vRegMask dst, immL con) %{ + predicate(n->in(1)->get_long() <= 16 || + n->in(1)->get_long() == Matcher::vector_length(n)); match(Set dst (VectorMaskGen con)); format %{ "vmask_gen_imm $dst, $con" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); - if ($con$$constant != Matcher::vector_length(this)) { - __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + if ((uint)($con$$constant) == 0) { __ vmclr_m(as_VectorRegister($dst$$reg)); + } else if ((uint)($con$$constant) == Matcher::vector_length(this)) { + __ vmset_m(as_VectorRegister($dst$$reg)); + } else { + assert((uint)($con$$constant) < Matcher::vector_length(this), "unsupported input lane_cnt"); + __ vid_v(as_VectorRegister($dst$$reg)); + __ vmsleu_vi(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), (uint)($con$$constant) - 1); } - __ vsetvli_helper(bt, (uint)($con$$constant)); - __ vmset_m(as_VectorRegister($dst$$reg)); %} ins_pipe(pipe_slow); %} @@ -3197,13 +3199,12 @@ instruct vcvtStoX_fp_extend(vReg dst, vReg src) %{ effect(TEMP_DEF dst); format %{ "vcvtStoX_fp_extend $dst, $src" %} ins_encode %{ - __ vsetvli_helper(T_SHORT, Matcher::vector_length(this), Assembler::mf2); + BasicType bt = Matcher::vector_element_basic_type(this); + __ integer_extend_v(as_VectorRegister($dst$$reg), (bt == T_FLOAT ? T_INT : T_LONG), + Matcher::vector_length(this), as_VectorRegister($src$$reg), T_SHORT); + __ vsetvli_helper(bt, Matcher::vector_length(this)); __ csrwi(CSR_FRM, C2_MacroAssembler::rne); - __ vfwcvt_f_x_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg)); - if (Matcher::vector_element_basic_type(this) == T_DOUBLE) { - __ vsetvli_helper(T_FLOAT, Matcher::vector_length(this), Assembler::mf2); - __ vfwcvt_f_f_v(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg)); - } + __ vfcvt_f_x_v(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg)); %} ins_pipe(pipe_slow); %} @@ -3309,12 +3310,11 @@ instruct vcvtFtoX_narrow(vReg dst, vReg src, vRegMask_V0 v0) %{ effect(TEMP_DEF dst, TEMP v0); format %{ "vcvtFtoX_narrow $dst, $src" %} ins_encode %{ - __ vsetvli_helper(T_SHORT, Matcher::vector_length(this), Assembler::mf2); - __ vfncvt_rtz_x_f_w_safe(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg)); - if (Matcher::vector_element_basic_type(this) == T_BYTE) { - __ vsetvli_helper(T_BYTE, Matcher::vector_length(this), Assembler::mf2); - __ vncvt_x_x_w(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg)); - } + __ vsetvli_helper(T_FLOAT, Matcher::vector_length(this)); + __ vfcvt_rtz_x_f_v_safe(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg)); + BasicType bt = Matcher::vector_element_basic_type(this); + __ integer_narrow_v(as_VectorRegister($dst$$reg), bt, Matcher::vector_length(this), + as_VectorRegister($dst$$reg), T_INT); %} ins_pipe(pipe_slow); %} @@ -3337,8 +3337,11 @@ instruct vcvtFtoL(vReg dst, vReg src, vRegMask_V0 v0) %{ effect(TEMP_DEF dst, TEMP v0); format %{ "vcvtFtoL $dst, $src" %} ins_encode %{ + __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); + __ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg)); __ vsetvli_helper(T_FLOAT, Matcher::vector_length(this), Assembler::mf2); - __ vfwcvt_rtz_x_f_v_safe(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg)); + __ vmfeq_vv(as_VectorRegister($v0$$reg), as_VectorRegister($src$$reg), as_VectorRegister($src$$reg)); + __ vfwcvt_rtz_x_f_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), Assembler::v0_t); %} ins_pipe(pipe_slow); %} @@ -3366,8 +3369,11 @@ instruct vcvtDtoX_narrow(vReg dst, vReg src, vRegMask_V0 v0) %{ effect(TEMP_DEF dst, TEMP v0); format %{ "vcvtDtoX_narrow $dst, $src" %} ins_encode %{ + __ vsetvli_helper(T_DOUBLE, Matcher::vector_length(this)); + __ vmfeq_vv(as_VectorRegister($v0$$reg), as_VectorRegister($src$$reg), as_VectorRegister($src$$reg)); __ vsetvli_helper(T_INT, Matcher::vector_length(this), Assembler::mf2); - __ vfncvt_rtz_x_f_w_safe(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg)); + __ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg)); + __ vfncvt_rtz_x_f_w(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), Assembler::v0_t); BasicType bt = Matcher::vector_element_basic_type(this); if (bt == T_BYTE || bt == T_SHORT) { __ integer_narrow_v(as_VectorRegister($dst$$reg), bt, Matcher::vector_length(this), @@ -3551,18 +3557,16 @@ instruct extractD(fRegD dst, vReg src, immI idx, vReg tmp) // ------------------------------ Compress/Expand Operations ------------------- -instruct mcompress(vRegMask dst, vRegMask src, iRegLNoSp tmp) %{ +instruct mcompress(vRegMask dst, vRegMask src, vReg tmp) %{ match(Set dst (CompressM src)); - effect(TEMP_DEF dst, TEMP tmp); + effect(TEMP tmp); format %{ "mcompress $dst, $src\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); - Assembler::SEW sew = Assembler::elemtype_to_sew(bt); __ vsetvli_helper(bt, Matcher::vector_length(this)); - __ vmclr_m(as_VectorRegister($dst$$reg)); - __ vcpop_m($tmp$$Register, as_VectorRegister($src$$reg)); - __ vsetvli(t0, $tmp$$Register, sew); - __ vmset_m(as_VectorRegister($dst$$reg)); + __ vid_v(as_VectorRegister($tmp$$reg)); + __ vcpop_m(t0, as_VectorRegister($src$$reg)); + __ vmsltu_vx(as_VectorRegister($dst$$reg), as_VectorRegister($tmp$$reg), t0); %} ins_pipe(pipe_slow); %} diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index 0c671ae1203e0..691dfa1bd7040 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -1650,6 +1650,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, const Register obj_reg = x9; // Will contain the oop const Register lock_reg = x30; // Address of compiler lock object (BasicLock) const Register old_hdr = x30; // value of old header at unlock time + const Register lock_tmp = x31; // Temporary used by lightweight_lock/unlock const Register tmp = ra; Label slow_path_lock; @@ -1701,7 +1702,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, } else { assert(LockingMode == LM_LIGHTWEIGHT, ""); __ ld(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ fast_lock(obj_reg, swap_reg, tmp, t0, slow_path_lock); + __ lightweight_lock(obj_reg, swap_reg, tmp, lock_tmp, slow_path_lock); } __ bind(count); @@ -1829,7 +1830,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ ld(old_hdr, Address(obj_reg, oopDesc::mark_offset_in_bytes())); __ test_bit(t0, old_hdr, exact_log2(markWord::monitor_value)); __ bnez(t0, slow_path_unlock); - __ fast_unlock(obj_reg, old_hdr, swap_reg, t0, slow_path_unlock); + __ lightweight_unlock(obj_reg, old_hdr, swap_reg, lock_tmp, slow_path_unlock); __ decrement(Address(xthread, JavaThread::held_monitor_count_offset())); } diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 60c1fc8c3d5a9..aab65019619f7 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -2310,24 +2310,21 @@ class StubGenerator: public StubCodeGenerator { } // code for comparing 8 characters of strings with Latin1 and Utf16 encoding - void compare_string_8_x_LU(Register tmpL, Register tmpU, Label &DIFF1, - Label &DIFF2) { - const Register strU = x12, curU = x7, strL = x29, tmp = x30; - __ ld(tmpL, Address(strL)); - __ addi(strL, strL, 8); + void compare_string_8_x_LU(Register tmpL, Register tmpU, Register strL, Register strU, Label& DIFF) { + const Register tmp = x30, tmpLval = x12; + __ ld(tmpLval, Address(strL)); + __ addi(strL, strL, wordSize); __ ld(tmpU, Address(strU)); - __ addi(strU, strU, 8); - __ inflate_lo32(tmp, tmpL); - __ mv(t0, tmp); - __ xorr(tmp, curU, t0); - __ bnez(tmp, DIFF2); - - __ ld(curU, Address(strU)); - __ addi(strU, strU, 8); - __ inflate_hi32(tmp, tmpL); - __ mv(t0, tmp); - __ xorr(tmp, tmpU, t0); - __ bnez(tmp, DIFF1); + __ addi(strU, strU, wordSize); + __ inflate_lo32(tmpL, tmpLval); + __ xorr(tmp, tmpU, tmpL); + __ bnez(tmp, DIFF); + + __ ld(tmpU, Address(strU)); + __ addi(strU, strU, wordSize); + __ inflate_hi32(tmpL, tmpLval); + __ xorr(tmp, tmpU, tmpL); + __ bnez(tmp, DIFF); } // x10 = result @@ -2342,11 +2339,9 @@ class StubGenerator: public StubCodeGenerator { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", isLU ? "compare_long_string_different_encoding LU" : "compare_long_string_different_encoding UL"); address entry = __ pc(); - Label SMALL_LOOP, TAIL, TAIL_LOAD_16, LOAD_LAST, DIFF1, DIFF2, - DONE, CALCULATE_DIFFERENCE; - const Register result = x10, str1 = x11, cnt1 = x12, str2 = x13, cnt2 = x14, - tmp1 = x28, tmp2 = x29, tmp3 = x30, tmp4 = x7, tmp5 = x31; - RegSet spilled_regs = RegSet::of(tmp4, tmp5); + Label SMALL_LOOP, TAIL, LOAD_LAST, DONE, CALCULATE_DIFFERENCE; + const Register result = x10, str1 = x11, str2 = x13, cnt2 = x14, + tmp1 = x28, tmp2 = x29, tmp3 = x30, tmp4 = x12; // cnt2 == amount of characters left to compare // Check already loaded first 4 symbols @@ -2354,77 +2349,81 @@ class StubGenerator: public StubCodeGenerator { __ mv(isLU ? tmp1 : tmp2, tmp3); __ addi(str1, str1, isLU ? wordSize / 2 : wordSize); __ addi(str2, str2, isLU ? wordSize : wordSize / 2); - __ sub(cnt2, cnt2, 8); // Already loaded 4 symbols. Last 4 is special case. - __ push_reg(spilled_regs, sp); + __ sub(cnt2, cnt2, wordSize / 2); // Already loaded 4 symbols - if (isLU) { - __ add(str1, str1, cnt2); - __ shadd(str2, cnt2, str2, t0, 1); - } else { - __ shadd(str1, cnt2, str1, t0, 1); - __ add(str2, str2, cnt2); - } __ xorr(tmp3, tmp1, tmp2); - __ mv(tmp5, tmp2); __ bnez(tmp3, CALCULATE_DIFFERENCE); Register strU = isLU ? str2 : str1, strL = isLU ? str1 : str2, - tmpU = isLU ? tmp5 : tmp1, // where to keep U for comparison - tmpL = isLU ? tmp1 : tmp5; // where to keep L for comparison + tmpU = isLU ? tmp2 : tmp1, // where to keep U for comparison + tmpL = isLU ? tmp1 : tmp2; // where to keep L for comparison - __ sub(tmp2, strL, cnt2); // strL pointer to load from - __ slli(t0, cnt2, 1); - __ sub(cnt1, strU, t0); // strU pointer to load from + // make sure main loop is 8 byte-aligned, we should load another 4 bytes from strL + // cnt2 is >= 68 here, no need to check it for >= 0 + __ lwu(tmpL, Address(strL)); + __ addi(strL, strL, wordSize / 2); + __ ld(tmpU, Address(strU)); + __ addi(strU, strU, wordSize); + __ inflate_lo32(tmp3, tmpL); + __ mv(tmpL, tmp3); + __ xorr(tmp3, tmpU, tmpL); + __ bnez(tmp3, CALCULATE_DIFFERENCE); + __ addi(cnt2, cnt2, -wordSize / 2); - __ ld(tmp4, Address(cnt1)); - __ addi(cnt1, cnt1, 8); - __ beqz(cnt2, LOAD_LAST); // no characters left except last load - __ sub(cnt2, cnt2, 16); + // we are now 8-bytes aligned on strL + __ sub(cnt2, cnt2, wordSize * 2); __ bltz(cnt2, TAIL); __ bind(SMALL_LOOP); // smaller loop - __ sub(cnt2, cnt2, 16); - compare_string_8_x_LU(tmpL, tmpU, DIFF1, DIFF2); - compare_string_8_x_LU(tmpL, tmpU, DIFF1, DIFF2); + __ sub(cnt2, cnt2, wordSize * 2); + compare_string_8_x_LU(tmpL, tmpU, strL, strU, CALCULATE_DIFFERENCE); + compare_string_8_x_LU(tmpL, tmpU, strL, strU, CALCULATE_DIFFERENCE); __ bgez(cnt2, SMALL_LOOP); - __ addi(t0, cnt2, 16); - __ beqz(t0, LOAD_LAST); - __ bind(TAIL); // 1..15 characters left until last load (last 4 characters) - // Address of 8 bytes before last 4 characters in UTF-16 string - __ shadd(cnt1, cnt2, cnt1, t0, 1); - // Address of 16 bytes before last 4 characters in Latin1 string - __ add(tmp2, tmp2, cnt2); - __ ld(tmp4, Address(cnt1, -8)); - // last 16 characters before last load - compare_string_8_x_LU(tmpL, tmpU, DIFF1, DIFF2); - compare_string_8_x_LU(tmpL, tmpU, DIFF1, DIFF2); - __ j(LOAD_LAST); - __ bind(DIFF2); - __ mv(tmpU, tmp4); - __ bind(DIFF1); - __ mv(tmpL, t0); - __ j(CALCULATE_DIFFERENCE); - __ bind(LOAD_LAST); - // Last 4 UTF-16 characters are already pre-loaded into tmp4 by compare_string_8_x_LU. - // No need to load it again - __ mv(tmpU, tmp4); - __ ld(tmpL, Address(strL)); + __ addi(t0, cnt2, wordSize * 2); + __ beqz(t0, DONE); + __ bind(TAIL); // 1..15 characters left + // Aligned access. Load bytes in portions - 4, 2, 1. + + __ addi(t0, cnt2, wordSize); + __ addi(cnt2, cnt2, wordSize * 2); // amount of characters left to process + __ bltz(t0, LOAD_LAST); + // remaining characters are greater than or equals to 8, we can do one compare_string_8_x_LU + compare_string_8_x_LU(tmpL, tmpU, strL, strU, CALCULATE_DIFFERENCE); + __ addi(cnt2, cnt2, -wordSize); + __ beqz(cnt2, DONE); // no character left + __ bind(LOAD_LAST); // cnt2 = 1..7 characters left + + __ addi(cnt2, cnt2, -wordSize); // cnt2 is now an offset in strL which points to last 8 bytes + __ slli(t0, cnt2, 1); // t0 is now an offset in strU which points to last 16 bytes + __ add(strL, strL, cnt2); // Address of last 8 bytes in Latin1 string + __ add(strU, strU, t0); // Address of last 16 bytes in UTF-16 string + __ load_int_misaligned(tmpL, Address(strL), t0, false); + __ load_long_misaligned(tmpU, Address(strU), t0, 2); __ inflate_lo32(tmp3, tmpL); __ mv(tmpL, tmp3); __ xorr(tmp3, tmpU, tmpL); - __ beqz(tmp3, DONE); + __ bnez(tmp3, CALCULATE_DIFFERENCE); + + __ addi(strL, strL, wordSize / 2); // Address of last 4 bytes in Latin1 string + __ addi(strU, strU, wordSize); // Address of last 8 bytes in UTF-16 string + __ load_int_misaligned(tmpL, Address(strL), t0, false); + __ load_long_misaligned(tmpU, Address(strU), t0, 2); + __ inflate_lo32(tmp3, tmpL); + __ mv(tmpL, tmp3); + __ xorr(tmp3, tmpU, tmpL); + __ bnez(tmp3, CALCULATE_DIFFERENCE); + __ j(DONE); // no character left // Find the first different characters in the longwords and // compute their difference. __ bind(CALCULATE_DIFFERENCE); __ ctzc_bit(tmp4, tmp3); __ srl(tmp1, tmp1, tmp4); - __ srl(tmp5, tmp5, tmp4); + __ srl(tmp2, tmp2, tmp4); __ andi(tmp1, tmp1, 0xFFFF); - __ andi(tmp5, tmp5, 0xFFFF); - __ sub(result, tmp1, tmp5); + __ andi(tmp2, tmp2, 0xFFFF); + __ sub(result, tmp1, tmp2); __ bind(DONE); - __ pop_reg(spilled_regs, sp); __ ret(); return entry; } @@ -2537,9 +2536,9 @@ class StubGenerator: public StubCodeGenerator { __ xorr(tmp4, tmp1, tmp2); __ bnez(tmp4, DIFF); __ add(str1, str1, cnt2); - __ ld(tmp5, Address(str1)); + __ load_long_misaligned(tmp5, Address(str1), tmp3, isLL ? 1 : 2); __ add(str2, str2, cnt2); - __ ld(cnt1, Address(str2)); + __ load_long_misaligned(cnt1, Address(str2), tmp3, isLL ? 1 : 2); __ xorr(tmp4, tmp5, cnt1); __ beqz(tmp4, LENGTH_DIFF); // Find the first different characters in the longwords and @@ -3950,6 +3949,375 @@ class StubGenerator: public StubCodeGenerator { return start; } + // Set of L registers that correspond to a contiguous memory area. + // Each 64-bit register typically corresponds to 2 32-bit integers. + template + class RegCache { + private: + MacroAssembler *_masm; + Register _regs[L]; + + public: + RegCache(MacroAssembler *masm, RegSet rs): _masm(masm) { + assert(rs.size() == L, "%u registers are used to cache %u 4-byte data", rs.size(), 2 * L); + auto it = rs.begin(); + for (auto &r: _regs) { + r = *it; + ++it; + } + } + + // generate load for the i'th register + void gen_load(uint i, Register base) { + assert(i < L, "invalid i: %u", i); + __ ld(_regs[i], Address(base, 8 * i)); + } + + // add i'th 32-bit integer to dest + void add_u32(const Register dest, uint i, const Register rtmp = t0) { + assert(i < 2 * L, "invalid i: %u", i); + + if (is_even(i)) { + // Use the bottom 32 bits. No need to mask off the top 32 bits + // as addw will do the right thing. + __ addw(dest, dest, _regs[i / 2]); + } else { + // Use the top 32 bits by right-shifting them. + __ srli(rtmp, _regs[i / 2], 32); + __ addw(dest, dest, rtmp); + } + } + }; + + typedef RegCache<8> BufRegCache; + + // a += value + x + ac; + // a = Integer.rotateLeft(a, s) + b; + void m5_FF_GG_HH_II_epilogue(BufRegCache& reg_cache, + Register a, Register b, Register c, Register d, + int k, int s, int t, + Register value) { + // a += ac + __ addw(a, a, t, t1); + + // a += x; + reg_cache.add_u32(a, k); + // a += value; + __ addw(a, a, value); + + // a = Integer.rotateLeft(a, s) + b; + __ rolw_imm(a, a, s); + __ addw(a, a, b); + } + + // a += ((b & c) | ((~b) & d)) + x + ac; + // a = Integer.rotateLeft(a, s) + b; + void md5_FF(BufRegCache& reg_cache, + Register a, Register b, Register c, Register d, + int k, int s, int t, + Register rtmp1, Register rtmp2) { + // rtmp1 = b & c + __ andr(rtmp1, b, c); + + // rtmp2 = (~b) & d + __ andn(rtmp2, d, b); + + // rtmp1 = (b & c) | ((~b) & d) + __ orr(rtmp1, rtmp1, rtmp2); + + m5_FF_GG_HH_II_epilogue(reg_cache, a, b, c, d, k, s, t, rtmp1); + } + + // a += ((b & d) | (c & (~d))) + x + ac; + // a = Integer.rotateLeft(a, s) + b; + void md5_GG(BufRegCache& reg_cache, + Register a, Register b, Register c, Register d, + int k, int s, int t, + Register rtmp1, Register rtmp2) { + // rtmp1 = b & d + __ andr(rtmp1, b, d); + + // rtmp2 = c & (~d) + __ andn(rtmp2, c, d); + + // rtmp1 = (b & d) | (c & (~d)) + __ orr(rtmp1, rtmp1, rtmp2); + + m5_FF_GG_HH_II_epilogue(reg_cache, a, b, c, d, k, s, t, rtmp1); + } + + // a += ((b ^ c) ^ d) + x + ac; + // a = Integer.rotateLeft(a, s) + b; + void md5_HH(BufRegCache& reg_cache, + Register a, Register b, Register c, Register d, + int k, int s, int t, + Register rtmp1, Register rtmp2) { + // rtmp1 = (b ^ c) ^ d + __ xorr(rtmp2, b, c); + __ xorr(rtmp1, rtmp2, d); + + m5_FF_GG_HH_II_epilogue(reg_cache, a, b, c, d, k, s, t, rtmp1); + } + + // a += (c ^ (b | (~d))) + x + ac; + // a = Integer.rotateLeft(a, s) + b; + void md5_II(BufRegCache& reg_cache, + Register a, Register b, Register c, Register d, + int k, int s, int t, + Register rtmp1, Register rtmp2) { + // rtmp1 = c ^ (b | (~d)) + __ orn(rtmp2, b, d); + __ xorr(rtmp1, c, rtmp2); + + m5_FF_GG_HH_II_epilogue(reg_cache, a, b, c, d, k, s, t, rtmp1); + } + + // Arguments: + // + // Inputs: + // c_rarg0 - byte[] source+offset + // c_rarg1 - int[] SHA.state + // c_rarg2 - int offset (multi_block == True) + // c_rarg3 - int limit (multi_block == True) + // + // Registers: + // x0 zero (zero) + // x1 ra (return address) + // x2 sp (stack pointer) + // x3 gp (global pointer) + // x4 tp (thread pointer) + // x5 t0 (tmp register) + // x6 t1 (tmp register) + // x7 t2 state0 + // x8 f0/s0 (frame pointer) + // x9 s1 + // x10 a0 rtmp1 / c_rarg0 + // x11 a1 rtmp2 / c_rarg1 + // x12 a2 a / c_rarg2 + // x13 a3 b / c_rarg3 + // x14 a4 c + // x15 a5 d + // x16 a6 buf + // x17 a7 state + // x18 s2 ofs [saved-reg] (multi_block == True) + // x19 s3 limit [saved-reg] (multi_block == True) + // x20 s4 state1 [saved-reg] + // x21 s5 state2 [saved-reg] + // x22 s6 state3 [saved-reg] + // x23 s7 + // x24 s8 buf0 [saved-reg] + // x25 s9 buf1 [saved-reg] + // x26 s10 buf2 [saved-reg] + // x27 s11 buf3 [saved-reg] + // x28 t3 buf4 + // x29 t4 buf5 + // x30 t5 buf6 + // x31 t6 buf7 + address generate_md5_implCompress(bool multi_block, const char *name) { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ pc(); + + // rotation constants + const int S11 = 7; + const int S12 = 12; + const int S13 = 17; + const int S14 = 22; + const int S21 = 5; + const int S22 = 9; + const int S23 = 14; + const int S24 = 20; + const int S31 = 4; + const int S32 = 11; + const int S33 = 16; + const int S34 = 23; + const int S41 = 6; + const int S42 = 10; + const int S43 = 15; + const int S44 = 21; + + const int64_t mask32 = 0xffffffff; + + Register buf_arg = c_rarg0; // a0 + Register state_arg = c_rarg1; // a1 + Register ofs_arg = c_rarg2; // a2 + Register limit_arg = c_rarg3; // a3 + + // we'll copy the args to these registers to free up a0-a3 + // to use for other values manipulated by instructions + // that can be compressed + Register buf = x16; // a6 + Register state = x17; // a7 + Register ofs = x18; // s2 + Register limit = x19; // s3 + + // using x12->15 to allow compressed instructions + Register a = x12; // a2 + Register b = x13; // a3 + Register c = x14; // a4 + Register d = x15; // a5 + + Register state0 = x7; // t2 + Register state1 = x20; // s4 + Register state2 = x21; // s5 + Register state3 = x22; // s6 + + // using x10->x11 to allow compressed instructions + Register rtmp1 = x10; // a0 + Register rtmp2 = x11; // a1 + + RegSet reg_cache_saved_regs = RegSet::of(x24, x25, x26, x27); // s8, s9, s10, s11 + RegSet reg_cache_regs; + reg_cache_regs += reg_cache_saved_regs; + reg_cache_regs += RegSet::of(x28, x29, x30, x31); // t3, t4, t5, t6 + BufRegCache reg_cache(_masm, reg_cache_regs); + + RegSet saved_regs; + if (multi_block) { + saved_regs += RegSet::of(ofs, limit); + } + saved_regs += RegSet::of(state1, state2, state3); + saved_regs += reg_cache_saved_regs; + + __ push_reg(saved_regs, sp); + + __ mv(buf, buf_arg); + __ mv(state, state_arg); + if (multi_block) { + __ mv(ofs, ofs_arg); + __ mv(limit, limit_arg); + } + + // to minimize the number of memory operations: + // read the 4 state 4-byte values in pairs, with a single ld, + // and split them into 2 registers + __ mv(t0, mask32); + __ ld(state0, Address(state)); + __ srli(state1, state0, 32); + __ andr(state0, state0, t0); + __ ld(state2, Address(state, 8)); + __ srli(state3, state2, 32); + __ andr(state2, state2, t0); + + Label md5_loop; + __ BIND(md5_loop); + + __ mv(a, state0); + __ mv(b, state1); + __ mv(c, state2); + __ mv(d, state3); + + // Round 1 + reg_cache.gen_load(0, buf); + md5_FF(reg_cache, a, b, c, d, 0, S11, 0xd76aa478, rtmp1, rtmp2); + md5_FF(reg_cache, d, a, b, c, 1, S12, 0xe8c7b756, rtmp1, rtmp2); + reg_cache.gen_load(1, buf); + md5_FF(reg_cache, c, d, a, b, 2, S13, 0x242070db, rtmp1, rtmp2); + md5_FF(reg_cache, b, c, d, a, 3, S14, 0xc1bdceee, rtmp1, rtmp2); + reg_cache.gen_load(2, buf); + md5_FF(reg_cache, a, b, c, d, 4, S11, 0xf57c0faf, rtmp1, rtmp2); + md5_FF(reg_cache, d, a, b, c, 5, S12, 0x4787c62a, rtmp1, rtmp2); + reg_cache.gen_load(3, buf); + md5_FF(reg_cache, c, d, a, b, 6, S13, 0xa8304613, rtmp1, rtmp2); + md5_FF(reg_cache, b, c, d, a, 7, S14, 0xfd469501, rtmp1, rtmp2); + reg_cache.gen_load(4, buf); + md5_FF(reg_cache, a, b, c, d, 8, S11, 0x698098d8, rtmp1, rtmp2); + md5_FF(reg_cache, d, a, b, c, 9, S12, 0x8b44f7af, rtmp1, rtmp2); + reg_cache.gen_load(5, buf); + md5_FF(reg_cache, c, d, a, b, 10, S13, 0xffff5bb1, rtmp1, rtmp2); + md5_FF(reg_cache, b, c, d, a, 11, S14, 0x895cd7be, rtmp1, rtmp2); + reg_cache.gen_load(6, buf); + md5_FF(reg_cache, a, b, c, d, 12, S11, 0x6b901122, rtmp1, rtmp2); + md5_FF(reg_cache, d, a, b, c, 13, S12, 0xfd987193, rtmp1, rtmp2); + reg_cache.gen_load(7, buf); + md5_FF(reg_cache, c, d, a, b, 14, S13, 0xa679438e, rtmp1, rtmp2); + md5_FF(reg_cache, b, c, d, a, 15, S14, 0x49b40821, rtmp1, rtmp2); + + // Round 2 + md5_GG(reg_cache, a, b, c, d, 1, S21, 0xf61e2562, rtmp1, rtmp2); + md5_GG(reg_cache, d, a, b, c, 6, S22, 0xc040b340, rtmp1, rtmp2); + md5_GG(reg_cache, c, d, a, b, 11, S23, 0x265e5a51, rtmp1, rtmp2); + md5_GG(reg_cache, b, c, d, a, 0, S24, 0xe9b6c7aa, rtmp1, rtmp2); + md5_GG(reg_cache, a, b, c, d, 5, S21, 0xd62f105d, rtmp1, rtmp2); + md5_GG(reg_cache, d, a, b, c, 10, S22, 0x02441453, rtmp1, rtmp2); + md5_GG(reg_cache, c, d, a, b, 15, S23, 0xd8a1e681, rtmp1, rtmp2); + md5_GG(reg_cache, b, c, d, a, 4, S24, 0xe7d3fbc8, rtmp1, rtmp2); + md5_GG(reg_cache, a, b, c, d, 9, S21, 0x21e1cde6, rtmp1, rtmp2); + md5_GG(reg_cache, d, a, b, c, 14, S22, 0xc33707d6, rtmp1, rtmp2); + md5_GG(reg_cache, c, d, a, b, 3, S23, 0xf4d50d87, rtmp1, rtmp2); + md5_GG(reg_cache, b, c, d, a, 8, S24, 0x455a14ed, rtmp1, rtmp2); + md5_GG(reg_cache, a, b, c, d, 13, S21, 0xa9e3e905, rtmp1, rtmp2); + md5_GG(reg_cache, d, a, b, c, 2, S22, 0xfcefa3f8, rtmp1, rtmp2); + md5_GG(reg_cache, c, d, a, b, 7, S23, 0x676f02d9, rtmp1, rtmp2); + md5_GG(reg_cache, b, c, d, a, 12, S24, 0x8d2a4c8a, rtmp1, rtmp2); + + // Round 3 + md5_HH(reg_cache, a, b, c, d, 5, S31, 0xfffa3942, rtmp1, rtmp2); + md5_HH(reg_cache, d, a, b, c, 8, S32, 0x8771f681, rtmp1, rtmp2); + md5_HH(reg_cache, c, d, a, b, 11, S33, 0x6d9d6122, rtmp1, rtmp2); + md5_HH(reg_cache, b, c, d, a, 14, S34, 0xfde5380c, rtmp1, rtmp2); + md5_HH(reg_cache, a, b, c, d, 1, S31, 0xa4beea44, rtmp1, rtmp2); + md5_HH(reg_cache, d, a, b, c, 4, S32, 0x4bdecfa9, rtmp1, rtmp2); + md5_HH(reg_cache, c, d, a, b, 7, S33, 0xf6bb4b60, rtmp1, rtmp2); + md5_HH(reg_cache, b, c, d, a, 10, S34, 0xbebfbc70, rtmp1, rtmp2); + md5_HH(reg_cache, a, b, c, d, 13, S31, 0x289b7ec6, rtmp1, rtmp2); + md5_HH(reg_cache, d, a, b, c, 0, S32, 0xeaa127fa, rtmp1, rtmp2); + md5_HH(reg_cache, c, d, a, b, 3, S33, 0xd4ef3085, rtmp1, rtmp2); + md5_HH(reg_cache, b, c, d, a, 6, S34, 0x04881d05, rtmp1, rtmp2); + md5_HH(reg_cache, a, b, c, d, 9, S31, 0xd9d4d039, rtmp1, rtmp2); + md5_HH(reg_cache, d, a, b, c, 12, S32, 0xe6db99e5, rtmp1, rtmp2); + md5_HH(reg_cache, c, d, a, b, 15, S33, 0x1fa27cf8, rtmp1, rtmp2); + md5_HH(reg_cache, b, c, d, a, 2, S34, 0xc4ac5665, rtmp1, rtmp2); + + // Round 4 + md5_II(reg_cache, a, b, c, d, 0, S41, 0xf4292244, rtmp1, rtmp2); + md5_II(reg_cache, d, a, b, c, 7, S42, 0x432aff97, rtmp1, rtmp2); + md5_II(reg_cache, c, d, a, b, 14, S43, 0xab9423a7, rtmp1, rtmp2); + md5_II(reg_cache, b, c, d, a, 5, S44, 0xfc93a039, rtmp1, rtmp2); + md5_II(reg_cache, a, b, c, d, 12, S41, 0x655b59c3, rtmp1, rtmp2); + md5_II(reg_cache, d, a, b, c, 3, S42, 0x8f0ccc92, rtmp1, rtmp2); + md5_II(reg_cache, c, d, a, b, 10, S43, 0xffeff47d, rtmp1, rtmp2); + md5_II(reg_cache, b, c, d, a, 1, S44, 0x85845dd1, rtmp1, rtmp2); + md5_II(reg_cache, a, b, c, d, 8, S41, 0x6fa87e4f, rtmp1, rtmp2); + md5_II(reg_cache, d, a, b, c, 15, S42, 0xfe2ce6e0, rtmp1, rtmp2); + md5_II(reg_cache, c, d, a, b, 6, S43, 0xa3014314, rtmp1, rtmp2); + md5_II(reg_cache, b, c, d, a, 13, S44, 0x4e0811a1, rtmp1, rtmp2); + md5_II(reg_cache, a, b, c, d, 4, S41, 0xf7537e82, rtmp1, rtmp2); + md5_II(reg_cache, d, a, b, c, 11, S42, 0xbd3af235, rtmp1, rtmp2); + md5_II(reg_cache, c, d, a, b, 2, S43, 0x2ad7d2bb, rtmp1, rtmp2); + md5_II(reg_cache, b, c, d, a, 9, S44, 0xeb86d391, rtmp1, rtmp2); + + __ addw(state0, state0, a); + __ addw(state1, state1, b); + __ addw(state2, state2, c); + __ addw(state3, state3, d); + + if (multi_block) { + __ addi(buf, buf, 64); + __ addi(ofs, ofs, 64); + // if (ofs <= limit) goto m5_loop + __ bge(limit, ofs, md5_loop); + __ mv(c_rarg0, ofs); // return ofs + } + + // to minimize the number of memory operations: + // write back the 4 state 4-byte values in pairs, with a single sd + __ mv(t0, mask32); + __ andr(state0, state0, t0); + __ slli(state1, state1, 32); + __ orr(state0, state0, state1); + __ sd(state0, Address(state)); + __ andr(state2, state2, t0); + __ slli(state3, state3, 32); + __ orr(state2, state2, state3); + __ sd(state2, Address(state, 8)); + + __ pop_reg(saved_regs, sp); + __ ret(); + + return (address) start; + } + #if INCLUDE_JFR static void jfr_prologue(address the_pc, MacroAssembler* _masm, Register thread) { @@ -4164,6 +4532,11 @@ class StubGenerator: public StubCodeGenerator { generate_compare_long_strings(); generate_string_indexof_stubs(); + + if (UseMD5Intrinsics) { + StubRoutines::_md5_implCompress = generate_md5_implCompress(false, "md5_implCompress"); + StubRoutines::_md5_implCompressMB = generate_md5_implCompress(true, "md5_implCompressMB"); + } #endif // COMPILER2_OR_JVMCI } diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index 6c9174da53b16..1bcc761d06f1e 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -600,7 +600,7 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { // monitor entry size: see picture of stack set // (generate_method_entry) and frame_amd64.hpp - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); // total overhead size: entry_size + (saved fp through expr stack // bottom). be sure to change this if you add/subtract anything @@ -673,7 +673,7 @@ void TemplateInterpreterGenerator::lock_method() { // synchronize method const Address access_flags(xmethod, Method::access_flags_offset()); const Address monitor_block_top(fp, frame::interpreter_frame_monitor_block_top_offset * wordSize); - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); #ifdef ASSERT __ lwu(x10, access_flags); diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index b8d176d0d4503..22e2531a83ad0 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -3739,7 +3739,7 @@ void TemplateTable::monitorenter() { fp, frame::interpreter_frame_monitor_block_top_offset * wordSize); const Address monitor_block_bot( fp, frame::interpreter_frame_initial_sp_offset * wordSize); - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); Label allocated; @@ -3837,7 +3837,7 @@ void TemplateTable::monitorexit() { fp, frame::interpreter_frame_monitor_block_top_offset * wordSize); const Address monitor_block_bot( fp, frame::interpreter_frame_initial_sp_offset * wordSize); - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); Label found; diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index ddddb6df3bcee..4ad0b16b6236d 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -171,9 +171,13 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); } - if (UseMD5Intrinsics) { - warning("MD5 intrinsics are not available on this CPU."); - FLAG_SET_DEFAULT(UseMD5Intrinsics, false); + if (UseVectorizedMismatchIntrinsic) { + warning("VectorizedMismatch intrinsic is not available on this CPU."); + FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); + } + + if (FLAG_IS_DEFAULT(UseMD5Intrinsics)) { + FLAG_SET_DEFAULT(UseMD5Intrinsics, true); } if (UseRVV) { @@ -261,8 +265,8 @@ void VM_Version::c2_initialize() { if (MaxVectorSize > _initial_vector_length) { warning("Current system only supports max RVV vector length %d. Set MaxVectorSize to %d", _initial_vector_length, _initial_vector_length); + MaxVectorSize = _initial_vector_length; } - MaxVectorSize = _initial_vector_length; } else { vm_exit_during_initialization(err_msg("Unsupported MaxVectorSize: %d", (int)MaxVectorSize)); } diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp index 6d9ea5c2ac33a..93ebd9e4e7dc3 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -201,6 +201,9 @@ class VM_Version : public Abstract_VM_Version { constexpr static bool supports_stack_watermark_barrier() { return true; } static bool supports_on_spin_wait() { return UseZihintpause; } + + // RISCV64 supports fast class initialization checks + static bool supports_fast_class_init_checks() { return true; } }; #endif // CPU_RISCV_VM_VERSION_RISCV_HPP diff --git a/src/hotspot/cpu/s390/assembler_s390.hpp b/src/hotspot/cpu/s390/assembler_s390.hpp index 5762161662dbc..0df4d10d47d32 100644 --- a/src/hotspot/cpu/s390/assembler_s390.hpp +++ b/src/hotspot/cpu/s390/assembler_s390.hpp @@ -140,7 +140,8 @@ class RelAddr { if ((target == nullptr) || (target == pc)) { return 0; // Yet unknown branch destination. } else { - guarantee(is_in_range_of_RelAddr(target, pc, shortForm), "target not within reach"); + guarantee(is_in_range_of_RelAddr(target, pc, shortForm), + "target not within reach at " INTPTR_FORMAT ", distance = " INTX_FORMAT, p2i(pc), (target - pc) ); return (int)((target - pc)>>1); } } diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp index 02b1e730c59e8..40edca6559aa4 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016 SAP SE. All rights reserved. + * Copyright (c) 2016, 2023 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 @@ -83,60 +83,63 @@ void C1_MacroAssembler::verified_entry(bool breakAtEntry) { if (breakAtEntry) z_illtrap(0xC1); } -void C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { +void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case) { const int hdr_offset = oopDesc::mark_offset_in_bytes(); - assert_different_registers(hdr, obj, disp_hdr); - verify_oop(obj, FILE_AND_LINE); + const Register tmp = Z_R1_scratch; + + assert_different_registers(Rmark, Roop, Rbox, tmp); + + verify_oop(Roop, FILE_AND_LINE); // Load object header. - z_lg(hdr, Address(obj, hdr_offset)); + z_lg(Rmark, Address(Roop, hdr_offset)); // Save object being locked into the BasicObjectLock... - z_stg(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + z_stg(Roop, Address(Rbox, BasicObjectLock::obj_offset())); if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(Z_R1_scratch, obj); - testbit(Address(Z_R1_scratch, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); - z_btrue(slow_case); + load_klass(tmp, Roop); + testbit(Address(tmp, Klass::access_flags_offset()), exact_log2(JVM_ACC_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) { - Unimplemented(); + lightweight_lock(Roop, Rmark, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { NearLabel done; // and mark it as unlocked. - z_oill(hdr, markWord::unlocked_value); + z_oill(Rmark, markWord::unlocked_value); // Save unlocked object header into the displaced header location on the stack. - z_stg(hdr, Address(disp_hdr, (intptr_t) 0)); + z_stg(Rmark, Address(Rbox, BasicLock::displaced_header_offset_in_bytes())); // Test if object header is still the same (i.e. unlocked), and if so, store the // displaced header address in the object header. If it is not the same, get the // object header instead. - z_csg(hdr, disp_hdr, hdr_offset, obj); + z_csg(Rmark, Rbox, hdr_offset, Roop); // If the object header was the same, we're done. branch_optimized(Assembler::bcondEqual, done); - // If the object header was not the same, it is now in the hdr register. + // If the object header was not the same, it is now in the Rmark register. // => Test if it is a stack pointer into the same stack (recursive locking), i.e.: // - // 1) (hdr & markWord::lock_mask_in_place) == 0 - // 2) rsp <= hdr - // 3) hdr <= rsp + page_size + // 1) (Rmark & markWord::lock_mask_in_place) == 0 + // 2) rsp <= Rmark + // 3) Rmark <= rsp + page_size // // These 3 tests can be done by evaluating the following expression: // - // (hdr - Z_SP) & (~(page_size-1) | markWord::lock_mask_in_place) + // (Rmark - Z_SP) & (~(page_size-1) | markWord::lock_mask_in_place) // // assuming both the stack pointer and page_size have their least // significant 2 bits cleared and page_size is a power of 2 - z_sgr(hdr, Z_SP); + z_sgr(Rmark, Z_SP); load_const_optimized(Z_R0_scratch, (~(os::vm_page_size() - 1) | markWord::lock_mask_in_place)); - z_ngr(hdr, Z_R0_scratch); // AND sets CC (result eq/ne 0). + z_ngr(Rmark, Z_R0_scratch); // AND sets CC (result eq/ne 0). // For recursive locking, the result is zero. => Save it in the displaced header - // location (null in the displaced hdr location indicates recursive locking). - z_stg(hdr, Address(disp_hdr, (intptr_t) 0)); + // location (null in the displaced Rmark location indicates recursive locking). + z_stg(Rmark, Address(Rbox, BasicLock::displaced_header_offset_in_bytes())); // Otherwise we don't care about the result and handle locking via runtime call. branch_optimized(Assembler::bcondNotZero, slow_case); // done @@ -144,35 +147,41 @@ void C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hd } } -void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { - const int aligned_mask = BytesPerWord -1; +void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case) { const int hdr_offset = oopDesc::mark_offset_in_bytes(); - assert_different_registers(hdr, obj, disp_hdr); + + assert_different_registers(Rmark, Roop, Rbox); + NearLabel done; if (LockingMode != LM_LIGHTWEIGHT) { // Load displaced header. - z_ltg(hdr, Address(disp_hdr, (intptr_t) 0)); - // If the loaded hdr is null we had recursive locking, and we are done. + z_ltg(Rmark, Address(Rbox, BasicLock::displaced_header_offset_in_bytes())); + // If the loaded Rmark is null we had recursive locking, and we are done. z_bre(done); } // Load object. - z_lg(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); - verify_oop(obj, FILE_AND_LINE); + z_lg(Roop, Address(Rbox, BasicObjectLock::obj_offset())); + verify_oop(Roop, FILE_AND_LINE); if (LockingMode == LM_LIGHTWEIGHT) { - Unimplemented(); - } else { + const Register tmp = Z_R1_scratch; + z_lg(Rmark, Address(Roop, hdr_offset)); + z_lgr(tmp, Rmark); + z_nill(tmp, markWord::monitor_value); + branch_optimized(Assembler::bcondNotZero, slow_case); + lightweight_unlock(Roop, Rmark, tmp, slow_case); + } else if (LockingMode == LM_LEGACY) { // Test if object header is pointing to the displaced header, and if so, restore // the displaced header in the object. If the object header is not pointing to // the displaced header, get the object header instead. - z_csg(disp_hdr, hdr, hdr_offset, obj); + z_csg(Rbox, Rmark, hdr_offset, Roop); // If the object header was not pointing to the displaced header, // we do unlocking via runtime call. branch_optimized(Assembler::bcondNotEqual, slow_case); - // done } + // done bind(done); } diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.hpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.hpp index 1ff914b7b71d5..7a4f76af1546e 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016 SAP SE. All rights reserved. + * Copyright (c) 2016, 2023 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,17 +41,18 @@ void initialize_body(Register objectFields, Register len_in_bytes, Register Rzero); // locking - // hdr : Used to hold locked markWord to be CASed into obj, contents destroyed. - // obj : Must point to the object to lock, contents preserved. - // disp_hdr: Must point to the displaced header location, contents preserved. - // Returns code offset at which to add null check debug information. - void lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case); + // Rmark : Used to hold locked markWord to be CASed into obj, contents destroyed. + // Roop : Must point to the object to lock, contents preserved. + // Rbox : Must point to the displaced header location, contents preserved. + // Z_R1_scratch : Used as temp and will be killed + void lock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case); // unlocking - // hdr : Used to hold original markWord to be CASed back into obj, contents destroyed. - // obj : Must point to the object to lock, contents preserved. - // disp_hdr: Must point to the displaced header location, contents destroyed. - void unlock_object(Register hdr, Register obj, Register lock, Label& slow_case); + // Rmark : Used to hold original markWord to be CASed back into obj, contents destroyed. + // Roop : Must point to the object to lock, contents preserved. + // Rbox : Must point to the displaced header location, contents destroyed. + // Z_R1_scratch : Used as temp and will be killed + void unlock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case); void initialize_object( Register obj, // result: Pointer to object after successful allocation. diff --git a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp index 28acb398c1faa..257148827be4e 100644 --- a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp +++ b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp @@ -233,6 +233,12 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) { // Other registers used in this stub. const Register handler_addr = Z_R4; + if (AbortVMOnException) { + save_live_registers(sasm); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, check_abort_on_vm_exception), Z_EXC_OOP); + restore_live_registers(sasm); + } + // Verify that only exception_oop, is valid at this time. __ invalidate_registers(Z_EXC_OOP, Z_EXC_PC); diff --git a/src/hotspot/cpu/s390/downcallLinker_s390.cpp b/src/hotspot/cpu/s390/downcallLinker_s390.cpp index baee7d7a043d7..f831da9075599 100644 --- a/src/hotspot/cpu/s390/downcallLinker_s390.cpp +++ b/src/hotspot/cpu/s390/downcallLinker_s390.cpp @@ -23,8 +23,76 @@ */ #include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "code/codeBlob.hpp" +#include "code/codeCache.hpp" +#include "code/vmreg.inline.hpp" +#include "compiler/oopMap.hpp" +#include "logging/logStream.hpp" +#include "memory/resourceArea.hpp" #include "prims/downcallLinker.hpp" -#include "utilities/debug.hpp" +#include "runtime/globals.hpp" +#include "runtime/stubCodeGenerator.hpp" + +#define __ _masm-> + +class DowncallStubGenerator : public StubCodeGenerator { + BasicType* _signature; + int _num_args; + BasicType _ret_bt; + const ABIDescriptor& _abi; + + const GrowableArray& _input_registers; + const GrowableArray& _output_registers; + + bool _needs_return_buffer; + int _captured_state_mask; + bool _needs_transition; + + int _frame_complete; + int _frame_size_slots; + OopMapSet* _oop_maps; + public: + DowncallStubGenerator(CodeBuffer* buffer, + BasicType* signature, + int num_args, + BasicType ret_bt, + const ABIDescriptor& abi, + const GrowableArray& input_registers, + const GrowableArray& output_registers, + bool needs_return_buffer, + int captured_state_mask, + bool needs_transition) + :StubCodeGenerator(buffer, PrintMethodHandleStubs), + _signature(signature), + _num_args(num_args), + _ret_bt(ret_bt), + _abi(abi), + _input_registers(input_registers), + _output_registers(output_registers), + _needs_return_buffer(needs_return_buffer), + _captured_state_mask(captured_state_mask), + _needs_transition(needs_transition), + _frame_complete(0), + _frame_size_slots(0), + _oop_maps(nullptr) { + } + void generate(); + int frame_complete() const { + return _frame_complete; + } + + int framesize() const { + return (_frame_size_slots >> (LogBytesPerWord - LogBytesPerInt)); + } + + OopMapSet* oop_maps() const { + return _oop_maps; + } +}; + +static const int native_invoker_code_base_size = 512; +static const int native_invoker_size_per_args = 8; RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature, int num_args, @@ -35,6 +103,197 @@ RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature, bool needs_return_buffer, int captured_state_mask, bool needs_transition) { - Unimplemented(); - return nullptr; + + int code_size = native_invoker_code_base_size + (num_args * native_invoker_size_per_args); + int locs_size = 1; //must be non zero + CodeBuffer code("nep_invoker_blob", code_size, locs_size); + + DowncallStubGenerator g(&code, signature, num_args, ret_bt, abi, + input_registers, output_registers, + needs_return_buffer, captured_state_mask, + needs_transition); + g.generate(); + code.log_section_sizes("nep_invoker_blob"); + + RuntimeStub* stub = + RuntimeStub::new_runtime_stub("nep_invoker_blob", + &code, + g.frame_complete(), + g.framesize(), + g.oop_maps(), false); + +#ifndef PRODUCT + LogTarget(Trace, foreign, downcall) lt; + if (lt.is_enabled()) { + ResourceMark rm; + LogStream ls(lt); + stub->print_on(&ls); + } +#endif + + return stub; +} + +void DowncallStubGenerator::generate() { + Register call_target_address = Z_R1_scratch, + tmp = Z_R0_scratch; + + VMStorage shuffle_reg = _abi._scratch1; + + JavaCallingConvention in_conv; + NativeCallingConvention out_conv(_input_registers); + ArgumentShuffle arg_shuffle(_signature, _num_args, _signature, _num_args, &in_conv, &out_conv, shuffle_reg); + +#ifndef PRODUCT + LogTarget(Trace, foreign, downcall) lt; + if (lt.is_enabled()) { + ResourceMark rm; + LogStream ls(lt); + arg_shuffle.print_on(&ls); + } +#endif + + assert(_abi._shadow_space_bytes == frame::z_abi_160_size, "expected space according to ABI"); + int allocated_frame_size = _abi._shadow_space_bytes; + allocated_frame_size += arg_shuffle.out_arg_bytes(); + + assert(!_needs_return_buffer, "unexpected needs_return_buffer"); + RegSpiller out_reg_spiller(_output_registers); + int spill_offset = allocated_frame_size; + allocated_frame_size += BytesPerWord; + + StubLocations locs; + locs.set(StubLocations::TARGET_ADDRESS, _abi._scratch2); + + if (_captured_state_mask != 0) { + __ block_comment("{ _captured_state_mask is set"); + locs.set_frame_data(StubLocations::CAPTURED_STATE_BUFFER, allocated_frame_size); + allocated_frame_size += BytesPerWord; + __ block_comment("} _captured_state_mask is set"); + } + + allocated_frame_size = align_up(allocated_frame_size, StackAlignmentInBytes); + _frame_size_slots = allocated_frame_size >> LogBytesPerInt; + + _oop_maps = _needs_transition ? new OopMapSet() : nullptr; + address start = __ pc(); + + __ save_return_pc(); + __ push_frame(allocated_frame_size, Z_R11); // Create a new frame for the wrapper. + + _frame_complete = __ pc() - start; // frame build complete. + + if (_needs_transition) { + __ block_comment("{ thread java2native"); + __ get_PC(Z_R1_scratch); + address the_pc = __ pc(); + __ set_last_Java_frame(Z_SP, Z_R1_scratch); + + OopMap* map = new OopMap(_frame_size_slots, 0); + _oop_maps->add_gc_map(the_pc - start, map); + + // State transition + __ set_thread_state(_thread_in_native); + __ block_comment("} thread java2native"); + } + __ block_comment("{ argument shuffle"); + arg_shuffle.generate(_masm, shuffle_reg, frame::z_jit_out_preserve_size, _abi._shadow_space_bytes, locs); + __ block_comment("} argument shuffle"); + + __ call(as_Register(locs.get(StubLocations::TARGET_ADDRESS))); + + ////////////////////////////////////////////////////////////////////////////// + + if (_captured_state_mask != 0) { + __ block_comment("{ save thread local"); + + out_reg_spiller.generate_spill(_masm, spill_offset); + + __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, DowncallLinker::capture_state)); + __ z_lg(Z_ARG1, Address(Z_SP, locs.data_offset(StubLocations::CAPTURED_STATE_BUFFER))); + __ load_const_optimized(Z_ARG2, _captured_state_mask); + __ call(call_target_address); + + out_reg_spiller.generate_fill(_masm, spill_offset); + + __ block_comment("} save thread local"); + } + + ////////////////////////////////////////////////////////////////////////////// + + Label L_after_safepoint_poll; + Label L_safepoint_poll_slow_path; + Label L_reguard; + Label L_after_reguard; + + if (_needs_transition) { + __ block_comment("{ thread native2java"); + __ set_thread_state(_thread_in_native_trans); + + if (!UseSystemMemoryBarrier) { + __ z_fence(); // Order state change wrt. safepoint poll. + } + + __ safepoint_poll(L_safepoint_poll_slow_path, tmp); + + __ load_and_test_int(tmp, Address(Z_thread, JavaThread::suspend_flags_offset())); + __ z_brne(L_safepoint_poll_slow_path); + + __ bind(L_after_safepoint_poll); + + // change thread state + __ set_thread_state(_thread_in_Java); + + __ block_comment("reguard stack check"); + __ z_cli(Address(Z_thread, JavaThread::stack_guard_state_offset() + in_ByteSize(sizeof(StackOverflow::StackGuardState) - 1)), + StackOverflow::stack_guard_yellow_reserved_disabled); + __ z_bre(L_reguard); + __ bind(L_after_reguard); + + __ reset_last_Java_frame(); + __ block_comment("} thread native2java"); + } + + __ pop_frame(); + __ restore_return_pc(); // This is the way back to the caller. + __ z_br(Z_R14); + + ////////////////////////////////////////////////////////////////////////////// + + if (_needs_transition) { + __ block_comment("{ L_safepoint_poll_slow_path"); + __ bind(L_safepoint_poll_slow_path); + + // Need to save the native result registers around any runtime calls. + out_reg_spiller.generate_spill(_masm, spill_offset); + + __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, JavaThread::check_special_condition_for_native_trans)); + __ z_lgr(Z_ARG1, Z_thread); + __ call(call_target_address); + + out_reg_spiller.generate_fill(_masm, spill_offset); + + __ z_bru(L_after_safepoint_poll); + __ block_comment("} L_safepoint_poll_slow_path"); + + ////////////////////////////////////////////////////////////////////////////// + __ block_comment("{ L_reguard"); + __ bind(L_reguard); + + // Need to save the native result registers around any runtime calls. + out_reg_spiller.generate_spill(_masm, spill_offset); + + __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, SharedRuntime::reguard_yellow_pages)); + __ call(call_target_address); + + out_reg_spiller.generate_fill(_masm, spill_offset); + + __ z_bru(L_after_reguard); + + __ block_comment("} L_reguard"); + } + + ////////////////////////////////////////////////////////////////////////////// + + __ flush(); } diff --git a/src/hotspot/cpu/s390/foreignGlobals_s390.cpp b/src/hotspot/cpu/s390/foreignGlobals_s390.cpp index d3a318536bd7b..9796ab4ffe4d8 100644 --- a/src/hotspot/cpu/s390/foreignGlobals_s390.cpp +++ b/src/hotspot/cpu/s390/foreignGlobals_s390.cpp @@ -23,34 +23,209 @@ */ #include "precompiled.hpp" -#include "code/vmreg.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "code/vmreg.inline.hpp" +#include "runtime/jniHandles.hpp" +#include "runtime/jniHandles.inline.hpp" +#include "oops/typeArrayOop.inline.hpp" +#include "oops/oopCast.inline.hpp" #include "prims/foreignGlobals.hpp" -#include "utilities/debug.hpp" +#include "prims/foreignGlobals.inline.hpp" +#include "prims/vmstorage.hpp" +#include "utilities/formatBuffer.hpp" -class MacroAssembler; +#define __ masm-> + +bool ABIDescriptor::is_volatile_reg(Register reg) const { + return _integer_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 false; + return true; } const ABIDescriptor ForeignGlobals::parse_abi_descriptor(jobject jabi) { - Unimplemented(); - return {}; + oop abi_oop = JNIHandles::resolve_non_null(jabi); + ABIDescriptor abi; + + objArrayOop inputStorage = jdk_internal_foreign_abi_ABIDescriptor::inputStorage(abi_oop); + parse_register_array(inputStorage, StorageType::INTEGER, abi._integer_argument_registers, as_Register); + parse_register_array(inputStorage, StorageType::FLOAT, abi._float_argument_registers, as_FloatRegister); + + objArrayOop outputStorage = jdk_internal_foreign_abi_ABIDescriptor::outputStorage(abi_oop); + 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_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); + + abi._scratch1 = parse_vmstorage(jdk_internal_foreign_abi_ABIDescriptor::scratch1(abi_oop)); + abi._scratch2 = parse_vmstorage(jdk_internal_foreign_abi_ABIDescriptor::scratch2(abi_oop)); + + return abi; } int RegSpiller::pd_reg_size(VMStorage reg) { - Unimplemented(); - return -1; + if (reg.type() == StorageType::INTEGER || reg.type() == StorageType::FLOAT) { + return 8; + } + return 0; // stack and BAD } void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMStorage reg) { - Unimplemented(); + if (reg.type() == StorageType::INTEGER) { + __ reg2mem_opt(as_Register(reg), Address(Z_SP, offset), true); + } else if (reg.type() == StorageType::FLOAT) { + __ freg2mem_opt(as_FloatRegister(reg), Address(Z_SP, offset), true); + } else { + // stack and BAD + } } void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMStorage reg) { - Unimplemented(); + if (reg.type() == StorageType::INTEGER) { + __ mem2reg_opt(as_Register(reg), Address(Z_SP, offset), true); + } else if (reg.type() == StorageType::FLOAT) { + __ mem2freg_opt(as_FloatRegister(reg), Address(Z_SP, offset), true); + } else { + // stack and BAD + } +} + +static int reg2offset(VMStorage vms, int stk_bias) { + assert(!vms.is_reg(), "wrong usage"); + return vms.index_or_offset() + stk_bias; +} + +static void move_reg(MacroAssembler* masm, int out_stk_bias, + VMStorage from_reg, VMStorage to_reg) { + int out_bias = 0; + switch (to_reg.type()) { + case StorageType::INTEGER: + if (to_reg.segment_mask() == REG64_MASK && from_reg.segment_mask() == REG32_MASK ) { + // see CCallingConventionRequiresIntsAsLongs + __ z_lgfr(as_Register(to_reg), as_Register(from_reg)); + } else { + __ lgr_if_needed(as_Register(to_reg), as_Register(from_reg)); + } + break; + case StorageType::STACK: + out_bias = out_stk_bias; //fallthrough + case StorageType::FRAME_DATA: { + // Integer types always get a 64 bit slot in C. + if (from_reg.segment_mask() == REG32_MASK) { + // see CCallingConventionRequiresIntsAsLongs + __ z_lgfr(as_Register(from_reg), as_Register(from_reg)); + } + switch (to_reg.stack_size()) { + case 8: __ reg2mem_opt(as_Register(from_reg), Address(Z_SP, reg2offset(to_reg, out_bias)), true); break; + case 4: __ reg2mem_opt(as_Register(from_reg), Address(Z_SP, reg2offset(to_reg, out_bias)), false); break; + default: ShouldNotReachHere(); + } + } break; + default: ShouldNotReachHere(); + } +} + +static void move_float(MacroAssembler* masm, int out_stk_bias, + VMStorage from_reg, VMStorage to_reg) { + switch (to_reg.type()) { + case StorageType::FLOAT: + if (from_reg.segment_mask() == REG64_MASK) + __ move_freg_if_needed(as_FloatRegister(to_reg), T_DOUBLE, as_FloatRegister(from_reg), T_DOUBLE); + else + __ move_freg_if_needed(as_FloatRegister(to_reg), T_FLOAT, as_FloatRegister(from_reg), T_FLOAT); + break; + case StorageType::STACK: + if (from_reg.segment_mask() == REG64_MASK) { + assert(to_reg.stack_size() == 8, "size should match"); + __ freg2mem_opt(as_FloatRegister(from_reg), Address(Z_SP, reg2offset(to_reg, out_stk_bias)), true); + } else { + assert(to_reg.stack_size() == 4, "size should match"); + __ freg2mem_opt(as_FloatRegister(from_reg), Address(Z_SP, reg2offset(to_reg, out_stk_bias)), false); + } + break; + default: ShouldNotReachHere(); + } +} + +static void move_stack(MacroAssembler* masm, Register tmp_reg, int in_stk_bias, int out_stk_bias, + VMStorage from_reg, VMStorage to_reg) { + int out_bias = 0; + Address from_addr(Z_R11, reg2offset(from_reg, in_stk_bias)); + switch (to_reg.type()) { + case StorageType::INTEGER: + switch (from_reg.stack_size()) { + case 8: __ mem2reg_opt(as_Register(to_reg), from_addr, true);break; + case 4: __ mem2reg_opt(as_Register(to_reg), from_addr, false);break; + default: ShouldNotReachHere(); + } + break; + case StorageType::FLOAT: + switch (from_reg.stack_size()) { + case 8: __ mem2freg_opt(as_FloatRegister(to_reg), from_addr, true);break; + case 4: __ mem2freg_opt(as_FloatRegister(to_reg), from_addr, false);break; + default: ShouldNotReachHere(); + } + break; + case StorageType::STACK: + out_bias = out_stk_bias; // fallthrough + case StorageType::FRAME_DATA: { + switch (from_reg.stack_size()) { + case 8: __ mem2reg_opt(tmp_reg, from_addr, true); break; + case 4: if (to_reg.stack_size() == 8) { + __ mem2reg_signed_opt(tmp_reg, from_addr); + } else { + __ mem2reg_opt(tmp_reg, from_addr, false); + } + break; + default: ShouldNotReachHere(); + } + switch (to_reg.stack_size()) { + case 8: __ reg2mem_opt(tmp_reg, Address (Z_SP, reg2offset(to_reg, out_bias)), true); break; + case 4: __ reg2mem_opt(tmp_reg, Address (Z_SP, reg2offset(to_reg, out_bias)), false); break; + default: ShouldNotReachHere(); + } + } break; + default: ShouldNotReachHere(); + } } void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMStorage tmp, int in_stk_bias, int out_stk_bias, const StubLocations& locs) const { - Unimplemented(); + Register tmp_reg = as_Register(tmp); + for (int i = 0; i < _moves.length(); i++) { + Move move = _moves.at(i); + VMStorage from_reg = move.from; + VMStorage to_reg = move.to; + + // replace any placeholders + if (from_reg.type() == StorageType::PLACEHOLDER) { + from_reg = locs.get(from_reg); + } + if (to_reg.type() == StorageType::PLACEHOLDER) { + to_reg = locs.get(to_reg); + } + + switch (from_reg.type()) { + case StorageType::INTEGER: + move_reg(masm, out_stk_bias, from_reg, to_reg); + break; + case StorageType::FLOAT: + move_float(masm, out_stk_bias, from_reg, to_reg); + break; + case StorageType::STACK: + move_stack(masm, tmp_reg, in_stk_bias, out_stk_bias, from_reg, to_reg); + break; + default: ShouldNotReachHere(); + } + } } diff --git a/src/hotspot/cpu/s390/foreignGlobals_s390.hpp b/src/hotspot/cpu/s390/foreignGlobals_s390.hpp index 8b86a2b06a601..4ff3b3e40b4ff 100644 --- a/src/hotspot/cpu/s390/foreignGlobals_s390.hpp +++ b/src/hotspot/cpu/s390/foreignGlobals_s390.hpp @@ -24,6 +24,23 @@ #ifndef CPU_S390_VM_FOREIGN_GLOBALS_S390_HPP #define CPU_S390_VM_FOREIGN_GLOBALS_S390_HPP -class ABIDescriptor {}; +struct ABIDescriptor { + GrowableArray _integer_argument_registers; + GrowableArray _integer_return_registers; + GrowableArray _float_argument_registers; + GrowableArray _float_return_registers; + + GrowableArray _integer_volatile_registers; + GrowableArray _float_additional_volatile_registers; + + int32_t _stack_alignment_bytes; + int32_t _shadow_space_bytes; + + VMStorage _scratch1; + VMStorage _scratch2; + + bool is_volatile_reg(Register reg) const; + bool is_volatile_reg(FloatRegister reg) const; +}; #endif // CPU_S390_VM_FOREIGN_GLOBALS_S390_HPP diff --git a/src/hotspot/cpu/s390/frame_s390.cpp b/src/hotspot/cpu/s390/frame_s390.cpp index 23547fa6617b4..dbaa243eb1cac 100644 --- a/src/hotspot/cpu/s390/frame_s390.cpp +++ b/src/hotspot/cpu/s390/frame_s390.cpp @@ -218,13 +218,32 @@ frame frame::sender_for_entry_frame(RegisterMap *map) const { } UpcallStub::FrameData* UpcallStub::frame_data_for_frame(const frame& frame) const { - ShouldNotCallThis(); - return nullptr; + assert(frame.is_upcall_stub_frame(), "wrong frame"); + // need unextended_sp here, since normal sp is wrong for interpreter callees + return reinterpret_cast( + reinterpret_cast
(frame.unextended_sp()) + in_bytes(_frame_data_offset)); } bool frame::upcall_stub_frame_is_first() const { - ShouldNotCallThis(); - return false; + assert(is_upcall_stub_frame(), "must be optimized entry frame"); + UpcallStub* blob = _cb->as_upcall_stub(); + JavaFrameAnchor* jfa = blob->jfa_for_frame(*this); + return jfa->last_Java_sp() == nullptr; +} + +frame frame::sender_for_upcall_stub_frame(RegisterMap* map) const { + assert(map != nullptr, "map must be set"); + UpcallStub* blob = _cb->as_upcall_stub(); + // Java frame called from C; skip all C frames and return top C + // frame of that chunk as the sender + JavaFrameAnchor* jfa = blob->jfa_for_frame(*this); + assert(!upcall_stub_frame_is_first(), "must have a frame anchor to go back to"); + assert(jfa->last_Java_sp() > sp(), "must be above this frame on stack"); + map->clear(); + assert(map->include_argument_oops(), "should be set by clear"); + frame fr(jfa->last_Java_sp(), jfa->last_Java_pc()); + + return fr; } frame frame::sender_for_interpreter_frame(RegisterMap *map) const { @@ -653,7 +672,6 @@ intptr_t *frame::initial_deoptimization_info() { return fp(); } -// Pointer beyond the "oldest/deepest" BasicObjectLock on stack. BasicObjectLock* frame::interpreter_frame_monitor_end() const { return interpreter_frame_monitors(); } diff --git a/src/hotspot/cpu/s390/frame_s390.hpp b/src/hotspot/cpu/s390/frame_s390.hpp index 85ce9c023e3da..3f81cd254d080 100644 --- a/src/hotspot/cpu/s390/frame_s390.hpp +++ b/src/hotspot/cpu/s390/frame_s390.hpp @@ -488,11 +488,6 @@ template static void update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr); - // Additional interface for interpreter frames: - static int interpreter_frame_interpreterstate_size_in_bytes(); - static int interpreter_frame_monitor_size_in_bytes(); - - // template interpreter state inline z_ijava_state* ijava_state_unchecked() const; diff --git a/src/hotspot/cpu/s390/frame_s390.inline.hpp b/src/hotspot/cpu/s390/frame_s390.inline.hpp index dfa68940bac5c..008c4b182f88f 100644 --- a/src/hotspot/cpu/s390/frame_s390.inline.hpp +++ b/src/hotspot/cpu/s390/frame_s390.inline.hpp @@ -254,15 +254,6 @@ inline int frame::interpreter_frame_monitor_size() { WordsPerLong /* Number of stack slots for a Java long. */); } -inline int frame::interpreter_frame_monitor_size_in_bytes() { - // Number of bytes for a monitor. - return frame::interpreter_frame_monitor_size() * wordSize; -} - -inline int frame::interpreter_frame_interpreterstate_size_in_bytes() { - return z_ijava_state_size; -} - inline Method** frame::interpreter_frame_method_addr() const { return (Method**)&(ijava_state()->method); } @@ -352,12 +343,10 @@ inline frame frame::sender(RegisterMap* map) const { // update it accordingly. map->set_include_argument_oops(false); - if (is_entry_frame()) { - return sender_for_entry_frame(map); - } - if (is_interpreted_frame()) { - return sender_for_interpreter_frame(map); - } + if (is_entry_frame()) return sender_for_entry_frame(map); + if (is_upcall_stub_frame()) return sender_for_upcall_stub_frame(map); + if (is_interpreted_frame()) return sender_for_interpreter_frame(map); + assert(_cb == CodeCache::find_blob(pc()),"Must be the same"); if (_cb != nullptr) return sender_for_compiled_frame(map); diff --git a/src/hotspot/cpu/s390/globalDefinitions_s390.hpp b/src/hotspot/cpu/s390/globalDefinitions_s390.hpp index 99906bb369e54..2232215a5875f 100644 --- a/src/hotspot/cpu/s390/globalDefinitions_s390.hpp +++ b/src/hotspot/cpu/s390/globalDefinitions_s390.hpp @@ -28,7 +28,7 @@ #define ShortenBranches true -const int StackAlignmentInBytes = 16; +const int StackAlignmentInBytes = 8; #define SUPPORTS_NATIVE_CX8 diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index 8bfc8249ed289..35016b60fa41b 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -838,7 +838,7 @@ void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state, // Check that all monitors are unlocked. { NearLabel loop, exception, entry, restart; - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); // We use Z_ARG2 so that if we go slow path it will be the correct // register for unlock_object to pass to VM directly. Register R_current_monitor = Z_ARG2; @@ -951,6 +951,11 @@ void InterpreterMacroAssembler::remove_activation(TosState state, // Test if reserved zone needs to be enabled. Label no_reserved_zone_enabling; + // check if already enabled - if so no re-enabling needed + assert(sizeof(StackOverflow::StackGuardState) == 4, "unexpected size"); + z_ly(Z_R0, Address(Z_thread, JavaThread::stack_guard_state_offset())); + compare32_and_branch(Z_R0, StackOverflow::stack_guard_enabled, bcondEqual, no_reserved_zone_enabling); + // Compare frame pointers. There is no good stack pointer, as with stack // frame compression we can get different SPs when we do calls. A subsequent // call could have a smaller SP, so that this compare succeeds for an @@ -977,9 +982,10 @@ void InterpreterMacroAssembler::remove_activation(TosState state, // lock object // // Registers alive -// monitor - Address of the BasicObjectLock to be used for locking, +// monitor (Z_R10) - Address of the BasicObjectLock to be used for locking, // which must be initialized with the object to lock. -// object - Address of the object to be locked. +// object (Z_R11, Z_R2) - Address of the object to be locked. +// templateTable (monitorenter) is using Z_R2 for object void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { if (LockingMode == LM_MONITOR) { @@ -987,7 +993,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { return; } - // template code: + // template code: (for LM_LEGACY) // // markWord displaced_header = obj->mark().set_unlocked(); // monitor->lock()->set_displaced_header(displaced_header); @@ -1001,68 +1007,77 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // InterpreterRuntime::monitorenter(THREAD, monitor); // } - const Register displaced_header = Z_ARG5; + const int hdr_offset = oopDesc::mark_offset_in_bytes(); + + const Register header = Z_ARG5; const Register object_mark_addr = Z_ARG4; const Register current_header = Z_ARG5; + const Register tmp = Z_R1_scratch; - NearLabel done; - NearLabel slow_case; + NearLabel done, slow_case; - // markWord displaced_header = obj->mark().set_unlocked(); + // markWord header = obj->mark().set_unlocked(); - // Load markWord from object into displaced_header. - z_lg(displaced_header, oopDesc::mark_offset_in_bytes(), object); + // Load markWord from object into header. + z_lg(header, hdr_offset, object); if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(Z_R1_scratch, object); - testbit(Address(Z_R1_scratch, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); + load_klass(tmp, object); + testbit(Address(tmp, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); z_btrue(slow_case); } - // Set displaced_header to be (markWord of object | UNLOCK_VALUE). - z_oill(displaced_header, markWord::unlocked_value); + if (LockingMode == LM_LIGHTWEIGHT) { + lightweight_lock(object, /* mark word */ header, tmp, slow_case); + } else if (LockingMode == LM_LEGACY) { - // monitor->lock()->set_displaced_header(displaced_header); + // Set header to be (markWord of object | UNLOCK_VALUE). + // This will not change anything if it was unlocked before. + z_oill(header, markWord::unlocked_value); - // Initialize the box (Must happen before we update the object mark!). - z_stg(displaced_header, in_bytes(BasicObjectLock::lock_offset()) + - BasicLock::displaced_header_offset_in_bytes(), monitor); + // monitor->lock()->set_displaced_header(displaced_header); + const int lock_offset = in_bytes(BasicObjectLock::lock_offset()); + const int mark_offset = lock_offset + BasicLock::displaced_header_offset_in_bytes(); - // if (Atomic::cmpxchg(/*addr*/obj->mark_addr(), /*cmp*/displaced_header, /*ex=*/monitor) == displaced_header) { + // Initialize the box (Must happen before we update the object mark!). + z_stg(header, mark_offset, monitor); - // Store stack address of the BasicObjectLock (this is monitor) into object. - add2reg(object_mark_addr, oopDesc::mark_offset_in_bytes(), object); + // if (Atomic::cmpxchg(/*addr*/obj->mark_addr(), /*cmp*/displaced_header, /*ex=*/monitor) == displaced_header) { - z_csg(displaced_header, monitor, 0, object_mark_addr); - assert(current_header==displaced_header, "must be same register"); // Identified two registers from z/Architecture. + // not necessary, use offset in instruction directly. + // add2reg(object_mark_addr, hdr_offset, object); - z_bre(done); + // Store stack address of the BasicObjectLock (this is monitor) into object. + z_csg(header, monitor, hdr_offset, object); + assert(current_header == header, + "must be same register"); // Identified two registers from z/Architecture. - // } else if (THREAD->is_lock_owned((address)displaced_header)) - // // Simple recursive case. - // monitor->lock()->set_displaced_header(nullptr); + z_bre(done); - // We did not see an unlocked object so try the fast recursive case. + // } else if (THREAD->is_lock_owned((address)displaced_header)) + // // Simple recursive case. + // monitor->lock()->set_displaced_header(nullptr); - // Check if owner is self by comparing the value in the markWord of object - // (current_header) with the stack pointer. - z_sgr(current_header, Z_SP); + // We did not see an unlocked object so try the fast recursive case. - assert(os::vm_page_size() > 0xfff, "page size too small - change the constant"); + // Check if owner is self by comparing the value in the markWord of object + // (current_header) with the stack pointer. + z_sgr(current_header, Z_SP); - // The prior sequence "LGR, NGR, LTGR" can be done better - // (Z_R1 is temp and not used after here). - load_const_optimized(Z_R0, (~(os::vm_page_size()-1) | markWord::lock_mask_in_place)); - z_ngr(Z_R0, current_header); // AND sets CC (result eq/ne 0) + assert(os::vm_page_size() > 0xfff, "page size too small - change the constant"); - // If condition is true we are done and hence we can store 0 in the displaced - // header indicating it is a recursive lock and be done. - z_brne(slow_case); - z_release(); // Membar unnecessary on zarch AND because the above csg does a sync before and after. - z_stg(Z_R0/*==0!*/, in_bytes(BasicObjectLock::lock_offset()) + - BasicLock::displaced_header_offset_in_bytes(), monitor); - z_bru(done); + // The prior sequence "LGR, NGR, LTGR" can be done better + // (Z_R1 is temp and not used after here). + load_const_optimized(Z_R0, (~(os::vm_page_size() - 1) | markWord::lock_mask_in_place)); + z_ngr(Z_R0, current_header); // AND sets CC (result eq/ne 0) + // If condition is true we are done and hence we can store 0 in the displaced + // header indicating it is a recursive lock and be done. + z_brne(slow_case); + z_release(); // Member unnecessary on zarch AND because the above csg does a sync before and after. + z_stg(Z_R0/*==0!*/, mark_offset, monitor); + } + z_bru(done); // } else { // // Slow path. // InterpreterRuntime::monitorenter(THREAD, monitor); @@ -1070,8 +1085,16 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // None of the above fast optimizations worked so we have to get into the // slow case of monitor enter. bind(slow_case); - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor); - + if (LockingMode == LM_LIGHTWEIGHT) { + // for lightweight locking we need to use monitorenter_obj, see interpreterRuntime.cpp + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), + object); + } else { + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + monitor); + } // } bind(done); @@ -1092,7 +1115,7 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, Register object) } // else { - // template code: + // template code: (for LM_LEGACY): // // if ((displaced_header = monitor->displaced_header()) == nullptr) { // // Recursive unlock. Mark the monitor unlocked by setting the object field to null. @@ -1105,10 +1128,12 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, Register object) // InterpreterRuntime::monitorexit(monitor); // } - const Register displaced_header = Z_ARG4; - const Register current_header = Z_R1; + const int hdr_offset = oopDesc::mark_offset_in_bytes(); + + const Register header = Z_ARG4; + const Register current_header = Z_R1_scratch; Address obj_entry(monitor, BasicObjectLock::obj_offset()); - Label done; + Label done, slow_case; if (object == noreg) { // In the template interpreter, we must assure that the object @@ -1118,35 +1143,63 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, Register object) z_lg(object, obj_entry); } - assert_different_registers(monitor, object, displaced_header, current_header); + assert_different_registers(monitor, object, header, current_header); // if ((displaced_header = monitor->displaced_header()) == nullptr) { // // Recursive unlock. Mark the monitor unlocked by setting the object field to null. // monitor->set_obj(nullptr); - clear_mem(obj_entry, sizeof(oop)); + // monitor->lock()->set_displaced_header(displaced_header); + const int lock_offset = in_bytes(BasicObjectLock::lock_offset()); + const int mark_offset = lock_offset + BasicLock::displaced_header_offset_in_bytes(); - // Test first if we are in the fast recursive case. - MacroAssembler::load_and_test_long(displaced_header, - Address(monitor, in_bytes(BasicObjectLock::lock_offset()) + - BasicLock::displaced_header_offset_in_bytes())); - z_bre(done); // displaced_header == 0 -> goto done + clear_mem(obj_entry, sizeof(oop)); + if (LockingMode != LM_LIGHTWEIGHT) { + // Test first if we are in the fast recursive case. + MacroAssembler::load_and_test_long(header, Address(monitor, mark_offset)); + z_bre(done); // header == 0 -> goto done + } // } else if (Atomic::cmpxchg(obj->mark_addr(), monitor, displaced_header) == monitor) { // // We swapped the unlocked mark in displaced_header into the object's mark word. // monitor->set_obj(nullptr); // If we still have a lightweight lock, unlock the object and be done. + if (LockingMode == LM_LIGHTWEIGHT) { + // Check for non-symmetric locking. This is allowed by the spec and the interpreter + // must handle it. + + Register tmp = current_header; - // The markword is expected to be at offset 0. - assert(oopDesc::mark_offset_in_bytes() == 0, "unlock_object: review code below"); + // First check for lock-stack underflow. + z_lgf(tmp, Address(Z_thread, JavaThread::lock_stack_top_offset())); + compareU32_and_branch(tmp, (unsigned)LockStack::start_offset(), Assembler::bcondNotHigh, slow_case); - // We have the displaced header in displaced_header. If the lock is still - // lightweight, it will contain the monitor address and we'll store the - // displaced header back into the object's mark word. - z_lgr(current_header, monitor); - z_csg(current_header, displaced_header, 0, object); - z_bre(done); + // Then check if the top of the lock-stack matches the unlocked object. + z_aghi(tmp, -oopSize); + z_lg(tmp, Address(Z_thread, tmp)); + compare64_and_branch(tmp, object, Assembler::bcondNotEqual, slow_case); + + z_lg(header, Address(object, hdr_offset)); + z_lgr(tmp, header); + z_nill(tmp, markWord::monitor_value); + z_brne(slow_case); + + lightweight_unlock(object, header, tmp, slow_case); + + z_bru(done); + } else { + // The markword is expected to be at offset 0. + // This is not required on s390, at least not here. + assert(hdr_offset == 0, "unlock_object: review code below"); + + // We have the displaced header in header. If the lock is still + // lightweight, it will contain the monitor address and we'll store the + // displaced header back into the object's mark word. + z_lgr(current_header, monitor); + z_csg(current_header, header, hdr_offset, object); + z_bre(done); + } // } else { // // Slow path. @@ -1154,6 +1207,7 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, Register object) // The lock has been converted into a heavy lock and hence // we need to get into the slow case. + bind(slow_case); z_stg(object, obj_entry); // Restore object entry, has been cleared above. call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); @@ -2033,7 +2087,7 @@ void InterpreterMacroAssembler::add_monitor_to_stack(bool stack_is_empty, const Register Rcurr_slot = Rtemp1; const Register Rlimit = Rtemp2; - const jint delta = -frame::interpreter_frame_monitor_size() * wordSize; + const jint delta = -frame::interpreter_frame_monitor_size_in_bytes(); assert((delta & LongAlignmentMask) == 0, "sizeof BasicObjectLock must be even number of doublewords"); @@ -2214,6 +2268,6 @@ void InterpreterMacroAssembler::pop_interpreter_frame(Register return_pc, Regist void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { if (VerifyFPU) { - unimplemented("verfiyFPU"); + unimplemented("verifyFPU"); } } diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 1960e6d3e0764..8a56f3e4c2b30 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -3165,11 +3165,15 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis // Handle existing monitor. // The object has an existing monitor iff (mark & monitor_value) != 0. guarantee(Immediate::is_uimm16(markWord::monitor_value), "must be half-word"); - z_lr(temp, displacedHeader); + z_lgr(temp, displacedHeader); z_nill(temp, markWord::monitor_value); z_brne(object_has_monitor); - if (LockingMode != LM_MONITOR) { + if (LockingMode == LM_MONITOR) { + // Set NE to indicate 'failure' -> take slow-path + z_ltgr(oop, oop); + z_bru(done); + } else if (LockingMode == LM_LEGACY) { // Set mark to markWord | markWord::unlocked_value. z_oill(displacedHeader, markWord::unlocked_value); @@ -3186,23 +3190,23 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis z_csg(displacedHeader, box, 0, oop); assert(currentHeader == displacedHeader, "must be same register"); // Identified two registers from z/Architecture. z_bre(done); - } else { - // Set NE to indicate 'failure' -> take slow-path - z_ltgr(oop, oop); - z_bru(done); - } - // We did not see an unlocked object so try the fast recursive case. + // We did not see an unlocked object so try the fast recursive case. - z_sgr(currentHeader, Z_SP); - load_const_optimized(temp, (~(os::vm_page_size()-1) | markWord::lock_mask_in_place)); + z_sgr(currentHeader, Z_SP); + load_const_optimized(temp, (~(os::vm_page_size() - 1) | markWord::lock_mask_in_place)); - z_ngr(currentHeader, temp); - // z_brne(done); - // z_release(); - z_stg(currentHeader/*==0 or not 0*/, BasicLock::displaced_header_offset_in_bytes(), box); + z_ngr(currentHeader, temp); + // z_brne(done); + // z_release(); + z_stg(currentHeader/*==0 or not 0*/, BasicLock::displaced_header_offset_in_bytes(), box); - z_bru(done); + z_bru(done); + } else { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + lightweight_lock(oop, displacedHeader, temp, done); + z_bru(done); + } Register zero = temp; Register monitor_tagged = displacedHeader; // Tagged with markWord::monitor_value. @@ -3214,8 +3218,10 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis z_lghi(zero, 0); // If m->owner is null, then csg succeeds and sets m->owner=THREAD and CR=EQ. z_csg(zero, Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor_tagged); - // Store a non-null value into the box. - z_stg(box, BasicLock::displaced_header_offset_in_bytes(), box); + if (LockingMode != LM_LIGHTWEIGHT) { + // Store a non-null value into the box. + z_stg(box, BasicLock::displaced_header_offset_in_bytes(), box); + } #ifdef ASSERT z_brne(done); // We've acquired the monitor, check some invariants. @@ -3238,11 +3244,13 @@ void MacroAssembler::compiler_fast_unlock_object(Register oop, Register box, Reg Register temp = temp1; Register monitor = temp2; + const int hdr_offset = oopDesc::mark_offset_in_bytes(); + Label done, object_has_monitor; BLOCK_COMMENT("compiler_fast_unlock_object {"); - if (LockingMode != LM_MONITOR) { + if (LockingMode == LM_LEGACY) { // Find the lock address and load the displaced header from the stack. // if the displaced header is zero, we have a recursive unlock. load_and_test_long(displacedHeader, Address(box, BasicLock::displaced_header_offset_in_bytes())); @@ -3251,27 +3259,41 @@ void MacroAssembler::compiler_fast_unlock_object(Register oop, Register box, Reg // Handle existing monitor. // The object has an existing monitor iff (mark & monitor_value) != 0. - z_lg(currentHeader, oopDesc::mark_offset_in_bytes(), oop); + z_lg(currentHeader, hdr_offset, oop); guarantee(Immediate::is_uimm16(markWord::monitor_value), "must be half-word"); + if (LockingMode == LM_LIGHTWEIGHT) { + z_lgr(temp, currentHeader); + } z_nill(currentHeader, markWord::monitor_value); z_brne(object_has_monitor); - if (LockingMode != LM_MONITOR) { + if (LockingMode == LM_MONITOR) { + // Set NE to indicate 'failure' -> take slow-path + z_ltgr(oop, oop); + z_bru(done); + } else if (LockingMode == LM_LEGACY) { // Check if it is still a light weight lock, this is true if we see // the stack address of the basicLock in the markWord of the object // copy box to currentHeader such that csg does not kill it. z_lgr(currentHeader, box); z_csg(currentHeader, displacedHeader, 0, oop); - z_bru(done); // Csg sets CR as desired. + z_bru(done); // csg sets CR as desired. } else { - // Set NE to indicate 'failure' -> take slow-path - z_ltgr(oop, oop); + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + + // don't load currentHead again from stack-top after monitor check, as it is possible + // some other thread modified it. + // currentHeader is altered, but it's contents are copied in temp as well + lightweight_unlock(oop, temp, currentHeader, done); z_bru(done); } + // In case of LM_LIGHTWEIGHT, we may reach here with (temp & ObjectMonitor::ANONYMOUS_OWNER) != 0. + // This is handled like owner thread mismatches: We take the slow path. + // Handle existing monitor. bind(object_has_monitor); - z_lg(currentHeader, oopDesc::mark_offset_in_bytes(), oop); // CurrentHeader is tagged with monitor_value set. + z_lg(currentHeader, hdr_offset, oop); // CurrentHeader is tagged with monitor_value set. load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); z_brne(done); load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); @@ -5621,3 +5643,103 @@ SkipIfEqual::SkipIfEqual(MacroAssembler* masm, const bool* flag_addr, bool value SkipIfEqual::~SkipIfEqual() { _masm->bind(_label); } + +// Implements lightweight-locking. +// Branches to slow upon failure to lock the object. +// Falls through upon success. +// +// - obj: the object to be locked, contents preserved. +// - hdr: the header, already loaded from obj, contents destroyed. +// Note: make sure Z_R1 is not manipulated here when C2 compiler is in play +void MacroAssembler::lightweight_lock(Register obj, Register hdr, Register temp, Label& slow_case) { + + assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); + assert_different_registers(obj, hdr, temp); + + // First we need to check if the lock-stack has room for pushing the object reference. + z_lgf(temp, Address(Z_thread, JavaThread::lock_stack_top_offset())); + + compareU32_and_branch(temp, (unsigned)LockStack::end_offset()-1, bcondHigh, slow_case); + + // attempting a lightweight_lock + // Load (object->mark() | 1) into hdr + z_oill(hdr, markWord::unlocked_value); + + z_lgr(temp, hdr); + + // Clear lock-bits from hdr (locked state) + z_xilf(temp, markWord::unlocked_value); + + z_csg(hdr, temp, oopDesc::mark_offset_in_bytes(), obj); + branch_optimized(Assembler::bcondNotEqual, slow_case); + + // After successful lock, push object on lock-stack + z_lgf(temp, Address(Z_thread, JavaThread::lock_stack_top_offset())); + z_stg(obj, Address(Z_thread, temp)); + z_ahi(temp, oopSize); + z_st(temp, Address(Z_thread, JavaThread::lock_stack_top_offset())); + + // as locking was successful, set CC to EQ + z_cr(temp, temp); +} + +// Implements lightweight-unlocking. +// Branches to slow upon failure. +// Falls through upon success. +// +// - obj: the object to be unlocked +// - hdr: the (pre-loaded) header of the object, will be destroyed +// - Z_R1_scratch: will be killed in case of Interpreter & C1 Compiler +void MacroAssembler::lightweight_unlock(Register obj, Register hdr, Register tmp, Label& slow) { + + assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); + assert_different_registers(obj, hdr, tmp); + +#ifdef ASSERT + { + // Check that hdr is lightweight-locked. + Label hdr_ok; + z_lgr(tmp, hdr); + z_nill(tmp, markWord::lock_mask_in_place); + z_bre(hdr_ok); + stop("Header is not lightweight-locked"); + bind(hdr_ok); + } + { + // The following checks rely on the fact that LockStack is only ever modified by + // its owning thread, even if the lock got inflated concurrently; removal of LockStack + // entries after inflation will happen delayed in that case. + + // Check for lock-stack underflow. + Label stack_ok; + z_lgf(tmp, Address(Z_thread, JavaThread::lock_stack_top_offset())); + compareU32_and_branch(tmp, (unsigned)LockStack::start_offset(), Assembler::bcondHigh, stack_ok); + stop("Lock-stack underflow"); + bind(stack_ok); + } + { + // Check if the top of the lock-stack matches the unlocked object. + Label tos_ok; + z_aghi(tmp, -oopSize); + z_lg(tmp, Address(Z_thread, tmp)); + compare64_and_branch(tmp, obj, Assembler::bcondEqual, tos_ok); + stop("Top of lock-stack does not match the unlocked object"); + bind(tos_ok); + } +#endif // ASSERT + + z_lgr(tmp, hdr); + z_oill(tmp, markWord::unlocked_value); + z_csg(hdr, tmp, oopDesc::mark_offset_in_bytes(), obj); + branch_optimized(Assembler::bcondNotEqual, slow); + + // After successful unlock, pop object from lock-stack +#ifdef ASSERT + z_lgf(tmp, Address(Z_thread, JavaThread::lock_stack_top_offset())); + z_aghi(tmp, -oopSize); + z_agr(tmp, Z_thread); + z_xc(0, oopSize-1, tmp, 0, tmp); // wipe out lock-stack entry +#endif + z_alsi(in_bytes(JavaThread::lock_stack_top_offset()), Z_thread, -oopSize); // pop object + z_cr(tmp, tmp); // set CC to EQ +} diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index fad35cf08b215..bf14b42e2d1b3 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -722,6 +722,8 @@ class MacroAssembler: public Assembler { void compiler_fast_lock_object(Register oop, Register box, Register temp1, Register temp2); void compiler_fast_unlock_object(Register oop, Register box, Register temp1, Register temp2); + void lightweight_lock(Register obj, Register hdr, Register tmp, Label& slow); + void lightweight_unlock(Register obj, Register hdr, Register tmp, Label& slow); void resolve_jobject(Register value, Register tmp1, Register tmp2); diff --git a/src/hotspot/cpu/s390/methodHandles_s390.cpp b/src/hotspot/cpu/s390/methodHandles_s390.cpp index aaccdbabb9e22..ef8722f2499c0 100644 --- a/src/hotspot/cpu/s390/methodHandles_s390.cpp +++ b/src/hotspot/cpu/s390/methodHandles_s390.cpp @@ -349,7 +349,16 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* void MethodHandles::jump_to_native_invoker(MacroAssembler* _masm, Register nep_reg, Register temp_target) { BLOCK_COMMENT("jump_to_native_invoker {"); - __ should_not_reach_here(); + assert(nep_reg != noreg, "required register"); + + // Load the invoker, as NEP -> .invoker + __ verify_oop(nep_reg); + + __ z_lg(temp_target, Address(nep_reg, + NONZERO(jdk_internal_foreign_abi_NativeEntryPoint::downcall_stub_address_offset_in_bytes()))); + + __ z_br(temp_target); + BLOCK_COMMENT("} jump_to_native_invoker"); } @@ -387,6 +396,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, } else if (iid == vmIntrinsics::_linkToNative) { assert(for_compiler_entry, "only compiler entry is supported"); jump_to_native_invoker(_masm, member_reg, temp1); + return; } // The method is a member invoker used by direct method handles. diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 26469e2fb3d58..05b607ec03c52 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -1716,7 +1716,9 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ add2reg(r_box, lock_offset, Z_SP); // Try fastpath for locking. - // Fast_lock kills r_temp_1, r_temp_2. (Don't use R1 as temp, won't work!) + // Fast_lock kills r_temp_1, r_temp_2. + // in case of DiagnoseSyncOnValueBasedClasses content for Z_R1_scratch + // will be destroyed, So avoid using Z_R1 as temp here. __ compiler_fast_lock_object(r_oop, r_box, r_tmp1, r_tmp2); __ z_bre(done); @@ -1915,7 +1917,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ add2reg(r_box, lock_offset, Z_SP); // Try fastpath for unlocking. - __ compiler_fast_unlock_object(r_oop, r_box, r_tmp1, r_tmp2); // Don't use R1 as temp. + // Fast_unlock kills r_tmp1, r_tmp2. + __ compiler_fast_unlock_object(r_oop, r_box, r_tmp1, r_tmp2); __ z_bre(done); // Slow path for unlocking. diff --git a/src/hotspot/cpu/s390/templateTable_s390.cpp b/src/hotspot/cpu/s390/templateTable_s390.cpp index 78765c1835062..689c760567593 100644 --- a/src/hotspot/cpu/s390/templateTable_s390.cpp +++ b/src/hotspot/cpu/s390/templateTable_s390.cpp @@ -4143,7 +4143,7 @@ void TemplateTable::monitorenter() { // Check for null object. __ null_check(Z_tos); - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); NearLabel allocated; // Initialize entry pointer. const Register Rfree_slot = Z_tmp_1; @@ -4238,7 +4238,7 @@ void TemplateTable::monitorexit() { // Find matching slot. { - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); NearLabel entry, loop; const Register Rbot = Z_ARG3; // Points to word under bottom of monitor block. diff --git a/src/hotspot/cpu/s390/upcallLinker_s390.cpp b/src/hotspot/cpu/s390/upcallLinker_s390.cpp index 3e1fb04218b51..b748ec547ccf1 100644 --- a/src/hotspot/cpu/s390/upcallLinker_s390.cpp +++ b/src/hotspot/cpu/s390/upcallLinker_s390.cpp @@ -22,15 +22,287 @@ */ #include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "logging/logStream.hpp" +#include "memory/resourceArea.hpp" #include "prims/upcallLinker.hpp" -#include "utilities/debug.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/signature.hpp" +#include "runtime/stubRoutines.hpp" +#include "utilities/formatBuffer.hpp" +#include "utilities/globalDefinitions.hpp" +#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); + // Z_SP saved/restored by prologue/epilogue + if (reg == Z_SP) 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); + // Z_SP saved/restored by prologue/epilogue + if (reg == Z_SP) continue; + if (!abi.is_volatile_reg(reg)) { + __ z_stg(reg, Address(Z_SP, offset)); + offset += 8; + } + } + + for (int i = 0; i < FloatRegister::number_of_registers; i++) { + FloatRegister reg = as_FloatRegister(i); + if (!abi.is_volatile_reg(reg)) { + __ z_std(reg, Address(Z_SP, offset)); + 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); + // Z_SP saved/restored by prologue/epilogue + if (reg == Z_SP) continue; + if (!abi.is_volatile_reg(reg)) { + __ z_lg(reg, Address(Z_SP, offset)); + offset += 8; + } + } + + for (int i = 0; i < FloatRegister::number_of_registers; i++) { + FloatRegister reg = as_FloatRegister(i); + if (!abi.is_volatile_reg(reg)) { + __ z_ld(reg, Address(Z_SP, offset)); + offset += 8; + } + } + + __ block_comment("} restore_callee_saved_regs "); +} + +static const int upcall_stub_code_base_size = 1024; // depends on GC (resolve_jobject) +static const int upcall_stub_size_per_arg = 16; // arg save & restore + move address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, BasicType* in_sig_bt, int total_in_args, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, bool needs_return_buffer, int ret_buf_size) { - ShouldNotCallThis(); - return nullptr; + ResourceMark rm; + const ABIDescriptor abi = ForeignGlobals::parse_abi_descriptor(jabi); + const CallRegs call_regs = ForeignGlobals::parse_call_regs(jconv); + int code_size = upcall_stub_code_base_size + (total_in_args * upcall_stub_size_per_arg); + CodeBuffer buffer("upcall_stub", code_size, /* locs_size = */ 0); + + Register call_target_address = Z_R1_scratch; + + VMStorage shuffle_reg = abi._scratch1; + JavaCallingConvention out_conv; + NativeCallingConvention in_conv(call_regs._arg_regs); + ArgumentShuffle arg_shuffle(in_sig_bt, total_in_args, out_sig_bt, total_out_args, &in_conv, &out_conv, shuffle_reg); + + // The Java call uses the JIT ABI, but we also call C. + int out_arg_area = MAX2(frame::z_jit_out_preserve_size + arg_shuffle.out_arg_bytes(), (int)frame::z_abi_160_size); + +#ifndef PRODUCT + LogTarget(Trace, foreign, upcall) lt; + if (lt.is_enabled()) { + ResourceMark rm; + LogStream ls(lt); + arg_shuffle.print_on(&ls); + } +#endif + + + int reg_save_area_size = compute_reg_save_area_size(abi); + 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(); + int frame_data_offset = reg_save_area_offset + reg_save_area_size; + int frame_bottom_offset = frame_data_offset + sizeof(UpcallStub::FrameData); + + int frame_size = align_up(frame_bottom_offset, StackAlignmentInBytes); + StubLocations locs; + + // The space we have allocated will look like: + // + // + // FP-> | | + // |---------------------| = frame_bottom_offset = frame_size + // | | + // | FrameData | + // |---------------------| = frame_data_offset + // | | + // | reg_save_area | + // |---------------------| = reg_save_are_offset + // | | + // | arg_save_area | + // |---------------------| = arg_save_are_offset + // | | + // | res_save_area | + // |---------------------| = res_save_are_offset + // | | + // SP-> | out_arg_area | needs to be at end for shadow space + // + // + + ////////////////////////////////////////////////////////////////////////////// + + MacroAssembler* _masm = new MacroAssembler(&buffer); + address start = __ pc(); + + __ save_return_pc(); + assert((abi._stack_alignment_bytes % StackAlignmentInBytes) == 0, "must be 8 byte aligned"); + // allocate frame (frame_size is also aligned, so stack is still aligned) + __ push_frame(frame_size); + + // we have to always spill args since we need to do a call to get the thread + // (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); + + __ block_comment("{ on_entry"); + __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry)); + __ z_aghik(Z_ARG1, Z_SP, frame_data_offset); + __ call(call_target_address); + __ z_lgr(Z_thread, Z_RET); + __ block_comment("} on_entry"); + + arg_spiller.generate_fill(_masm, arg_save_area_offset); + __ block_comment("{ argument shuffle"); + arg_shuffle.generate(_masm, shuffle_reg, abi._shadow_space_bytes, frame::z_jit_out_preserve_size, locs); + __ block_comment("} argument shuffle"); + + __ block_comment("{ receiver "); + __ load_const_optimized(Z_ARG1, (intptr_t)receiver); + __ resolve_jobject(Z_ARG1, Z_tmp_1, Z_tmp_2); + __ block_comment("} receiver "); + + __ load_const_optimized(Z_method, (intptr_t)entry); + __ z_stg(Z_method, Address(Z_thread, in_bytes(JavaThread::callee_target_offset()))); + + __ z_lg(call_target_address, Address(Z_method, in_bytes(Method::from_compiled_offset()))); + __ call(call_target_address); + + // return value shuffle + assert(!needs_return_buffer, "unexpected needs_return_buffer"); + // CallArranger can pick a return type that goes in the same reg for both CCs. + if (call_regs._ret_regs.length() > 0) { // 0 or 1 + VMStorage ret_reg = call_regs._ret_regs.at(0); + // Check if the return reg is as expected. + switch (ret_type) { + case T_BOOLEAN: + case T_BYTE: + case T_SHORT: + case T_CHAR: + case T_INT: + __ z_lgfr(Z_RET, Z_RET); // Clear garbage in high half. + // fallthrough + case T_LONG: + assert(as_Register(ret_reg) == Z_RET, "unexpected result register"); + break; + case T_FLOAT: + case T_DOUBLE: + assert(as_FloatRegister(ret_reg) == Z_FRET, "unexpected result register"); + break; + default: + fatal("unexpected return type: %s", type2name(ret_type)); + } + } + + result_spiller.generate_spill(_masm, res_save_area_offset); + + __ block_comment("{ on_exit"); + __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_exit)); + __ z_aghik(Z_ARG1, Z_SP, frame_data_offset); + __ call(call_target_address); + __ block_comment("} on_exit"); + + restore_callee_saved_registers(_masm, abi, reg_save_area_offset); + + result_spiller.generate_fill(_masm, res_save_area_offset); + + __ pop_frame(); + __ restore_return_pc(); + __ z_br(Z_R14); + + ////////////////////////////////////////////////////////////////////////////// + + __ block_comment("{ exception handler"); + + intptr_t exception_handler_offset = __ pc() - start; + + // Native caller has no idea how to handle exceptions, + // so we just crash here. Up to callee to catch exceptions. + __ verify_oop(Z_ARG1); + __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::handle_uncaught_exception)); + __ call_c(call_target_address); + __ should_not_reach_here(); + + __ block_comment("} exception handler"); + + _masm->flush(); + +#ifndef PRODUCT + stringStream ss; + ss.print("upcall_stub_%s", entry->signature()->as_C_string()); + const char* name = _masm->code_string(ss.as_string()); +#else // PRODUCT + const char* name = "upcall_stub"; +#endif // PRODUCT + + buffer.log_section_sizes(name); + UpcallStub* blob + = UpcallStub::create(name, + &buffer, + exception_handler_offset, + receiver, + in_ByteSize(frame_data_offset)); +#ifndef PRODUCT + if (lt.is_enabled()) { + ResourceMark rm; + LogStream ls(lt); + blob->print_on(&ls); + } +#endif + + return blob->code_begin(); } diff --git a/src/hotspot/cpu/s390/vmstorage_s390.hpp b/src/hotspot/cpu/s390/vmstorage_s390.hpp index 192159adc4cc5..6a59567092078 100644 --- a/src/hotspot/cpu/s390/vmstorage_s390.hpp +++ b/src/hotspot/cpu/s390/vmstorage_s390.hpp @@ -29,24 +29,79 @@ #include "asm/register.hpp" enum class StorageType : int8_t { - STACK = 0, - PLACEHOLDER = 1, -// special locations used only by native code - FRAME_DATA = PLACEHOLDER + 1, + INTEGER = 0, + FLOAT = 1, + STACK = 2, + PLACEHOLDER = 3, + // special locations used only by native code + FRAME_DATA = 4, INVALID = -1 }; // need to define this before constructing VMStorage (below) constexpr inline bool VMStorage::is_reg(StorageType type) { - return false; + return type == StorageType::INTEGER || type == StorageType::FLOAT; } constexpr inline StorageType VMStorage::stack_type() { return StorageType::STACK; } constexpr inline StorageType VMStorage::placeholder_type() { return StorageType::PLACEHOLDER; } constexpr inline StorageType VMStorage::frame_data_type() { return StorageType::FRAME_DATA; } +// Needs to be consistent with S390Architecture.java. +constexpr uint16_t REG32_MASK = 0b0000000000000001; +constexpr uint16_t REG64_MASK = 0b0000000000000011; + +inline Register as_Register(VMStorage vms) { + assert(vms.type() == StorageType::INTEGER, "not the right type"); + return ::as_Register(vms.index()); +} + +inline FloatRegister as_FloatRegister(VMStorage vms) { + assert(vms.type() == StorageType::FLOAT, "not the right type"); + return ::as_FloatRegister(vms.index()); +} + +inline VMStorage as_VMStorage(Register reg, uint16_t segment_mask = REG64_MASK) { + return VMStorage::reg_storage(StorageType::INTEGER, segment_mask, reg->encoding()); +} + +inline VMStorage as_VMStorage(FloatRegister reg, uint16_t segment_mask = REG64_MASK) { + return VMStorage::reg_storage(StorageType::FLOAT, segment_mask, reg->encoding()); +} + inline VMStorage as_VMStorage(VMReg reg, BasicType bt) { + if (reg->is_Register()) { + uint16_t segment_mask = 0; + switch (bt) { + case T_BOOLEAN: + case T_CHAR : + case T_BYTE : + case T_SHORT : + case T_INT : segment_mask = REG32_MASK; break; + default : segment_mask = REG64_MASK; break; + } + return as_VMStorage(reg->as_Register(), segment_mask); + } else if (reg->is_FloatRegister()) { + // FP regs always use double format. However, we need the correct format for loads /stores. + return as_VMStorage(reg->as_FloatRegister(), (bt == T_FLOAT) ? REG32_MASK : REG64_MASK); + } else if (reg->is_stack()) { + uint16_t size = 0; + switch (bt) { + case T_BOOLEAN: + case T_CHAR : + case T_BYTE : + case T_SHORT : + case T_INT : + case T_FLOAT : size = 4; break; + default : size = 8; break; + } + return VMStorage(StorageType::STACK, size, + checked_cast(reg->reg2stack() * VMRegImpl::stack_slot_size)); + } else if (!reg->is_valid()) { + return VMStorage::invalid(); + } + ShouldNotReachHere(); return VMStorage::invalid(); } -#endif // CPU_S390_VMSTORAGE_S390_INLINE_HPP \ No newline at end of file +#endif // CPU_S390_VMSTORAGE_S390_INLINE_HPP diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index a228bd28db7ce..ff0fee0f5deff 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -315,7 +315,7 @@ class Address { } bool xmmindex_needs_rex() const { - return _xmmindex->is_valid() && _xmmindex->encoding() >= 8; + return _xmmindex->is_valid() && ((_xmmindex->encoding() & 8) == 8); } relocInfo::relocType reloc() const { return _rspec.type(); } diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index cec75f210e9bf..57da386032402 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -1713,7 +1713,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L assert_different_registers(obj, k_RInfo, klass_RInfo); - __ cmpptr(obj, NULL_WORD); + __ testptr(obj, obj); if (op->should_profile()) { Label not_null; __ jccb(Assembler::notEqual, not_null); @@ -1792,7 +1792,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L __ pop(klass_RInfo); __ pop(klass_RInfo); // result is a boolean - __ cmpl(klass_RInfo, 0); + __ testl(klass_RInfo, klass_RInfo); __ jcc(Assembler::equal, *failure_target); // successful cast, fall through to profile or jump } @@ -1806,7 +1806,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L __ pop(klass_RInfo); __ pop(k_RInfo); // result is a boolean - __ cmpl(k_RInfo, 0); + __ testl(k_RInfo, k_RInfo); __ jcc(Assembler::equal, *failure_target); // successful cast, fall through to profile or jump } @@ -1859,7 +1859,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { Label *success_target = op->should_profile() ? &profile_cast_success : &done; Label *failure_target = op->should_profile() ? &profile_cast_failure : stub->entry(); - __ cmpptr(value, NULL_WORD); + __ testptr(value, value); if (op->should_profile()) { Label not_null; __ jccb(Assembler::notEqual, not_null); @@ -1890,7 +1890,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { __ pop(klass_RInfo); __ pop(k_RInfo); // result is a boolean - __ cmpl(k_RInfo, 0); + __ testl(k_RInfo, k_RInfo); __ jcc(Assembler::equal, *failure_target); // fall through to the success case @@ -2047,7 +2047,7 @@ void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, L } else { Label skip; - __ jcc (acond, skip); + __ jccb(acond, skip); if (opr2->is_cpu_register()) { reg2reg(opr2, result); } else if (opr2->is_stack()) { @@ -2664,13 +2664,18 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, // cpu register - constant LIR_Const* c = opr2->as_constant_ptr(); if (c->type() == T_INT) { - __ cmpl(reg1, c->as_jint()); + jint i = c->as_jint(); + if (i == 0) { + __ testl(reg1, reg1); + } else { + __ cmpl(reg1, i); + } } else if (c->type() == T_METADATA) { // All we need for now is a comparison with null for equality. assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "oops"); Metadata* m = c->as_metadata(); if (m == nullptr) { - __ cmpptr(reg1, NULL_WORD); + __ testptr(reg1, reg1); } else { ShouldNotReachHere(); } @@ -2678,7 +2683,7 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, // In 64bit oops are single register jobject o = c->as_jobject(); if (o == nullptr) { - __ cmpptr(reg1, NULL_WORD); + __ testptr(reg1, reg1); } else { __ cmpoop(reg1, o, rscratch1); } @@ -3146,7 +3151,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { #endif // _LP64 - __ cmpl(rax, 0); + __ testl(rax, rax); __ jcc(Assembler::equal, *stub->continuation()); __ mov(tmp, rax); @@ -3288,7 +3293,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { __ pop(dst); __ pop(src); - __ cmpl(src, 0); + __ testl(src, src); __ jcc(Assembler::notEqual, cont); __ bind(slow); @@ -3635,13 +3640,33 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { __ verify_oop(obj); - if (tmp != obj) { - __ mov(tmp, obj); +#ifdef ASSERT + if (obj == tmp) { +#ifdef _LP64 + assert_different_registers(obj, rscratch1, mdo_addr.base(), mdo_addr.index()); +#else + assert_different_registers(obj, mdo_addr.base(), mdo_addr.index()); +#endif + } else { +#ifdef _LP64 + assert_different_registers(obj, tmp, rscratch1, mdo_addr.base(), mdo_addr.index()); +#else + assert_different_registers(obj, tmp, mdo_addr.base(), mdo_addr.index()); +#endif } +#endif if (do_null) { - __ testptr(tmp, tmp); + __ testptr(obj, obj); __ jccb(Assembler::notZero, update); if (!TypeEntries::was_null_seen(current_klass)) { + __ testptr(mdo_addr, TypeEntries::null_seen); +#ifndef ASSERT + __ jccb(Assembler::notZero, next); // already set +#else + __ jcc(Assembler::notZero, next); // already set +#endif + // atomic update to prevent overwriting Klass* with 0 + __ lock(); __ orptr(mdo_addr, TypeEntries::null_seen); } if (do_update) { @@ -3652,7 +3677,7 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { __ jmp(next); } } else { - __ testptr(tmp, tmp); + __ testptr(obj, obj); __ jcc(Assembler::notZero, update); __ stop("unexpected null obj"); #endif @@ -3664,7 +3689,7 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { #ifdef ASSERT if (exact_klass != nullptr) { Label ok; - __ load_klass(tmp, tmp, tmp_load_klass); + __ load_klass(tmp, obj, tmp_load_klass); __ push(tmp); __ mov_metadata(tmp, exact_klass->constant_encoding()); __ cmpptr(tmp, Address(rsp, 0)); @@ -3679,9 +3704,11 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { if (exact_klass != nullptr) { __ mov_metadata(tmp, exact_klass->constant_encoding()); } else { - __ load_klass(tmp, tmp, tmp_load_klass); + __ load_klass(tmp, obj, tmp_load_klass); } - +#ifdef _LP64 + __ mov(rscratch1, tmp); // save original value before XOR +#endif __ xorptr(tmp, mdo_addr); __ testptr(tmp, TypeEntries::type_klass_mask); // klass seen before, nothing to do. The unknown bit may have been @@ -3692,23 +3719,23 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. if (TypeEntries::is_type_none(current_klass)) { - __ cmpptr(mdo_addr, 0); - __ jccb(Assembler::equal, none); - __ cmpptr(mdo_addr, TypeEntries::null_seen); - __ jccb(Assembler::equal, none); + __ testptr(mdo_addr, TypeEntries::type_mask); + __ jccb(Assembler::zero, none); +#ifdef _LP64 // There is a chance that the checks above (re-reading profiling // data from memory) fail if another thread has just set the // profiling to this obj's klass + __ mov(tmp, rscratch1); // get back original value before XOR __ xorptr(tmp, mdo_addr); __ testptr(tmp, TypeEntries::type_klass_mask); __ jccb(Assembler::zero, next); +#endif } } else { assert(ciTypeEntries::valid_ciklass(current_klass) != nullptr && ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only"); - __ movptr(tmp, mdo_addr); - __ testptr(tmp, TypeEntries::type_unknown); + __ testptr(mdo_addr, TypeEntries::type_unknown); __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. } @@ -3721,6 +3748,10 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { __ bind(none); // first time here. Set profile type. __ movptr(mdo_addr, tmp); +#ifdef ASSERT + __ andptr(tmp, TypeEntries::type_klass_mask); + __ verify_klass_ptr(tmp); +#endif } } else { // There's a single possible klass at this profile point @@ -3735,10 +3766,8 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { { Label ok; __ push(tmp); - __ cmpptr(mdo_addr, 0); - __ jcc(Assembler::equal, ok); - __ cmpptr(mdo_addr, TypeEntries::null_seen); - __ jcc(Assembler::equal, ok); + __ testptr(mdo_addr, TypeEntries::type_mask); + __ jcc(Assembler::zero, ok); // may have been set by another thread __ mov_metadata(tmp, exact_klass->constant_encoding()); __ xorptr(tmp, mdo_addr); @@ -3754,20 +3783,22 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { #endif // first time here. Set profile type. __ movptr(mdo_addr, tmp); +#ifdef ASSERT + __ andptr(tmp, TypeEntries::type_klass_mask); + __ verify_klass_ptr(tmp); +#endif } else { assert(ciTypeEntries::valid_ciklass(current_klass) != nullptr && ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent"); - __ movptr(tmp, mdo_addr); - __ testptr(tmp, TypeEntries::type_unknown); + __ testptr(mdo_addr, TypeEntries::type_unknown); __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. __ orptr(mdo_addr, TypeEntries::type_unknown); } } - - __ bind(next); } + __ bind(next); } void LIR_Assembler::emit_delay(LIR_OpDelay*) { diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index c760722187a38..ce9133986178c 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -69,7 +69,7 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr const Register thread = disp_hdr; get_thread(thread); #endif - fast_lock_impl(obj, hdr, thread, tmp, slow_case); + lightweight_lock(obj, hdr, thread, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { Label done; // and mark it as unlocked @@ -135,7 +135,7 @@ void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_ if (LockingMode == LM_LIGHTWEIGHT) { movptr(disp_hdr, Address(obj, hdr_offset)); andptr(disp_hdr, ~(int32_t)markWord::lock_mask_in_place); - fast_unlock_impl(obj, disp_hdr, hdr, slow_case); + lightweight_unlock(obj, disp_hdr, hdr, slow_case); } else if (LockingMode == LM_LEGACY) { // test if object header is pointing to the displaced header, and if so, restore // the displaced header in the object - if the object header is not pointing to diff --git a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp index 7dd83bcc7a5bf..8b56f464f2739 100644 --- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp +++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp @@ -798,6 +798,14 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) { const Register handler_addr = rbx; const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread); + if (AbortVMOnException) { + __ enter(); + save_live_registers(sasm, 2); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, check_abort_on_vm_exception), rax); + restore_live_registers(sasm); + __ leave(); + } + // verify that only rax, is valid at this time __ invalidate_registers(false, true, true, true, true, true); diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 0dc02d9f07d8b..84a1f18951803 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -621,7 +621,7 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp movptr(Address(boxReg, 0), tmpReg); } else { assert(LockingMode == LM_LIGHTWEIGHT, ""); - fast_lock_impl(objReg, tmpReg, thread, scrReg, NO_COUNT); + lightweight_lock(objReg, tmpReg, thread, scrReg, NO_COUNT); jmp(COUNT); } jmp(DONE_LABEL); @@ -925,7 +925,7 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t bind (Stacked); if (LockingMode == LM_LIGHTWEIGHT) { mov(boxReg, tmpReg); - fast_unlock_impl(objReg, boxReg, tmpReg, NO_COUNT); + lightweight_unlock(objReg, boxReg, tmpReg, NO_COUNT); jmp(COUNT); } else if (LockingMode == LM_LEGACY) { movptr(tmpReg, Address (boxReg, 0)); // re-fetch diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index b6e88c969f2ed..7e4b24e097d5e 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -496,7 +496,7 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { // do some validation of frame elements // first the method - Method* m = *interpreter_frame_method_addr(); + Method* m = safe_interpreter_frame_method(); // validate the method we'd find in this potential sender if (!Method::is_valid_method(m)) return false; diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index fc5056d2d9383..0f1c808b27be8 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -51,15 +51,28 @@ void InterpreterMacroAssembler::jump_to_entry(address entry) { void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { Label update, next, none; +#ifdef _LP64 + assert_different_registers(obj, rscratch1, mdo_addr.base(), mdo_addr.index()); +#else + assert_different_registers(obj, mdo_addr.base(), mdo_addr.index()); +#endif + interp_verify_oop(obj, atos); testptr(obj, obj); jccb(Assembler::notZero, update); + testptr(mdo_addr, TypeEntries::null_seen); + jccb(Assembler::notZero, next); // null already seen. Nothing to do anymore. + // atomic update to prevent overwriting Klass* with 0 + lock(); orptr(mdo_addr, TypeEntries::null_seen); jmpb(next); bind(update); load_klass(obj, obj, rscratch1); +#ifdef _LP64 + mov(rscratch1, obj); +#endif xorptr(obj, mdo_addr); testptr(obj, TypeEntries::type_klass_mask); @@ -74,12 +87,15 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& md jccb(Assembler::equal, none); cmpptr(mdo_addr, TypeEntries::null_seen); jccb(Assembler::equal, none); +#ifdef _LP64 // There is a chance that the checks above (re-reading profiling // data from memory) fail if another thread has just set the // profiling to this obj's klass + mov(obj, rscratch1); xorptr(obj, mdo_addr); testptr(obj, TypeEntries::type_klass_mask); jccb(Assembler::zero, next); +#endif // different than before. Cannot keep accurate profile. orptr(mdo_addr, TypeEntries::type_unknown); @@ -88,6 +104,10 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& md bind(none); // first time here. Set profile type. movptr(mdo_addr, obj); +#ifdef ASSERT + andptr(obj, TypeEntries::type_klass_mask); + verify_klass_ptr(obj); +#endif bind(next); } @@ -1074,7 +1094,7 @@ void InterpreterMacroAssembler::remove_activation( // Check that all monitors are unlocked { Label loop, exception, entry, restart; - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); const Address monitor_block_top( rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); const Address monitor_block_bot( @@ -1150,6 +1170,8 @@ void InterpreterMacroAssembler::remove_activation( NOT_LP64(get_thread(rthread);) + // check if already enabled - if so no re-enabling needed + assert(sizeof(StackOverflow::StackGuardState) == 4, "unexpected size"); cmpl(Address(rthread, JavaThread::stack_guard_state_offset()), StackOverflow::stack_guard_enabled); jcc(Assembler::equal, no_reserved_zone_enabling); @@ -1232,7 +1254,7 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) { #endif // Load object header, prepare for CAS from unlocked to locked. movptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - fast_lock_impl(obj_reg, swap_reg, thread, tmp_reg, slow_case); + lightweight_lock(obj_reg, swap_reg, thread, tmp_reg, slow_case); } else if (LockingMode == LM_LEGACY) { // Load immediate 1 into swap_reg %rax movl(swap_reg, 1); @@ -1362,7 +1384,7 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) { // Try to swing header from locked to unlocked. movptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); andptr(swap_reg, ~(int32_t)markWord::lock_mask_in_place); - fast_unlock_impl(obj_reg, swap_reg, header_reg, slow_case); + lightweight_unlock(obj_reg, swap_reg, header_reg, slow_case); } else if (LockingMode == LM_LEGACY) { // Load the old header from BasicLock structure movptr(header_reg, Address(swap_reg, diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index da3bc94f30478..101d8eb0ace04 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -9801,7 +9801,7 @@ void MacroAssembler::check_stack_alignment(Register sp, const char* msg, unsigne bind(L_stack_ok); } -// Implements fast-locking. +// Implements lightweight-locking. // Branches to slow upon failure to lock the object, with ZF cleared. // Falls through upon success with unspecified ZF. // @@ -9809,7 +9809,7 @@ void MacroAssembler::check_stack_alignment(Register sp, const char* msg, unsigne // hdr: the (pre-loaded) header of the object, must be rax // thread: the thread which attempts to lock obj // tmp: a temporary register -void MacroAssembler::fast_lock_impl(Register obj, Register hdr, Register thread, Register tmp, Label& slow) { +void MacroAssembler::lightweight_lock(Register obj, Register hdr, Register thread, Register tmp, Label& slow) { assert(hdr == rax, "header must be in rax for cmpxchg"); assert_different_registers(obj, hdr, thread, tmp); @@ -9837,14 +9837,14 @@ void MacroAssembler::fast_lock_impl(Register obj, Register hdr, Register thread, movl(Address(thread, JavaThread::lock_stack_top_offset()), tmp); } -// Implements fast-unlocking. +// Implements lightweight-unlocking. // Branches to slow upon failure, with ZF cleared. // Falls through upon success, with unspecified ZF. // // obj: the object to be unlocked // hdr: the (pre-loaded) header of the object, must be rax // tmp: a temporary register -void MacroAssembler::fast_unlock_impl(Register obj, Register hdr, Register tmp, Label& slow) { +void MacroAssembler::lightweight_unlock(Register obj, Register hdr, Register tmp, Label& slow) { assert(hdr == rax, "header must be in rax for cmpxchg"); assert_different_registers(obj, hdr, tmp); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 61db66ae00f39..7eb037e6fe26e 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -876,6 +876,7 @@ class MacroAssembler: public Assembler { void testptr(Register src, int32_t imm32) { LP64_ONLY(testq(src, imm32)) NOT_LP64(testl(src, imm32)); } void testptr(Register src1, Address src2) { LP64_ONLY(testq(src1, src2)) NOT_LP64(testl(src1, src2)); } + void testptr(Address src, int32_t imm32) { LP64_ONLY(testq(src, imm32)) NOT_LP64(testl(src, imm32)); } void testptr(Register src1, Register src2); void xorptr(Register dst, Register src) { LP64_ONLY(xorq(dst, src)) NOT_LP64(xorl(dst, src)); } @@ -2022,8 +2023,8 @@ class MacroAssembler: public Assembler { void check_stack_alignment(Register sp, const char* msg, unsigned bias = 0, Register tmp = noreg); - void fast_lock_impl(Register obj, Register hdr, Register thread, Register tmp, Label& slow); - void fast_unlock_impl(Register obj, Register hdr, Register tmp, Label& slow); + void lightweight_lock(Register obj, Register hdr, Register thread, Register tmp, Label& slow); + void lightweight_unlock(Register obj, Register hdr, Register tmp, Label& slow); }; /** diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index 7995ed5b265bd..c391349cfa323 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -1717,7 +1717,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, assert(LockingMode == LM_LIGHTWEIGHT, "must be"); // Load object header __ movptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ fast_lock_impl(obj_reg, swap_reg, thread, lock_reg, slow_path_lock); + __ lightweight_lock(obj_reg, swap_reg, thread, lock_reg, slow_path_lock); } __ bind(count_mon); __ inc_held_monitor_count(); @@ -1876,7 +1876,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, assert(LockingMode == LM_LIGHTWEIGHT, "must be"); __ movptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); __ andptr(swap_reg, ~(int32_t)markWord::lock_mask_in_place); - __ fast_unlock_impl(obj_reg, swap_reg, lock_reg, slow_path_unlock); + __ lightweight_unlock(obj_reg, swap_reg, lock_reg, slow_path_unlock); __ dec_held_monitor_count(); } diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 20495135c642e..0712ba50c078a 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -2187,7 +2187,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, assert(LockingMode == LM_LIGHTWEIGHT, "must be"); // Load object header __ movptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ fast_lock_impl(obj_reg, swap_reg, r15_thread, rscratch1, slow_path_lock); + __ lightweight_lock(obj_reg, swap_reg, r15_thread, rscratch1, slow_path_lock); } __ bind(count_mon); __ inc_held_monitor_count(); @@ -2331,7 +2331,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, assert(LockingMode == LM_LIGHTWEIGHT, "must be"); __ movptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); __ andptr(swap_reg, ~(int32_t)markWord::lock_mask_in_place); - __ fast_unlock_impl(obj_reg, swap_reg, lock_reg, slow_path_unlock); + __ lightweight_unlock(obj_reg, swap_reg, lock_reg, slow_path_unlock); __ dec_held_monitor_count(); } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 014737322d81b..2a52fa200c94e 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2324,7 +2324,7 @@ address StubGenerator::generate_base64_decodeBlock() { const Register isURL = c_rarg5;// Base64 or URL character set __ movl(isMIME, Address(rbp, 2 * wordSize)); #else - const Address dp_mem(rbp, 6 * wordSize); // length is on stack on Win64 + const Address dp_mem(rbp, 6 * wordSize); // length is on stack on Win64 const Address isURL_mem(rbp, 7 * wordSize); const Register isURL = r10; // pick the volatile windows register const Register dp = r12; @@ -2546,10 +2546,12 @@ address StubGenerator::generate_base64_decodeBlock() { // output_size in r13 // Strip pad characters, if any, and adjust length and mask + __ addq(length, start_offset); __ cmpb(Address(source, length, Address::times_1, -1), '='); __ jcc(Assembler::equal, L_padding); __ BIND(L_donePadding); + __ subq(length, start_offset); // Output size is (64 - output_size), output mask is (all 1s >> output_size). __ kmovql(input_mask, rax); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_adler.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_adler.cpp index bb8e8f6b1eac8..84f5cc80b0d3a 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_adler.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_adler.cpp @@ -330,6 +330,7 @@ address StubGenerator::generate_updateBytesAdler32() { __ movq(r13, xtmp4); __ movq(r12, xtmp3); + __ vzeroupper(); __ leave(); __ ret(0); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_chacha.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_chacha.cpp index f94297ce82d73..47354f4fc7cf7 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_chacha.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_chacha.cpp @@ -291,6 +291,9 @@ address StubGenerator::generate_chacha20Block_avx() { // registers. That length should be returned through %rax. __ mov64(rax, outlen); + if (outlen == 256) { + __ vzeroupper(); + } __ leave(); __ ret(0); return start; @@ -460,6 +463,7 @@ address StubGenerator::generate_chacha20Block_avx512() { // and that length should be returned through %rax. __ mov64(rax, 1024); + __ vzeroupper(); __ leave(); __ ret(0); return start; diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index 48f5b860faf4c..817baea61746f 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -477,7 +477,7 @@ void TemplateInterpreterGenerator::generate_counter_overflow(Label& do_continue) void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { // monitor entry size: see picture of stack in frame_x86.hpp - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); // total overhead size: entry_size + (saved rbp through expr stack // bottom). be sure to change this if you add/subtract anything @@ -566,7 +566,7 @@ void TemplateInterpreterGenerator::lock_method() { const Address monitor_block_top( rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); #ifdef ASSERT { diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index d56cc67bff9f7..62d667abe0d19 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -4319,7 +4319,7 @@ void TemplateTable::monitorenter() { rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); const Address monitor_block_bot( rbp, frame::interpreter_frame_initial_sp_offset * wordSize); - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); Label allocated; @@ -4416,7 +4416,7 @@ void TemplateTable::monitorexit() { rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); const Address monitor_block_bot( rbp, frame::interpreter_frame_initial_sp_offset * wordSize); - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); Register rtop = LP64_ONLY(c_rarg1) NOT_LP64(rdx); Register rbot = LP64_ONLY(c_rarg2) NOT_LP64(rbx); diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index b4e9e721b5ad0..1f9238c60cba1 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1124,6 +1124,7 @@ 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 @@ -1139,6 +1140,13 @@ 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); + } +#endif // _LP64 // Base64 Intrinsics (Check the condition for which the intrinsic will be active) if (UseAVX >= 2) { diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 55f465bf76b31..1a37e3124d573 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -8985,9 +8985,9 @@ instruct vmask_cmp_node(rRegI dst, vec src1, vec src2, kReg mask, kReg ktmp1, kR %} -instruct vmask_gen(kReg dst, rRegL len, rRegL temp) %{ +instruct vmask_gen(kReg dst, rRegL len, rRegL temp, rFlagsReg cr) %{ match(Set dst (VectorMaskGen len)); - effect(TEMP temp); + effect(TEMP temp, KILL cr); format %{ "vector_mask_gen32 $dst, $len \t! vector mask generator" %} ins_encode %{ __ genmask($dst$$KRegister, $len$$Register, $temp$$Register); diff --git a/src/hotspot/cpu/zero/frame_zero.cpp b/src/hotspot/cpu/zero/frame_zero.cpp index 923d3082b25e7..5ddd23a9d59ef 100644 --- a/src/hotspot/cpu/zero/frame_zero.cpp +++ b/src/hotspot/cpu/zero/frame_zero.cpp @@ -82,7 +82,6 @@ BasicObjectLock* frame::interpreter_frame_monitor_begin() const { return get_interpreterState()->monitor_base(); } -// Pointer beyond the "oldest/deepest" BasicObjectLock on stack. BasicObjectLock* frame::interpreter_frame_monitor_end() const { return (BasicObjectLock*) get_interpreterState()->stack_base(); } diff --git a/src/hotspot/cpu/zero/globalDefinitions_zero.hpp b/src/hotspot/cpu/zero/globalDefinitions_zero.hpp index b8f01f4045486..ca11d106c2618 100644 --- a/src/hotspot/cpu/zero/globalDefinitions_zero.hpp +++ b/src/hotspot/cpu/zero/globalDefinitions_zero.hpp @@ -30,6 +30,8 @@ #define SUPPORTS_NATIVE_CX8 #endif +#define DEFAULT_CACHE_LINE_SIZE 64 + #define SUPPORT_MONITOR_COUNT #ifdef __APPLE__ diff --git a/src/hotspot/cpu/zero/vm_version_zero.cpp b/src/hotspot/cpu/zero/vm_version_zero.cpp index 3d17e159a619c..a99885a533df8 100644 --- a/src/hotspot/cpu/zero/vm_version_zero.cpp +++ b/src/hotspot/cpu/zero/vm_version_zero.cpp @@ -137,6 +137,12 @@ void VM_Version::initialize() { #ifdef ASSERT UNSUPPORTED_OPTION(CountCompiledCalls); #endif + + // Supports 8-byte cmpxchg with compiler built-ins. + // These built-ins are supposed to be implemented on + // all platforms (even if not natively), so we claim + // the support unconditionally. + _supports_cx8 = true; } void VM_Version::initialize_cpu_information(void) { diff --git a/src/hotspot/os/aix/globals_aix.hpp b/src/hotspot/os/aix/globals_aix.hpp index a047e79b695fa..fb353348a5364 100644 --- a/src/hotspot/os/aix/globals_aix.hpp +++ b/src/hotspot/os/aix/globals_aix.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2018 SAP SE. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,11 +49,12 @@ "Allow VM to run with EXTSHM=ON.") \ \ /* Maximum expected size of the data segment. That correlates with the */ \ - /* to the maximum C Heap consumption we expect. */ \ - /* We need to know this because we need to leave "breathing space" for the */ \ - /* data segment when placing the java heap. If that space is too small, we */ \ - /* reduce our chance of getting a low heap address (needed for compressed */ \ - /* Oops). */ \ + /* maximum C Heap consumption we expect. */ \ + /* We need to leave "breathing space" for the data segment when */ \ + /* placing the java heap. If the MaxExpectedDataSegmentSize setting */ \ + /* is too small, we might run into resource issues creating many native */ \ + /* threads, if it is too large, we reduce our chance of getting a low heap */ \ + /* address (needed for compressed Oops). */ \ product(uintx, MaxExpectedDataSegmentSize, 8*G, \ "Maximum expected Data Segment Size.") \ \ diff --git a/src/hotspot/os/aix/libodm_aix.cpp b/src/hotspot/os/aix/libodm_aix.cpp index db8e8a5d96009..9fe0fb7abd842 100644 --- a/src/hotspot/os/aix/libodm_aix.cpp +++ b/src/hotspot/os/aix/libodm_aix.cpp @@ -29,13 +29,16 @@ #include #include #include "runtime/arguments.hpp" +#include "runtime/os.hpp" dynamicOdm::dynamicOdm() { - const char *libodmname = "/usr/lib/libodm.a(shr_64.o)"; - _libhandle = dlopen(libodmname, RTLD_MEMBER | RTLD_NOW); + const char* libodmname = "/usr/lib/libodm.a(shr_64.o)"; + char ebuf[512]; + _libhandle = os::dll_load(libodmname, ebuf, sizeof(ebuf)); + if (!_libhandle) { - trcVerbose("Couldn't open %s", libodmname); + trcVerbose("Cannot load %s (error %s)", libodmname, ebuf); return; } _odm_initialize = (fun_odm_initialize )dlsym(_libhandle, "odm_initialize" ); @@ -45,14 +48,14 @@ dynamicOdm::dynamicOdm() { _odm_terminate = (fun_odm_terminate )dlsym(_libhandle, "odm_terminate" ); if (!_odm_initialize || !_odm_set_path || !_odm_mount_class || !_odm_get_obj || !_odm_terminate) { trcVerbose("Couldn't find all required odm symbols from %s", libodmname); - dlclose(_libhandle); + os::dll_unload(_libhandle); _libhandle = nullptr; return; } } dynamicOdm::~dynamicOdm() { - if (_libhandle) { dlclose(_libhandle); } + if (_libhandle) { os::dll_unload(_libhandle); } } diff --git a/src/hotspot/os/aix/libperfstat_aix.cpp b/src/hotspot/os/aix/libperfstat_aix.cpp index 79b8f09cc65ec..f547b4c78e77c 100644 --- a/src/hotspot/os/aix/libperfstat_aix.cpp +++ b/src/hotspot/os/aix/libperfstat_aix.cpp @@ -26,6 +26,7 @@ #include "libperfstat_aix.hpp" #include "misc_aix.hpp" +#include "runtime/os.hpp" #include @@ -71,11 +72,11 @@ static fun_perfstat_reset_t g_fun_perfstat_reset = nullptr; static fun_wpar_getcid_t g_fun_wpar_getcid = nullptr; bool libperfstat::init() { - - // Dynamically load the libperfstat porting library. - g_libhandle = dlopen("/usr/lib/libperfstat.a(shr_64.o)", RTLD_MEMBER | RTLD_NOW); + const char* libperfstat = "/usr/lib/libperfstat.a(shr_64.o)"; + char ebuf[512]; + g_libhandle = os::dll_load(libperfstat, ebuf, sizeof(ebuf)); if (!g_libhandle) { - trcVerbose("Cannot load libperfstat.a (dlerror: %s)", dlerror()); + trcVerbose("Cannot load %s (error: %s)", libperfstat, ebuf); return false; } @@ -113,7 +114,7 @@ bool libperfstat::init() { void libperfstat::cleanup() { if (g_libhandle) { - dlclose(g_libhandle); + os::dll_unload(g_libhandle); g_libhandle = nullptr; } diff --git a/src/hotspot/os/aix/loadlib_aix.cpp b/src/hotspot/os/aix/loadlib_aix.cpp index 3a71a78e45cea..bc71ca2e3101b 100644 --- a/src/hotspot/os/aix/loadlib_aix.cpp +++ b/src/hotspot/os/aix/loadlib_aix.cpp @@ -225,6 +225,7 @@ static bool reload_table() { lm->path = g_stringlist.add(ldi->ldinfo_filename); if (!lm->path) { trcVerbose("OOM."); + free(lm); goto cleanup; } @@ -246,6 +247,7 @@ static bool reload_table() { lm->member = g_stringlist.add(p_mbr_name); if (!lm->member) { trcVerbose("OOM."); + free(lm); goto cleanup; } } else { diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 91a9bbcff7137..3321c32a68791 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -828,7 +828,8 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, log_warning(os, thread)("Failed to start thread \"%s\" - pthread_create failed (%d=%s) for attributes: %s.", thread->name(), ret, os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); // Log some OS information which might explain why creating the thread failed. - log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads()); + log_warning(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads()); + log_warning(os, thread)("Checking JVM parameter MaxExpectedDataSegmentSize (currently " SIZE_FORMAT "k) might be helpful", MaxExpectedDataSegmentSize/K); LogStream st(Log(os, thread)::info()); os::Posix::print_rlimit_info(&st); os::print_memory_info(&st); @@ -1010,6 +1011,10 @@ int os::current_process_id() { // directory not the java application's temp directory, ala java.io.tmpdir. const char* os::get_temp_directory() { return "/tmp"; } +void os::prepare_native_symbols() { + LoadedLibraries::reload(); +} + // Check if addr is inside libjvm.so. bool os::address_is_in_vm(address addr) { @@ -1097,8 +1102,6 @@ bool os::dll_address_to_library_name(address addr, char* buf, return true; } -// Loads .dll/.so and in case of error it checks if .dll/.so was built -// for the same architecture as Hotspot is running on. void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { log_info(os)("attempting shared library load of %s", filename); @@ -1109,12 +1112,25 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { } if (!filename || strlen(filename) == 0) { - ::strncpy(ebuf, "dll_load: empty filename specified", ebuflen - 1); + if (ebuf != nullptr && ebuflen > 0) { + ::strncpy(ebuf, "dll_load: empty filename specified", ebuflen - 1); + } return nullptr; } - // RTLD_LAZY is currently not implemented. The dl is loaded immediately with all its dependants. - void * result= ::dlopen(filename, RTLD_LAZY); + // RTLD_LAZY has currently the same behavior as RTLD_NOW + // The dl is loaded immediately with all its dependants. + int dflags = RTLD_LAZY; + // check for filename ending with ')', it indicates we want to load + // a MEMBER module that is a member of an archive. + int flen = strlen(filename); + if (flen > 0 && filename[flen - 1] == ')') { + dflags |= RTLD_MEMBER; + } + + void* result; + const char* error_report = nullptr; + result = Aix_dlopen(filename, dflags, &error_report); if (result != nullptr) { Events::log_dll_message(nullptr, "Loaded shared library %s", filename); // Reload dll cache. Don't do this in signal handling. @@ -1123,7 +1139,6 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { return result; } else { // error analysis when dlopen fails - const char* error_report = ::dlerror(); if (error_report == nullptr) { error_report = "dlerror returned no error description"; } @@ -3008,3 +3023,4 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {} void os::jfr_report_memory_info() {} #endif // INCLUDE_JFR + diff --git a/src/hotspot/os/aix/os_aix.hpp b/src/hotspot/os/aix/os_aix.hpp index 9756734efd217..a1db2b2be3cc7 100644 --- a/src/hotspot/os/aix/os_aix.hpp +++ b/src/hotspot/os/aix/os_aix.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2013, 2016 SAP SE. All rights reserved. + * Copyright (c) 2013, 2023 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 @@ -174,6 +174,7 @@ class os::Aix { static bool platform_print_native_stack(outputStream* st, const void* context, char *buf, int buf_size, address& lastpc); static void* resolve_function_descriptor(void* p); + }; #endif // OS_AIX_OS_AIX_HPP diff --git a/src/hotspot/os/aix/os_aix.inline.hpp b/src/hotspot/os/aix/os_aix.inline.hpp index 5f7415e4a5181..f7e7ee8abc65a 100644 --- a/src/hotspot/os/aix/os_aix.inline.hpp +++ b/src/hotspot/os/aix/os_aix.inline.hpp @@ -52,7 +52,7 @@ inline bool os::must_commit_stack_guard_pages() { inline void os::map_stack_shadow_pages(address sp) { } -// stubbed-out trim-native support +// Trim-native support, stubbed out for now, may be enabled later inline bool os::can_trim_native_heap() { return false; } inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; } diff --git a/src/hotspot/os/aix/os_perf_aix.cpp b/src/hotspot/os/aix/os_perf_aix.cpp index bdb70250a76a9..f4e13374fd7c4 100644 --- a/src/hotspot/os/aix/os_perf_aix.cpp +++ b/src/hotspot/os/aix/os_perf_aix.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2022, IBM Corp. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, IBM Corp. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,6 +87,7 @@ static bool read_psinfo(const u_longlong_t& pid, psinfo_t& psinfo) { } len = fread(&psinfo, 1, sizeof(psinfo_t), fp); + fclose(fp); return len == sizeof(psinfo_t); } diff --git a/src/hotspot/os/aix/porting_aix.cpp b/src/hotspot/os/aix/porting_aix.cpp index ab84dc8102770..68233097b4957 100644 --- a/src/hotspot/os/aix/porting_aix.cpp +++ b/src/hotspot/os/aix/porting_aix.cpp @@ -21,6 +21,12 @@ * questions. * */ +// needs to be defined first, so that the implicit loaded xcoff.h header defines +// the right structures to analyze the loader header of 64 Bit executable files +// this is needed for rtv_linkedin_libpath() to get the linked (burned) in library +// search path of an XCOFF executable +#define __XCOFF64__ +#include #include "asm/assembler.hpp" #include "compiler/disassembler.hpp" @@ -891,3 +897,275 @@ bool AixMisc::query_stack_bounds_for_current_thread(stackbounds_t* out) { return true; } + +// variables needed to emulate linux behavior in os::dll_load() if library is loaded twice +static pthread_mutex_t g_handletable_mutex = PTHREAD_MUTEX_INITIALIZER; + +struct TableLocker { + TableLocker() { pthread_mutex_lock(&g_handletable_mutex); } + ~TableLocker() { pthread_mutex_unlock(&g_handletable_mutex); } +}; +struct handletableentry{ + void* handle; + ino64_t inode; + dev64_t devid; + uint refcount; +}; +constexpr unsigned init_num_handles = 128; +static unsigned max_handletable = 0; +static unsigned g_handletable_used = 0; +// We start with an empty array. At first use we will dynamically allocate memory for 128 entries. +// If this table is full we dynamically reallocate a memory reagion of double size, and so on. +static struct handletableentry* p_handletable = nullptr; + +// get the library search path burned in to the executable file during linking +// If the libpath cannot be retrieved return an empty path +static const char* rtv_linkedin_libpath() { + constexpr int bufsize = 4096; + static char buffer[bufsize]; + static const char* libpath = 0; + + // we only try to retrieve the libpath once. After that try we + // let libpath point to buffer, which then contains a valid libpath + // or an empty string + if (libpath != nullptr) { + return libpath; + } + + // retrieve the path to the currently running executable binary + // to open it + snprintf(buffer, 100, "/proc/%ld/object/a.out", (long)getpid()); + FILE* f = nullptr; + struct xcoffhdr the_xcoff; + struct scnhdr the_scn; + struct ldhdr the_ldr; + constexpr size_t xcoffsz = FILHSZ + _AOUTHSZ_EXEC; + STATIC_ASSERT(sizeof(the_xcoff) == xcoffsz); + STATIC_ASSERT(sizeof(the_scn) == SCNHSZ); + STATIC_ASSERT(sizeof(the_ldr) == LDHDRSZ); + // read the generic XCOFF header and analyze the substructures + // to find the burned in libpath. In any case of error perform the assert + if (nullptr == (f = fopen(buffer, "r")) || + xcoffsz != fread(&the_xcoff, 1, xcoffsz, f) || + the_xcoff.filehdr.f_magic != U64_TOCMAGIC || + 0 != fseek(f, (FILHSZ + the_xcoff.filehdr.f_opthdr + (the_xcoff.aouthdr.o_snloader -1)*SCNHSZ), SEEK_SET) || + SCNHSZ != fread(&the_scn, 1, SCNHSZ, f) || + 0 != strcmp(the_scn.s_name, ".loader") || + 0 != fseek(f, the_scn.s_scnptr, SEEK_SET) || + LDHDRSZ != fread(&the_ldr, 1, LDHDRSZ, f) || + 0 != fseek(f, the_scn.s_scnptr + the_ldr.l_impoff, SEEK_SET) || + 0 == fread(buffer, 1, bufsize, f)) { + buffer[0] = 0; + assert(false, "could not retrieve burned in library path from executables loader section"); + } + + if (f) { + fclose(f); + } + libpath = buffer; + + return libpath; +} + +// Simulate the library search algorithm of dlopen() (in os::dll_load) +static bool search_file_in_LIBPATH(const char* path, struct stat64x* stat) { + if (path == nullptr) + return false; + + char* path2 = os::strdup(path); + // if exist, strip off trailing (shr_64.o) or similar + char* substr; + if (path2[strlen(path2) - 1] == ')' && (substr = strrchr(path2, '('))) { + *substr = 0; + } + + bool ret = false; + // If FilePath contains a slash character, FilePath is used directly, + // and no directories are searched. + // But if FilePath does not start with / or . we have to prepend it with ./ + if (strchr(path2, '/')) { + stringStream combined; + if (*path2 == '/' || *path2 == '.') { + combined.print("%s", path2); + } else { + combined.print("./%s", path2); + } + ret = (0 == stat64x(combined.base(), stat)); + os::free(path2); + return ret; + } + + const char* env = getenv("LIBPATH"); + if (env == nullptr) { + // no LIBPATH, try with LD_LIBRARY_PATH + env = getenv("LD_LIBRARY_PATH"); + } + + stringStream Libpath; + if (env == nullptr) { + // no LIBPATH or LD_LIBRARY_PATH given -> try only with burned in libpath + Libpath.print("%s", rtv_linkedin_libpath()); + } else if (*env == 0) { + // LIBPATH or LD_LIBRARY_PATH given but empty -> try first with burned + // in libpath and with current working directory second + Libpath.print("%s:.", rtv_linkedin_libpath()); + } else { + // LIBPATH or LD_LIBRARY_PATH given with content -> try first with + // LIBPATH or LD_LIBRARY_PATH and second with burned in libpath. + // No check against current working directory + Libpath.print("%s:%s", env, rtv_linkedin_libpath()); + } + + char* libpath = os::strdup(Libpath.base()); + + char *saveptr, *token; + for (token = strtok_r(libpath, ":", &saveptr); token != nullptr; token = strtok_r(nullptr, ":", &saveptr)) { + stringStream combined; + combined.print("%s/%s", token, path2); + if ((ret = (0 == stat64x(combined.base(), stat)))) + break; + } + + os::free(libpath); + os::free(path2); + return ret; +} + +// specific AIX versions for ::dlopen() and ::dlclose(), which handles the struct g_handletable +// This way we mimic dl handle equality for a library +// opened a second time, as it is implemented on other platforms. +void* Aix_dlopen(const char* filename, int Flags, const char** error_report) { + assert(error_report != nullptr, "error_report is nullptr"); + void* result; + struct stat64x libstat; + + if (false == search_file_in_LIBPATH(filename, &libstat)) { + // file with filename does not exist + #ifdef ASSERT + result = ::dlopen(filename, Flags); + assert(result == nullptr, "dll_load: Could not stat() file %s, but dlopen() worked; Have to improve stat()", filename); + #endif + *error_report = "Could not load module .\nSystem error: No such file or directory"; + return nullptr; + } + else { + unsigned i = 0; + TableLocker lock; + // check if library belonging to filename is already loaded. + // If yes use stored handle from previous ::dlopen() and increase refcount + for (i = 0; i < g_handletable_used; i++) { + if ((p_handletable + i)->handle && + (p_handletable + i)->inode == libstat.st_ino && + (p_handletable + i)->devid == libstat.st_dev) { + (p_handletable + i)->refcount++; + result = (p_handletable + i)->handle; + break; + } + } + if (i == g_handletable_used) { + // library not yet loaded. Check if there is space left in array + // to store new ::dlopen() handle + 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)); + assert(new_tab != nullptr, "no more memory for handletable"); + if (new_tab == nullptr) { + *error_report = "dlopen: no more memory for handletable"; + return nullptr; + } + max_handletable = new_max; + p_handletable = new_tab; + } + // Library not yet loaded; load it, then store its handle in handle table + result = ::dlopen(filename, Flags); + if (result != nullptr) { + g_handletable_used++; + (p_handletable + i)->handle = result; + (p_handletable + i)->inode = libstat.st_ino; + (p_handletable + i)->devid = libstat.st_dev; + (p_handletable + i)->refcount = 1; + } + else { + // error analysis when dlopen fails + *error_report = ::dlerror(); + if (*error_report == nullptr) { + *error_report = "dlerror returned no error description"; + } + } + } + } + return result; +} + +bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { + unsigned i = 0; + bool res = false; + + if (ebuf && ebuflen > 0) { + ebuf[0] = '\0'; + ebuf[ebuflen - 1] = '\0'; + } + + { + TableLocker lock; + // try to find handle in array, which means library was loaded by os::dll_load() call + for (i = 0; i < g_handletable_used; i++) { + if ((p_handletable + i)->handle == libhandle) { + // handle found, decrease refcount + assert((p_handletable + i)->refcount > 0, "Sanity"); + (p_handletable + i)->refcount--; + if ((p_handletable + i)->refcount > 0) { + // if refcount is still >0 then we have to keep library and just return true + return true; + } + // refcount == 0, so we have to ::dlclose() the lib + // and delete the entry from the array. + break; + } + } + + // If we reach this point either the libhandle was found with refcount == 0, or the libhandle + // was not found in the array at all. In both cases we have to ::dlclose the lib and perform + // the error handling. In the first case we then also have to delete the entry from the array + // while in the second case we simply have to nag. + res = (0 == ::dlclose(libhandle)); + if (!res) { + // error analysis when dlopen fails + const char* error_report = ::dlerror(); + if (error_report == nullptr) { + error_report = "dlerror returned no error description"; + } + if (ebuf != nullptr && ebuflen > 0) { + snprintf(ebuf, ebuflen - 1, "%s", error_report); + } + assert(false, "os::pd_dll_unload() ::dlclose() failed"); + } + + if (i < g_handletable_used) { + if (res) { + // First case: libhandle was found (with refcount == 0) and ::dlclose successful, + // so delete entry from array + g_handletable_used--; + // If the entry was the last one of the array, the previous g_handletable_used-- + // is sufficient to remove the entry from the array, otherwise we move the last + // entry of the array to the place of the entry we want to remove and overwrite it + if (i < g_handletable_used) { + *(p_handletable + i) = *(p_handletable + g_handletable_used); + (p_handletable + g_handletable_used)->handle = nullptr; + } + } + } + else { + // Second case: libhandle was not found (library was not loaded by os::dll_load()) + // therefore nag + assert(false, "os::pd_dll_unload() library was not loaded by os::dll_load()"); + } + } + + // Update the dll cache + LoadedLibraries::reload(); + + return res; +} // end: os::pd_dll_unload() + diff --git a/src/hotspot/os/aix/porting_aix.hpp b/src/hotspot/os/aix/porting_aix.hpp index 2c4c0e002a8fa..109eceee3fca5 100644 --- a/src/hotspot/os/aix/porting_aix.hpp +++ b/src/hotspot/os/aix/porting_aix.hpp @@ -115,4 +115,6 @@ class AixMisc { }; +void* Aix_dlopen(const char* filename, int Flags, const char** error_report); + #endif // OS_AIX_PORTING_AIX_HPP diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 79ea61c253641..4a2922cb7283d 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -891,6 +891,9 @@ bool os::address_is_in_vm(address addr) { return false; } +void os::prepare_native_symbols() { +} + bool os::dll_address_to_function_name(address addr, char *buf, int buflen, int *offset, bool demangle) { @@ -2485,3 +2488,25 @@ void os::jfr_report_memory_info() { } #endif // INCLUDE_JFR + +bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { + + if (ebuf && ebuflen > 0) { + ebuf[0] = '\0'; + ebuf[ebuflen - 1] = '\0'; + } + + bool res = (0 == ::dlclose(libhandle)); + if (!res) { + // error analysis when dlopen fails + const char* error_report = ::dlerror(); + if (error_report == nullptr) { + error_report = "dlerror returned no error description"; + } + if (ebuf != nullptr && ebuflen > 0) { + snprintf(ebuf, ebuflen - 1, "%s", error_report); + } + } + + return res; +} // end: os::pd_dll_unload() diff --git a/src/hotspot/os/bsd/os_bsd.inline.hpp b/src/hotspot/os/bsd/os_bsd.inline.hpp index f30ac61e463ff..2049b337118a3 100644 --- a/src/hotspot/os/bsd/os_bsd.inline.hpp +++ b/src/hotspot/os/bsd/os_bsd.inline.hpp @@ -55,7 +55,7 @@ inline bool os::must_commit_stack_guard_pages() { inline void os::map_stack_shadow_pages(address sp) { } -// stubbed-out trim-native support +// Trim-native support, stubbed out for now, may be enabled later inline bool os::can_trim_native_heap() { return false; } inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; } diff --git a/src/hotspot/os/linux/attachListener_linux.cpp b/src/hotspot/os/linux/attachListener_linux.cpp index 63c5bfef12594..715603d4bafc2 100644 --- a/src/hotspot/os/linux/attachListener_linux.cpp +++ b/src/hotspot/os/linux/attachListener_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -183,6 +183,8 @@ int LinuxAttachListener::init() { char initial_path[UNIX_PATH_MAX]; // socket file during setup int listener; // listener socket (file descriptor) + static_assert(sizeof(off_t) == 8, "Expected Large File Support in this file"); + // register function to cleanup if (!_atexit_registered) { _atexit_registered = true; @@ -445,14 +447,14 @@ AttachOperation* AttachListener::dequeue() { void AttachListener::vm_start() { char fn[UNIX_PATH_MAX]; - struct stat64 st; + struct stat st; int ret; int n = snprintf(fn, UNIX_PATH_MAX, "%s/.java_pid%d", os::get_temp_directory(), os::current_process_id()); assert(n < (int)UNIX_PATH_MAX, "java_pid file name buffer overflow"); - RESTARTABLE(::stat64(fn, &st), ret); + RESTARTABLE(::stat(fn, &st), ret); if (ret == 0) { ret = ::unlink(fn); if (ret == -1) { @@ -472,8 +474,8 @@ int AttachListener::pd_init() { bool AttachListener::check_socket_file() { int ret; - struct stat64 st; - ret = stat64(LinuxAttachListener::path(), &st); + struct stat st; + ret = stat(LinuxAttachListener::path(), &st); if (ret == -1) { // need to restart attach listener. log_debug(attach)("Socket file %s does not exist - Restart Attach Listener", LinuxAttachListener::path()); @@ -512,14 +514,14 @@ bool AttachListener::is_init_trigger() { } char fn[PATH_MAX + 1]; int ret; - struct stat64 st; + struct stat st; os::snprintf_checked(fn, sizeof(fn), ".attach_pid%d", os::current_process_id()); - RESTARTABLE(::stat64(fn, &st), ret); + RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_trace(attach)("Failed to find attach file: %s, trying alternate", fn); snprintf(fn, sizeof(fn), "%s/.attach_pid%d", os::get_temp_directory(), os::current_process_id()); - RESTARTABLE(::stat64(fn, &st), ret); + RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_debug(attach)("Failed to find attach file: %s", fn); } diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp index 9dc070233fee9..f0cbc9780b230 100644 --- a/src/hotspot/os/linux/globals_linux.hpp +++ b/src/hotspot/os/linux/globals_linux.hpp @@ -77,7 +77,28 @@ "Use CPU_ALLOC code path in os::active_processor_count ") \ \ product(bool, DumpPerfMapAtExit, false, DIAGNOSTIC, \ - "Write map file for Linux perf tool at exit") + "Write map file for Linux perf tool at exit") \ + \ + product(intx, TimerSlack, -1, EXPERIMENTAL, \ + "Overrides the timer slack value to the given number of " \ + "nanoseconds. Lower value provides more accurate " \ + "high-precision timers, at the expense of (possibly) worse " \ + "power efficiency. In current Linux, 0 means using the " \ + "system-wide default, which would disable the override, but " \ + "VM would still print the current timer slack values. Use -1 "\ + "to disable both the override and the printouts." \ + "See prctl(PR_SET_TIMERSLACK) for more info.") \ + \ + product(bool, THPStackMitigation, true, DIAGNOSTIC, \ + "If THPs are unconditionally enabled on the system (mode " \ + "\"always\"), the JVM will prevent THP from forming in " \ + "thread stacks. When disabled, the absence of this mitigation"\ + "allows THPs to form in thread stacks.") \ + \ + develop(bool, DelayThreadStartALot, false, \ + "Artificially delay thread starts randomly for testing.") \ + \ + // end of RUNTIME_OS_FLAGS diff --git a/src/hotspot/os/linux/hugepages.cpp b/src/hotspot/os/linux/hugepages.cpp new file mode 100644 index 0000000000000..f9f9dd497c7b6 --- /dev/null +++ b/src/hotspot/os/linux/hugepages.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, Red Hat Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "hugepages.hpp" + +#include "logging/log.hpp" +#include "logging/logStream.hpp" +#include "runtime/os.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" + +#include + +StaticHugePageSupport::StaticHugePageSupport() : + _initialized(false), _pagesizes(), _default_hugepage_size(SIZE_MAX), _inconsistent(false) {} + +os::PageSizes StaticHugePageSupport::pagesizes() const { + assert(_initialized, "Not initialized"); + return _pagesizes; +} + +size_t StaticHugePageSupport::default_hugepage_size() const { + assert(_initialized, "Not initialized"); + return _default_hugepage_size; +} + +// Scan /proc/meminfo and return value of Hugepagesize +static size_t scan_default_hugepagesize() { + size_t pagesize = 0; + + // large_page_size on Linux is used to round up heap size. x86 uses either + // 2M or 4M page, depending on whether PAE (Physical Address Extensions) + // mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use + // page as large as 1G. + // + // Here we try to figure out page size by parsing /proc/meminfo and looking + // for a line with the following format: + // Hugepagesize: 2048 kB + // + // If we can't determine the value (e.g. /proc is not mounted, or the text + // format has been changed), we'll set largest page size to 0 + + FILE *fp = os::fopen("/proc/meminfo", "r"); + if (fp) { + while (!feof(fp)) { + int x = 0; + char buf[16]; + if (fscanf(fp, "Hugepagesize: %d", &x) == 1) { + if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) { + pagesize = x * K; + break; + } + } else { + // skip to next line + for (;;) { + int ch = fgetc(fp); + if (ch == EOF || ch == (int)'\n') break; + } + } + } + fclose(fp); + } + + return pagesize; +} + +// Given a file that contains a single (integral) number, return that number in (*out) and true; +// in case of an error, return false. +static bool read_number_file(const char* file, size_t* out) { + FILE* f = ::fopen(file, "r"); + bool rc = false; + if (f != nullptr) { + uint64_t i = 0; + if (::fscanf(f, SIZE_FORMAT, out) == 1) { + rc = true; + } + ::fclose(f); + } + return rc; +} + +static const char* const sys_hugepages = "/sys/kernel/mm/hugepages"; + +// Scan all directories in /sys/kernel/mm/hugepages/hugepages-xxxx +// to discover the available page sizes +static os::PageSizes scan_hugepages() { + + os::PageSizes pagesizes; + + DIR* dir = opendir(sys_hugepages); + + if (dir != nullptr) { + struct dirent *entry; + size_t pagesize; + while ((entry = readdir(dir)) != nullptr) { + if (entry->d_type == DT_DIR && + sscanf(entry->d_name, "hugepages-%zukB", &pagesize) == 1) { + // The kernel is using kB, hotspot uses bytes + // Add each found Large Page Size to page_sizes + pagesize *= K; + pagesizes.add(pagesize); + } + } + closedir(dir); + } + + return pagesizes; +} + +void StaticHugePageSupport::print_on(outputStream* os) { + if (_initialized) { + os->print_cr("Static hugepage support:"); + for (size_t s = _pagesizes.smallest(); s != 0; s = _pagesizes.next_larger(s)) { + os->print_cr(" hugepage size: " EXACTFMT, EXACTFMTARGS(s)); + } + os->print_cr(" default hugepage size: " EXACTFMT, EXACTFMTARGS(_default_hugepage_size)); + } else { + os->print_cr(" unknown."); + } + if (_inconsistent) { + os->print_cr(" Support inconsistent. JVM will not use static hugepages."); + } +} + +void StaticHugePageSupport::scan_os() { + _default_hugepage_size = scan_default_hugepagesize(); + if (_default_hugepage_size > 0) { + _pagesizes = scan_hugepages(); + // See https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt: /proc/meminfo should match + // /sys/kernel/mm/hugepages/hugepages-xxxx. However, we may run on a broken kernel (e.g. on WSL) + // that only exposes /proc/meminfo but not /sys/kernel/mm/hugepages. In that case, we are not + // sure about the state of hugepage support by the kernel, so we won't use static hugepages. + if (!_pagesizes.contains(_default_hugepage_size)) { + log_info(pagesize)("Unexpected configuration: default pagesize (" SIZE_FORMAT ") " + "has no associated directory in /sys/kernel/mm/hugepages..", _default_hugepage_size); + _inconsistent = true; + } + } + _initialized = true; + LogTarget(Info, pagesize) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + print_on(&ls); + } +} + +THPSupport::THPSupport() : + _initialized(false), _mode(THPMode::never), _pagesize(SIZE_MAX) {} + + +THPMode THPSupport::mode() const { + assert(_initialized, "Not initialized"); + return _mode; +} + +size_t THPSupport::pagesize() const { + assert(_initialized, "Not initialized"); + return _pagesize; +} + +void THPSupport::scan_os() { + // Scan /sys/kernel/mm/transparent_hugepage/enabled + // see mm/huge_memory.c + _mode = THPMode::never; + const char* filename = "/sys/kernel/mm/transparent_hugepage/enabled"; + FILE* f = ::fopen(filename, "r"); + if (f != nullptr) { + char buf[64]; + char* s = fgets(buf, sizeof(buf), f); + assert(s == buf, "Should have worked"); + if (::strstr(buf, "[madvise]") != nullptr) { + _mode = THPMode::madvise; + } else if (::strstr(buf, "[always]") != nullptr) { + _mode = THPMode::always; + } else { + assert(::strstr(buf, "[never]") != nullptr, "Weird content of %s: %s", filename, buf); + } + fclose(f); + } + + // Scan large page size for THP from hpage_pmd_size + _pagesize = 0; + if (read_number_file("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", &_pagesize)) { + assert(_pagesize > 0, "Expected"); + } + _initialized = true; + + LogTarget(Info, pagesize) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + print_on(&ls); + } +} + +void THPSupport::print_on(outputStream* os) { + if (_initialized) { + os->print_cr("Transparent hugepage (THP) support:"); + os->print_cr(" THP mode: %s", + (_mode == THPMode::always ? "always" : (_mode == THPMode::never ? "never" : "madvise"))); + os->print_cr(" THP pagesize: " EXACTFMT, EXACTFMTARGS(_pagesize)); + } else { + os->print_cr(" unknown."); + } +} + +StaticHugePageSupport HugePages::_static_hugepage_support; +THPSupport HugePages::_thp_support; + +void HugePages::initialize() { + _static_hugepage_support.scan_os(); + _thp_support.scan_os(); +} + +void HugePages::print_on(outputStream* os) { + _static_hugepage_support.print_on(os); + _thp_support.print_on(os); +} diff --git a/src/hotspot/os/linux/hugepages.hpp b/src/hotspot/os/linux/hugepages.hpp new file mode 100644 index 0000000000000..cb7c992d78950 --- /dev/null +++ b/src/hotspot/os/linux/hugepages.hpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, Red Hat Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_LINUX_HUGEPAGES_HPP +#define OS_LINUX_HUGEPAGES_HPP + +#include "memory/allStatic.hpp" +#include "runtime/os.hpp" // for os::PageSizes +#include "utilities/globalDefinitions.hpp" + +class outputStream; + +// Header contains the interface that reads OS information about +// available hugepage support: +// - class StaticHugePageSupport - about static (non-THP) hugepages +// - class THPSupport - about transparent huge pages +// and: +// - class HugePages - a static umbrella wrapper + +// Information about static (non-thp) hugepages +class StaticHugePageSupport { + bool _initialized; + + // All supported hugepage sizes (sizes for which entries exist + // in /sys/kernel/mm/hugepages/hugepage-xxx) + os::PageSizes _pagesizes; + + // Contains the default hugepage. The "default hugepage size" is the one that + // - is marked in /proc/meminfo as "Hugepagesize" + // - is the size one gets when using mmap(MAP_HUGETLB) when omitting size specifiers like MAP_HUGE_SHIFT) + size_t _default_hugepage_size; + + // If true, the kernel support for hugepages is inconsistent + bool _inconsistent; + +public: + StaticHugePageSupport(); + + void scan_os(); + + os::PageSizes pagesizes() const; + size_t default_hugepage_size() const; + void print_on(outputStream* os); + + bool inconsistent() const { return _inconsistent; } +}; + +enum class THPMode { always, never, madvise }; + +// 2) for transparent hugepages +class THPSupport { + bool _initialized; + + // See /sys/kernel/mm/transparent_hugepages/enabled + THPMode _mode; + + // Contains the THP page size + size_t _pagesize; + +public: + + THPSupport(); + + // Queries the OS, fills in object + void scan_os(); + + THPMode mode() const; + size_t pagesize() const; + void print_on(outputStream* os); +}; + +// Umbrella static interface +class HugePages : public AllStatic { + + static StaticHugePageSupport _static_hugepage_support; + static THPSupport _thp_support; + +public: + + static const StaticHugePageSupport& static_info() { return _static_hugepage_support; } + static const THPSupport& thp_info() { return _thp_support; } + + static size_t default_static_hugepage_size() { return _static_hugepage_support.default_hugepage_size(); } + static bool supports_static_hugepages() { return default_static_hugepage_size() > 0 && !_static_hugepage_support.inconsistent(); } + static THPMode thp_mode() { return _thp_support.mode(); } + static bool supports_thp() { return thp_mode() == THPMode::madvise || thp_mode() == THPMode::always; } + static size_t thp_pagesize() { return _thp_support.pagesize(); } + + static void initialize(); + static void print_on(outputStream* os); +}; + +#endif // OS_LINUX_HUGEPAGES_HPP diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index a77476e218a5e..aa8be1d897d42 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2015, 2022 SAP SE. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "code/vtableStubs.hpp" #include "compiler/compileBroker.hpp" #include "compiler/disassembler.hpp" +#include "hugepages.hpp" #include "interpreter/interpreter.hpp" #include "jvm.h" #include "jvmtifiles/jvmti.h" @@ -113,6 +114,7 @@ # include # include # include +# include #ifdef __GLIBC__ # include #endif @@ -169,7 +171,6 @@ pthread_t os::Linux::_main_thread; bool os::Linux::_supports_fast_thread_cpu_time = false; const char * os::Linux::_libc_version = nullptr; const char * os::Linux::_libpthread_version = nullptr; -size_t os::Linux::_default_large_page_size = 0; #ifdef __GLIBC__ // We want to be buildable and runnable on older and newer glibcs, so resolve both @@ -410,7 +411,7 @@ pid_t os::Linux::gettid() { julong os::Linux::host_swap() { struct sysinfo si; sysinfo(&si); - return (julong)si.totalswap; + return (julong)(si.totalswap * si.mem_unit); } // Most versions of linux have a bug where the number of processors are @@ -774,6 +775,10 @@ static void *thread_native_entry(Thread *thread) { assert(osthread->pthread_id() != 0, "pthread_id was not set as expected"); + if (DelayThreadStartALot) { + os::naked_short_sleep(100); + } + // call one more level start routine thread->call_run(); @@ -910,6 +915,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, // Calculate stack size if it's not specified by caller. size_t stack_size = os::Posix::get_initial_stack_size(thr_type, req_stack_size); size_t guard_size = os::Linux::default_guard_size(thr_type); + // Configure glibc guard page. Must happen before calling // get_static_tls_area_size(), which uses the guard_size. pthread_attr_setguardsize(&attr, guard_size); @@ -930,13 +936,16 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, } assert(is_aligned(stack_size, os::vm_page_size()), "stack_size not aligned"); - // Add an additional page to the stack size to reduce its chances of getting large page aligned - // so that the stack does not get backed by a transparent huge page. - size_t default_large_page_size = os::Linux::default_large_page_size(); - if (default_large_page_size != 0 && - stack_size >= default_large_page_size && - is_aligned(stack_size, default_large_page_size)) { - stack_size += os::vm_page_size(); + if (THPStackMitigation) { + // In addition to the glibc guard page that prevents inter-thread-stack hugepage + // coalescing (see comment in os::Linux::default_guard_size()), we also make + // sure the stack size itself is not huge-page-size aligned; that makes it much + // more likely for thread stack boundaries to be unaligned as well and hence + // protects thread stacks from being targeted by khugepaged. + if (HugePages::thp_pagesize() > 0 && + is_aligned(stack_size, HugePages::thp_pagesize())) { + stack_size += os::vm_page_size(); + } } int status = pthread_attr_setstacksize(&attr, stack_size); @@ -967,6 +976,16 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, if (ret == 0) { log_info(os, thread)("Thread \"%s\" started (pthread id: " UINTX_FORMAT ", attributes: %s). ", thread->name(), (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + + // Print current timer slack if override is enabled and timer slack value is available. + // Avoid calling prctl otherwise for extra safety. + if (TimerSlack >= 0) { + int slack = prctl(PR_GET_TIMERSLACK); + if (slack >= 0) { + log_info(os, thread)("Thread \"%s\" (pthread id: " UINTX_FORMAT ") timer slack: %dns", + thread->name(), (uintx) tid, slack); + } + } } else { log_warning(os, thread)("Failed to start thread \"%s\" - pthread_create failed (%s) for attributes: %s.", thread->name(), os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); @@ -1441,6 +1460,9 @@ bool os::address_is_in_vm(address addr) { return false; } +void os::prepare_native_symbols() { +} + bool os::dll_address_to_function_name(address addr, char *buf, int buflen, int *offset, bool demangle) { @@ -1708,11 +1730,11 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { static Elf32_Half running_arch_code=EM_SH; #elif (defined RISCV) static Elf32_Half running_arch_code=EM_RISCV; -#elif (defined LOONGARCH) +#elif (defined LOONGARCH64) static Elf32_Half running_arch_code=EM_LOONGARCH; #else #error Method os::dll_load requires that one of following is defined:\ - AARCH64, ALPHA, ARM, AMD64, IA32, IA64, LOONGARCH, M68K, MIPS, MIPSEL, PARISC, __powerpc__, __powerpc64__, RISCV, S390, SH, __sparc + AARCH64, ALPHA, ARM, AMD64, IA32, IA64, LOONGARCH64, M68K, MIPS, MIPSEL, PARISC, __powerpc__, __powerpc64__, RISCV, S390, SH, __sparc #endif // Identify compatibility class for VM's architecture and library's architecture @@ -2016,7 +2038,6 @@ const char* distro_files[] = { "/etc/mandrake-release", "/etc/sun-release", "/etc/redhat-release", - "/etc/SuSE-release", "/etc/lsb-release", "/etc/turbolinux-release", "/etc/gentoo-release", @@ -2024,6 +2045,7 @@ const char* distro_files[] = { "/etc/angstrom-version", "/etc/system-release", "/etc/os-release", + "/etc/SuSE-release", // Deprecated in favor of os-release since SuSE 12 nullptr }; void os::Linux::print_distro_info(outputStream* st) { @@ -2135,6 +2157,8 @@ void os::Linux::print_system_memory_info(outputStream* st) { // https://www.kernel.org/doc/Documentation/vm/transhuge.txt _print_ascii_file_h("/sys/kernel/mm/transparent_hugepage/enabled", "/sys/kernel/mm/transparent_hugepage/enabled", st); + _print_ascii_file_h("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", + "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", st); _print_ascii_file_h("/sys/kernel/mm/transparent_hugepage/defrag (defrag/compaction efforts parameter)", "/sys/kernel/mm/transparent_hugepage/defrag", st); } @@ -2671,6 +2695,8 @@ void os::jvm_path(char *buf, jint buflen) { void linux_wrap_code(char* base, size_t size) { static volatile jint cnt = 0; + static_assert(sizeof(off_t) == 8, "Expected Large File Support in this file"); + if (!UseOprofile) { return; } @@ -3066,6 +3092,27 @@ bool os::Linux::libnuma_init() { } size_t os::Linux::default_guard_size(os::ThreadType thr_type) { + + if (THPStackMitigation) { + // If THPs are unconditionally enabled, the following scenario can lead to huge RSS + // - parent thread spawns, in quick succession, multiple child threads + // - child threads are slow to start + // - thread stacks of future child threads are adjacent and get merged into one large VMA + // by the kernel, and subsequently transformed into huge pages by khugepaged + // - child threads come up, place JVM guard pages, thus splinter the large VMA, splinter + // the huge pages into many (still paged-in) small pages. + // The result of that sequence are thread stacks that are fully paged-in even though the + // threads did not even start yet. + // We prevent that by letting the glibc allocate a guard page, which causes a VMA with different + // permission bits to separate two ajacent thread stacks and therefore prevent merging stacks + // into one VMA. + // + // Yes, this means we have two guard sections - the glibc and the JVM one - per thread. But the + // cost for that one extra protected page is dwarfed from a large win in performance and memory + // that avoiding interference by khugepaged buys us. + return os::vm_page_size(); + } + // Creating guard page is very expensive. Java thread has HotSpot // guard pages, only enable glibc guard page for non-Java threads. // (Remember: compiler thread is a Java thread, too!) @@ -3545,7 +3592,7 @@ bool os::Linux::transparent_huge_pages_sanity_check(bool warn, } int os::Linux::hugetlbfs_page_size_flag(size_t page_size) { - if (page_size != default_large_page_size()) { + if (page_size != HugePages::default_static_hugepage_size()) { return (exact_log2(page_size) << MAP_HUGE_SHIFT); } return 0; @@ -3653,79 +3700,6 @@ static void set_coredump_filter(CoredumpFilterBit bit) { static size_t _large_page_size = 0; -static size_t scan_default_large_page_size() { - size_t default_large_page_size = 0; - - // large_page_size on Linux is used to round up heap size. x86 uses either - // 2M or 4M page, depending on whether PAE (Physical Address Extensions) - // mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use - // page as large as 1G. - // - // Here we try to figure out page size by parsing /proc/meminfo and looking - // for a line with the following format: - // Hugepagesize: 2048 kB - // - // If we can't determine the value (e.g. /proc is not mounted, or the text - // format has been changed), we'll set largest page size to 0 - - FILE *fp = os::fopen("/proc/meminfo", "r"); - if (fp) { - while (!feof(fp)) { - int x = 0; - char buf[16]; - if (fscanf(fp, "Hugepagesize: %d", &x) == 1) { - if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) { - default_large_page_size = x * K; - break; - } - } else { - // skip to next line - for (;;) { - int ch = fgetc(fp); - if (ch == EOF || ch == (int)'\n') break; - } - } - } - fclose(fp); - } - - return default_large_page_size; -} - -static os::PageSizes scan_multiple_page_support() { - // Scan /sys/kernel/mm/hugepages - // to discover the available page sizes - const char* sys_hugepages = "/sys/kernel/mm/hugepages"; - os::PageSizes page_sizes; - - DIR *dir = opendir(sys_hugepages); - - struct dirent *entry; - size_t page_size; - while ((entry = readdir(dir)) != nullptr) { - if (entry->d_type == DT_DIR && - sscanf(entry->d_name, "hugepages-%zukB", &page_size) == 1) { - // The kernel is using kB, hotspot uses bytes - // Add each found Large Page Size to page_sizes - page_sizes.add(page_size * K); - } - } - closedir(dir); - - LogTarget(Debug, pagesize) lt; - if (lt.is_enabled()) { - LogStream ls(lt); - ls.print("Large Page sizes: "); - page_sizes.print_on(&ls); - } - - return page_sizes; -} - -size_t os::Linux::default_large_page_size() { - return _default_large_page_size; -} - void warn_no_large_pages_configured() { if (!FLAG_IS_DEFAULT(UseLargePages)) { log_warning(pagesize)("UseLargePages disabled, no large pages configured and available on the system."); @@ -3778,10 +3752,44 @@ bool os::Linux::setup_large_page_type(size_t page_size) { return false; } +struct LargePageInitializationLoggerMark { + ~LargePageInitializationLoggerMark() { + LogTarget(Info, pagesize) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + if (UseLargePages) { + ls.print_cr("UseLargePages=1, UseTransparentHugePages=%d, UseHugeTLBFS=%d, UseSHM=%d", + UseTransparentHugePages, UseHugeTLBFS, UseSHM); + ls.print("Large page support enabled. Usable page sizes: "); + os::page_sizes().print_on(&ls); + ls.print_cr(". Default large page size: " EXACTFMT ".", EXACTFMTARGS(os::large_page_size())); + } else { + ls.print("Large page support disabled."); + } + } + } +}; + void os::large_page_init() { - // Always initialize the default large page size even if large pages are not being used. - size_t default_large_page_size = scan_default_large_page_size(); - os::Linux::_default_large_page_size = default_large_page_size; + LargePageInitializationLoggerMark logger; + + // Query OS information first. + HugePages::initialize(); + + // If THPs are unconditionally enabled (THP mode "always"), khugepaged may attempt to + // coalesce small pages in thread stacks to huge pages. That costs a lot of memory and + // is usually unwanted for thread stacks. Therefore we attempt to prevent THP formation in + // thread stacks unless the user explicitly allowed THP formation by manually disabling + // -XX:-THPStackMitigation. + if (HugePages::thp_mode() == THPMode::always) { + if (THPStackMitigation) { + log_info(pagesize)("JVM will attempt to prevent THPs in thread stacks."); + } else { + log_info(pagesize)("JVM will *not* prevent THPs in thread stacks. This may cause high RSS."); + } + } else { + FLAG_SET_ERGO(THPStackMitigation, false); // Mitigation not needed + } // 1) Handle the case where we do not want to use huge pages if (!UseLargePages && @@ -3801,67 +3809,77 @@ void os::large_page_init() { return; } - // 2) check if large pages are configured - if (default_large_page_size == 0) { - // No large pages configured, return. + // 2) check if the OS supports THPs resp. static hugepages. + if (UseTransparentHugePages && !HugePages::supports_thp()) { + if (!FLAG_IS_DEFAULT(UseTransparentHugePages)) { + log_warning(pagesize)("UseTransparentHugePages disabled, transparent huge pages are not supported by the operating system."); + } + UseLargePages = UseTransparentHugePages = UseHugeTLBFS = UseSHM = false; + return; + } + if (!UseTransparentHugePages && !HugePages::supports_static_hugepages()) { warn_no_large_pages_configured(); - UseLargePages = false; - UseTransparentHugePages = false; - UseHugeTLBFS = false; - UseSHM = false; + UseLargePages = UseTransparentHugePages = UseHugeTLBFS = UseSHM = false; return; } - os::PageSizes all_large_pages = scan_multiple_page_support(); - - // 3) Consistency check and post-processing - - // It is unclear if /sys/kernel/mm/hugepages/ and /proc/meminfo could disagree. Manually - // re-add the default page size to the list of page sizes to be sure. - all_large_pages.add(default_large_page_size); - - // Check LargePageSizeInBytes matches an available page size and if so set _large_page_size - // using LargePageSizeInBytes as the maximum allowed large page size. If LargePageSizeInBytes - // doesn't match an available page size set _large_page_size to default_large_page_size - // and use it as the maximum. - if (FLAG_IS_DEFAULT(LargePageSizeInBytes) || - LargePageSizeInBytes == 0 || - LargePageSizeInBytes == default_large_page_size) { - _large_page_size = default_large_page_size; - log_info(pagesize)("Using the default large page size: " SIZE_FORMAT "%s", - byte_size_in_exact_unit(_large_page_size), - exact_unit_for_byte_size(_large_page_size)); + + if (UseTransparentHugePages) { + // In THP mode: + // - os::large_page_size() is the *THP page size* + // - os::pagesizes() has two members, the THP page size and the system page size + assert(HugePages::supports_thp() && HugePages::thp_pagesize() > 0, "Missing OS info"); + _large_page_size = HugePages::thp_pagesize(); + _page_sizes.add(_large_page_size); + _page_sizes.add(os::vm_page_size()); + } else { - if (all_large_pages.contains(LargePageSizeInBytes)) { - _large_page_size = LargePageSizeInBytes; - log_info(pagesize)("Overriding default large page size (" SIZE_FORMAT "%s) " - "using LargePageSizeInBytes: " SIZE_FORMAT "%s", - byte_size_in_exact_unit(default_large_page_size), - exact_unit_for_byte_size(default_large_page_size), - byte_size_in_exact_unit(_large_page_size), - exact_unit_for_byte_size(_large_page_size)); - } else { + + // In static hugepage mode: + // - os::large_page_size() is the default static hugepage size (/proc/meminfo "Hugepagesize") + // - os::pagesizes() contains all hugepage sizes the kernel supports, regardless whether there + // are pages configured in the pool or not (from /sys/kernel/hugepages/hugepage-xxxx ...) + os::PageSizes all_large_pages = HugePages::static_info().pagesizes(); + const size_t default_large_page_size = HugePages::default_static_hugepage_size(); + + // 3) Consistency check and post-processing + + // Check LargePageSizeInBytes matches an available page size and if so set _large_page_size + // using LargePageSizeInBytes as the maximum allowed large page size. If LargePageSizeInBytes + // doesn't match an available page size set _large_page_size to default_large_page_size + // and use it as the maximum. + if (FLAG_IS_DEFAULT(LargePageSizeInBytes) || + LargePageSizeInBytes == 0 || + LargePageSizeInBytes == default_large_page_size) { _large_page_size = default_large_page_size; - log_info(pagesize)("LargePageSizeInBytes is not a valid large page size (" SIZE_FORMAT "%s) " - "using the default large page size: " SIZE_FORMAT "%s", - byte_size_in_exact_unit(LargePageSizeInBytes), - exact_unit_for_byte_size(LargePageSizeInBytes), + log_info(pagesize)("Using the default large page size: " SIZE_FORMAT "%s", byte_size_in_exact_unit(_large_page_size), exact_unit_for_byte_size(_large_page_size)); + } else { + if (all_large_pages.contains(LargePageSizeInBytes)) { + _large_page_size = LargePageSizeInBytes; + log_info(pagesize)("Overriding default large page size (" SIZE_FORMAT "%s) " + "using LargePageSizeInBytes: " SIZE_FORMAT "%s", + byte_size_in_exact_unit(default_large_page_size), + exact_unit_for_byte_size(default_large_page_size), + byte_size_in_exact_unit(_large_page_size), + exact_unit_for_byte_size(_large_page_size)); + } else { + _large_page_size = default_large_page_size; + log_info(pagesize)("LargePageSizeInBytes is not a valid large page size (" SIZE_FORMAT "%s) " + "using the default large page size: " SIZE_FORMAT "%s", + byte_size_in_exact_unit(LargePageSizeInBytes), + exact_unit_for_byte_size(LargePageSizeInBytes), + byte_size_in_exact_unit(_large_page_size), + exact_unit_for_byte_size(_large_page_size)); + } } - } - // Populate _page_sizes with large page sizes less than or equal to - // _large_page_size. - for (size_t page_size = _large_page_size; page_size != 0; - page_size = all_large_pages.next_smaller(page_size)) { - _page_sizes.add(page_size); - } - - LogTarget(Info, pagesize) lt; - if (lt.is_enabled()) { - LogStream ls(lt); - ls.print("Usable page sizes: "); - _page_sizes.print_on(&ls); + // Populate _page_sizes with large page sizes less than or equal to + // _large_page_size. + for (size_t page_size = _large_page_size; page_size != 0; + page_size = all_large_pages.next_smaller(page_size)) { + _page_sizes.add(page_size); + } } // Now determine the type of large pages to use: @@ -4701,6 +4719,15 @@ jint os::init_2(void) { FLAG_SET_DEFAULT(UseCodeCacheFlushing, false); } + // Override the timer slack value if needed. The adjustment for the main + // thread will establish the setting for child threads, which would be + // most threads in JDK/JVM. + if (TimerSlack >= 0) { + if (prctl(PR_SET_TIMERSLACK, TimerSlack) < 0) { + vm_exit_during_initialization("Setting timer slack failed: %s", os::strerror(errno)); + } + } + return JNI_OK; } @@ -4988,14 +5015,14 @@ int os::open(const char *path, int oflag, int mode) { oflag |= O_CLOEXEC; #endif - int fd = ::open64(path, oflag, mode); + int fd = ::open(path, oflag, mode); if (fd == -1) return -1; //If the open succeeded, the file might still be a directory { - struct stat64 buf64; - int ret = ::fstat64(fd, &buf64); - int st_mode = buf64.st_mode; + struct stat buf; + int ret = ::fstat(fd, &buf); + int st_mode = buf.st_mode; if (ret != -1) { if ((st_mode & S_IFMT) == S_IFDIR) { @@ -5032,17 +5059,17 @@ int os::open(const char *path, int oflag, int mode) { int os::create_binary_file(const char* path, bool rewrite_existing) { int oflags = O_WRONLY | O_CREAT; oflags |= rewrite_existing ? O_TRUNC : O_EXCL; - return ::open64(path, oflags, S_IREAD | S_IWRITE); + return ::open(path, oflags, S_IREAD | S_IWRITE); } // return current position of file pointer jlong os::current_file_offset(int fd) { - return (jlong)::lseek64(fd, (off64_t)0, SEEK_CUR); + return (jlong)::lseek(fd, (off_t)0, SEEK_CUR); } // move file pointer to the specified offset jlong os::seek_to_file_offset(int fd, jlong offset) { - return (jlong)::lseek64(fd, (off64_t)offset, SEEK_SET); + return (jlong)::lseek(fd, (off_t)offset, SEEK_SET); } // Map a block of memory. @@ -5543,3 +5570,25 @@ bool os::trim_native_heap(os::size_change_t* rss_change) { return false; // musl #endif } + +bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { + + if (ebuf && ebuflen > 0) { + ebuf[0] = '\0'; + ebuf[ebuflen - 1] = '\0'; + } + + bool res = (0 == ::dlclose(libhandle)); + if (!res) { + // error analysis when dlopen fails + const char* error_report = ::dlerror(); + if (error_report == nullptr) { + error_report = "dlerror returned no error description"; + } + if (ebuf != nullptr && ebuflen > 0) { + snprintf(ebuf, ebuflen - 1, "%s", error_report); + } + } + + return res; +} // end: os::pd_dll_unload() diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index a7cf69f3164c8..ace7e4ab2ddef 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -49,8 +49,6 @@ class os::Linux { static GrowableArray* _cpu_to_node; static GrowableArray* _nindex_to_node; - static size_t _default_large_page_size; - static julong available_memory_in_container(); protected: @@ -77,10 +75,6 @@ class os::Linux { static GrowableArray* cpu_to_node() { return _cpu_to_node; } static GrowableArray* nindex_to_node() { return _nindex_to_node; } - static size_t default_large_page_size(); - static size_t scan_default_large_page_size(); - static os::PageSizes scan_multiple_page_support(); - static bool setup_large_page_type(size_t page_size); static bool transparent_huge_pages_sanity_check(bool warn, size_t pages_size); static bool hugetlbfs_sanity_check(bool warn, size_t page_size); diff --git a/src/hotspot/os/linux/trimCHeapDCmd.cpp b/src/hotspot/os/linux/trimCHeapDCmd.cpp index 33dd6f3a5bdc7..26c066ffe5b6e 100644 --- a/src/hotspot/os/linux/trimCHeapDCmd.cpp +++ b/src/hotspot/os/linux/trimCHeapDCmd.cpp @@ -24,6 +24,7 @@ */ #include "precompiled.hpp" +#include "logging/log.hpp" #include "runtime/os.inline.hpp" #include "trimCHeapDCmd.hpp" #include "utilities/debug.hpp" @@ -42,6 +43,9 @@ void TrimCLibcHeapDCmd::execute(DCmdSource source, TRAPS) { const char sign = sc.after < sc.before ? '-' : '+'; _output->print_cr("RSS+Swap: " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT ")", PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta)); + // Also log if native trim log is active + log_info(trimnative)("Manual Trim: " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT ")", + PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta)); } else { _output->print_cr("(no details available)."); } diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 893ca3a7b73f7..af7de184b1471 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,6 +50,7 @@ #include "utilities/vmError.hpp" #ifdef AIX #include "loadlib_aix.hpp" +#include "os_aix.hpp" #endif #ifdef LINUX #include "os_linux.hpp" @@ -293,6 +294,7 @@ static char* reserve_mmapped_memory(size_t bytes, char* requested_addr) { } static int util_posix_fallocate(int fd, off_t offset, off_t len) { + static_assert(sizeof(off_t) == 8, "Expected Large File Support in this file"); #ifdef __APPLE__ fstore_t store = { F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, len }; // First we try to get a continuous chunk of disk space @@ -733,34 +735,29 @@ void os::dll_unload(void *lib) { if (l_path == nullptr) { l_path = ""; } - int res = ::dlclose(lib); - if (res == 0) { + char ebuf[1024]; + bool res = os::pd_dll_unload(lib, ebuf, sizeof(ebuf)); + + if (res) { Events::log_dll_message(nullptr, "Unloaded shared library \"%s\" [" INTPTR_FORMAT "]", l_path, p2i(lib)); log_info(os)("Unloaded shared library \"%s\" [" INTPTR_FORMAT "]", l_path, p2i(lib)); } else { - const char* error_report = ::dlerror(); - if (error_report == nullptr) { - error_report = "dlerror returned no error description"; - } - Events::log_dll_message(nullptr, "Attempt to unload shared library \"%s\" [" INTPTR_FORMAT "] failed, %s", - l_path, p2i(lib), error_report); + l_path, p2i(lib), ebuf); log_info(os)("Attempt to unload shared library \"%s\" [" INTPTR_FORMAT "] failed, %s", - l_path, p2i(lib), error_report); + l_path, p2i(lib), ebuf); } - // Update the dll cache - AIX_ONLY(LoadedLibraries::reload()); LINUX_ONLY(os::free(l_pathdup)); } jlong os::lseek(int fd, jlong offset, int whence) { - return (jlong) BSD_ONLY(::lseek) NOT_BSD(::lseek64)(fd, offset, whence); + return (jlong) AIX_ONLY(::lseek64) NOT_AIX(::lseek)(fd, offset, whence); } int os::ftruncate(int fd, jlong length) { - return BSD_ONLY(::ftruncate) NOT_BSD(::ftruncate64)(fd, length); + return AIX_ONLY(::ftruncate64) NOT_AIX(::ftruncate)(fd, length); } const char* os::get_current_directory(char *buf, size_t buflen) { diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp index 051b23d51bdb7..9e98f4316c4a5 100644 --- a/src/hotspot/os/posix/os_posix.hpp +++ b/src/hotspot/os/posix/os_posix.hpp @@ -31,7 +31,7 @@ // Note: the Posix API aims to capture functionality available on all Posix // compliant platforms, but in practice the implementations may depend on -// non-Posix functionality. For example, the use of lseek64 and ftruncate64. +// non-Posix functionality. // This use of non-Posix API's is made possible by compiling/linking in a mode // that is not restricted to being fully Posix complaint, such as by declaring // -D_GNU_SOURCE. But be aware that in doing so we may enable non-Posix diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 69c957135c09a..a6aa82012e851 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1395,6 +1395,9 @@ const char* os::get_current_directory(char *buf, size_t buflen) { return _getcwd(buf, n); } +void os::prepare_native_symbols() { +} + //----------------------------------------------------------- // Helper functions for fatal error handler #ifdef _WIN64 diff --git a/src/hotspot/os/windows/os_windows.inline.hpp b/src/hotspot/os/windows/os_windows.inline.hpp index d765966b7c665..ce5647e275b25 100644 --- a/src/hotspot/os/windows/os_windows.inline.hpp +++ b/src/hotspot/os/windows/os_windows.inline.hpp @@ -97,7 +97,7 @@ inline void PlatformMonitor::notify_all() { WakeAllConditionVariable(&_cond); } -// stubbed-out trim-native support +// Trim-native support, stubbed out for now, may be enabled later inline bool os::can_trim_native_heap() { return false; } inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; } 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 3882ed6770389..2ade1c7153be9 100644 --- a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp +++ b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp @@ -463,7 +463,7 @@ void os::print_tos_pc(outputStream *st, const void *context) { // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::Posix::ucontext_get_pc(uc); - print_instructions(st, pc, /*instrsize=*/4); + print_instructions(st, pc); st->cr(); // Try to decode the instructions. 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 ae5d249a5db08..feda935c6c1e6 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp +++ b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp @@ -177,7 +177,7 @@ frame os::fetch_compiled_frame_from_context(const void* ucVoid) { // 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->link(), fr->link(), fr->sender_pc()); + return frame(fr->sender_sp(), fr->link(), fr->sender_pc()); } NOINLINE frame os::current_frame() { @@ -477,7 +477,7 @@ void os::print_tos_pc(outputStream *st, const void *context) { // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::Posix::ucontext_get_pc(uc); - print_instructions(st, pc, 4/*native instruction size*/); + print_instructions(st, pc); st->cr(); } diff --git a/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp index 77104194b0b78..9ba246f553d88 100644 --- a/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp +++ b/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp @@ -153,6 +153,14 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest, return cmpxchg_using_helper(_Atomic_cmpxchg_long, dest, compare_value, exchange_value); } +// No direct support for 8-byte xchg; emulate using cmpxchg. +template<> +struct Atomic::PlatformXchg<8> : Atomic::XchgUsingCmpxchg<8> {}; + +// No direct support for 8-byte add; emulate using cmpxchg. +template<> +struct Atomic::PlatformAdd<8> : Atomic::AddUsingCmpxchg<8> {}; + template<> template inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const { 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 961464fa38dea..0fb1b958339dd 100644 --- a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp +++ b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp @@ -854,7 +854,7 @@ void os::print_tos_pc(outputStream *st, const void *context) { // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::Posix::ucontext_get_pc(uc); - print_instructions(st, pc, sizeof(char)); + print_instructions(st, pc); st->cr(); } diff --git a/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp b/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp index b39f03fd0d2a7..37cd93e765d97 100644 --- a/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp +++ b/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp @@ -31,135 +31,6 @@ // Implementation of class atomic -#ifdef M68K - -/* - * __m68k_cmpxchg - * - * Atomically store newval in *ptr if *ptr is equal to oldval for user space. - * Returns newval on success and oldval if no exchange happened. - * This implementation is processor specific and works on - * 68020 68030 68040 and 68060. - * - * It will not work on ColdFire, 68000 and 68010 since they lack the CAS - * instruction. - * Using a kernelhelper would be better for arch complete implementation. - * - */ - -static inline int __m68k_cmpxchg(int oldval, int newval, volatile int *ptr) { - int ret; - __asm __volatile ("cas%.l %0,%2,%1" - : "=d" (ret), "+m" (*(ptr)) - : "d" (newval), "0" (oldval)); - return ret; -} - -/* Perform an atomic compare and swap: if the current value of `*PTR' - is OLDVAL, then write NEWVAL into `*PTR'. Return the contents of - `*PTR' before the operation.*/ -static inline int m68k_compare_and_swap(int newval, - volatile int *ptr, - int oldval) { - for (;;) { - int prev = *ptr; - if (prev != oldval) - return prev; - - if (__m68k_cmpxchg (prev, newval, ptr) == newval) - // Success. - return prev; - - // We failed even though prev == oldval. Try again. - } -} - -/* Atomically add an int to memory. */ -static inline int m68k_add_then_fetch(int add_value, volatile int *ptr) { - for (;;) { - // Loop until success. - - int prev = *ptr; - - if (__m68k_cmpxchg (prev, prev + add_value, ptr) == prev + add_value) - return prev + add_value; - } -} - -/* Atomically write VALUE into `*PTR' and returns the previous - contents of `*PTR'. */ -static inline int m68k_lock_test_and_set(int newval, volatile int *ptr) { - for (;;) { - // Loop until success. - int prev = *ptr; - - if (__m68k_cmpxchg (prev, newval, ptr) == prev) - return prev; - } -} -#endif // M68K - -#ifdef ARM - -/* - * __kernel_cmpxchg - * - * Atomically store newval in *ptr if *ptr is equal to oldval for user space. - * Return zero if *ptr was changed or non-zero if no exchange happened. - * The C flag is also set if *ptr was changed to allow for assembly - * optimization in the calling code. - * - */ - -typedef int (__kernel_cmpxchg_t)(int oldval, int newval, volatile int *ptr); -#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *) 0xffff0fc0) - - - -/* Perform an atomic compare and swap: if the current value of `*PTR' - is OLDVAL, then write NEWVAL into `*PTR'. Return the contents of - `*PTR' before the operation.*/ -static inline int arm_compare_and_swap(int newval, - volatile int *ptr, - int oldval) { - for (;;) { - int prev = *ptr; - if (prev != oldval) - return prev; - - if (__kernel_cmpxchg (prev, newval, ptr) == 0) - // Success. - return prev; - - // We failed even though prev == oldval. Try again. - } -} - -/* Atomically add an int to memory. */ -static inline int arm_add_then_fetch(int add_value, volatile int *ptr) { - for (;;) { - // Loop until a __kernel_cmpxchg succeeds. - - int prev = *ptr; - - if (__kernel_cmpxchg (prev, prev + add_value, ptr) == 0) - return prev + add_value; - } -} - -/* Atomically write VALUE into `*PTR' and returns the previous - contents of `*PTR'. */ -static inline int arm_lock_test_and_set(int newval, volatile int *ptr) { - for (;;) { - // Loop until a __kernel_cmpxchg succeeds. - int prev = *ptr; - - if (__kernel_cmpxchg (prev, newval, ptr) == 0) - return prev; - } -} -#endif // ARM - template struct Atomic::PlatformAdd { template @@ -178,17 +49,9 @@ inline D Atomic::PlatformAdd<4>::add_then_fetch(D volatile* dest, I add_value, STATIC_ASSERT(4 == sizeof(I)); STATIC_ASSERT(4 == sizeof(D)); -#ifdef ARM - return add_using_helper(arm_add_then_fetch, dest, add_value); -#else -#ifdef M68K - return add_using_helper(m68k_add_then_fetch, dest, add_value); -#else D res = __atomic_add_fetch(dest, add_value, __ATOMIC_RELEASE); FULL_MEM_BARRIER; return res; -#endif // M68K -#endif // ARM } template<> @@ -209,26 +72,10 @@ inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest, T exchange_value, atomic_memory_order order) const { STATIC_ASSERT(4 == sizeof(T)); -#ifdef ARM - return xchg_using_helper(arm_lock_test_and_set, dest, exchange_value); -#else -#ifdef M68K - return xchg_using_helper(m68k_lock_test_and_set, dest, exchange_value); -#else - // __sync_lock_test_and_set is a bizarrely named atomic exchange - // operation. Note that some platforms only support this with the - // limitation that the only valid value to store is the immediate - // constant 1. There is a test for this in JNI_CreateJavaVM(). - T result = __sync_lock_test_and_set (dest, exchange_value); - // All atomic operations are expected to be full memory barriers - // (see atomic.hpp). However, __sync_lock_test_and_set is not - // a full memory barrier, but an acquire barrier. Hence, this added - // barrier. Some platforms (notably ARM) have peculiarities with - // their barrier implementations, delegate it to OrderAccess. - OrderAccess::fence(); + FULL_MEM_BARRIER; + T result = __atomic_exchange_n(dest, exchange_value, __ATOMIC_RELAXED); + FULL_MEM_BARRIER; return result; -#endif // M68K -#endif // ARM } template<> @@ -237,8 +84,9 @@ inline T Atomic::PlatformXchg<8>::operator()(T volatile* dest, T exchange_value, atomic_memory_order order) const { STATIC_ASSERT(8 == sizeof(T)); - T result = __sync_lock_test_and_set (dest, exchange_value); - OrderAccess::fence(); + FULL_MEM_BARRIER; + T result = __atomic_exchange_n(dest, exchange_value, __ATOMIC_RELAXED); + FULL_MEM_BARRIER; return result; } @@ -253,20 +101,12 @@ inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest, T exchange_value, atomic_memory_order order) const { STATIC_ASSERT(4 == sizeof(T)); -#ifdef ARM - return cmpxchg_using_helper(arm_compare_and_swap, dest, compare_value, exchange_value); -#else -#ifdef M68K - return cmpxchg_using_helper(m68k_compare_and_swap, dest, compare_value, exchange_value); -#else T value = compare_value; FULL_MEM_BARRIER; __atomic_compare_exchange(dest, &value, &exchange_value, /*weak*/false, __ATOMIC_RELAXED, __ATOMIC_RELAXED); FULL_MEM_BARRIER; return value; -#endif // M68K -#endif // ARM } template<> @@ -286,31 +126,19 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest, } // Atomically copy 64 bits of data -static void atomic_copy64(const volatile void *src, volatile void *dst) { -#if defined(PPC32) - double tmp; - asm volatile ("lfd %0, 0(%1)\n" - "stfd %0, 0(%2)\n" - : "=f"(tmp) - : "b"(src), "b"(dst)); -#elif defined(S390) && !defined(_LP64) - double tmp; - asm volatile ("ld %0, 0(%1)\n" - "std %0, 0(%2)\n" - : "=r"(tmp) - : "a"(src), "a"(dst)); -#else - *(jlong *) dst = *(const jlong *) src; -#endif +inline void atomic_copy64(const volatile void *src, volatile void *dst) { + int64_t tmp; + __atomic_load(reinterpret_cast(src), &tmp, __ATOMIC_RELAXED); + __atomic_store(reinterpret_cast(dst), &tmp, __ATOMIC_RELAXED); } template<> template inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const { STATIC_ASSERT(8 == sizeof(T)); - volatile int64_t dest; - atomic_copy64(reinterpret_cast(src), reinterpret_cast(&dest)); - return PrimitiveConversions::cast(dest); + T dest; + __atomic_load(const_cast(src), &dest, __ATOMIC_RELAXED); + return dest; } template<> @@ -318,7 +146,7 @@ template inline void Atomic::PlatformStore<8>::operator()(T volatile* dest, T store_value) const { STATIC_ASSERT(8 == sizeof(T)); - atomic_copy64(reinterpret_cast(&store_value), reinterpret_cast(dest)); + __atomic_store(dest, &store_value, __ATOMIC_RELAXED); } #endif // OS_CPU_BSD_ZERO_ATOMIC_BSD_ZERO_HPP 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 55b5efd5f6efc..c1bcf841b0848 100644 --- a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp +++ b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp @@ -331,22 +331,6 @@ extern "C" { } }; -///////////////////////////////////////////////////////////////////////////// -// Implementations of atomic operations not supported by processors. -// -- http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Atomic-Builtins.html - -#ifndef _LP64 -extern "C" { - long long unsigned int __sync_val_compare_and_swap_8( - volatile void *ptr, - long long unsigned int oldval, - long long unsigned int newval) { - ShouldNotCallThis(); - return 0; // silence compiler warnings - } -}; -#endif // !_LP64 - #ifndef PRODUCT void os::verify_stack_alignment() { } 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 28e17385d4339..86721c94797df 100644 --- a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp @@ -152,8 +152,23 @@ frame os::fetch_compiled_frame_from_context(const void* ucVoid) { // 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 +// specify a location for the frame record within a stack frame (6.4.6). +// GCC currently chooses to save it at the top of the frame (lowest address). +// This means that using fr->sender_sp() to set the caller's frame _unextended_sp, +// as we do in x86, is wrong. Using fr->link() instead only makes sense for +// native frames. Setting a correct value for _unextended_sp is important +// if this value is later used to get that frame's caller. This will happen +// if we end up calling frame::sender_for_compiled_frame(), which will be the +// case if the _pc is associated with a CodeBlob that has a _frame_size > 0 +// (nmethod, runtime stub, safepoint stub, etc). frame os::get_sender_for_C_frame(frame* fr) { - return frame(fr->link(), fr->link(), fr->sender_pc()); + address pc = fr->sender_pc(); + CodeBlob* cb = CodeCache::find_blob(pc); + bool use_codeblob = cb != nullptr && cb->frame_size() > 0; + assert(!use_codeblob || !Interpreter::contains(pc), "should not be an interpreter frame"); + intptr_t* sender_sp = use_codeblob ? (fr->link() + frame::metadata_words - cb->frame_size()) : fr->link(); + return frame(sender_sp, sender_sp, fr->link(), pc, cb, true /* allow_cb_null */); } NOINLINE frame os::current_frame() { @@ -355,7 +370,7 @@ void os::print_tos_pc(outputStream *st, const void *context) { // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::fetch_frame_from_context(uc).pc(); - print_instructions(st, pc, 4/*native instruction size*/); + print_instructions(st, pc); st->cr(); } diff --git a/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp b/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp index 814dbd9aab501..513217649e633 100644 --- a/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp +++ b/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp @@ -128,6 +128,13 @@ inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest, return xchg_using_helper(ARMAtomicFuncs::_xchg_func, dest, exchange_value); } +// No direct support for 8-byte xchg; emulate using cmpxchg. +template<> +struct Atomic::PlatformXchg<8> : Atomic::XchgUsingCmpxchg<8> {}; + +// No direct support for 8-byte add; emulate using cmpxchg. +template<> +struct Atomic::PlatformAdd<8> : Atomic::AddUsingCmpxchg<8> {}; // The memory_order parameter is ignored - we always provide the strongest/most-conservative ordering 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 3bbe93fe798e4..86e8ed25618c1 100644 --- a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp +++ b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp @@ -483,7 +483,7 @@ void os::print_tos_pc(outputStream *st, const void *context) { // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::Posix::ucontext_get_pc(uc); - print_instructions(st, pc, Assembler::InstructionSize); + print_instructions(st, pc); st->cr(); } 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 e5837af0a73f5..2e603ac06909b 100644 --- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp +++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp @@ -477,7 +477,7 @@ void os::print_tos_pc(outputStream *st, const void *context) { // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::Posix::ucontext_get_pc(uc); - print_instructions(st, pc, /*instrsize=*/4); + print_instructions(st, pc); st->cr(); } diff --git a/src/hotspot/os_cpu/linux_riscv/atomic_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/atomic_linux_riscv.hpp index 393c245ec0278..fdb8b340ab9ed 100644 --- a/src/hotspot/os_cpu/linux_riscv/atomic_linux_riscv.hpp +++ b/src/hotspot/os_cpu/linux_riscv/atomic_linux_riscv.hpp @@ -33,10 +33,23 @@ // Note that memory_order_conservative requires a full barrier after atomic stores. // See https://patchwork.kernel.org/patch/3575821/ +#if defined(__clang_major__) +#define FULL_COMPILER_ATOMIC_SUPPORT +#elif (__GNUC__ > 13) || ((__GNUC__ == 13) && (__GNUC_MINOR__ >= 2)) +#define FULL_COMPILER_ATOMIC_SUPPORT +#endif + template struct Atomic::PlatformAdd { template D add_then_fetch(D volatile* dest, I add_value, atomic_memory_order order) const { + +#ifndef FULL_COMPILER_ATOMIC_SUPPORT + // If we add add and fetch for sub word and are using older compiler + // it must be added here due to not using lib atomic. + STATIC_ASSERT(byte_size >= 4); +#endif + if (order != memory_order_relaxed) { FULL_MEM_BARRIER; } @@ -55,12 +68,65 @@ struct Atomic::PlatformAdd { } }; +#ifndef FULL_COMPILER_ATOMIC_SUPPORT +template<> +template +inline T Atomic::PlatformCmpxchg<1>::operator()(T volatile* dest __attribute__((unused)), + T compare_value, + T exchange_value, + atomic_memory_order order) const { + STATIC_ASSERT(1 == sizeof(T)); + + if (order != memory_order_relaxed) { + FULL_MEM_BARRIER; + } + + uint32_t volatile* aligned_dst = (uint32_t volatile*)(((uintptr_t)dest) & (~((uintptr_t)0x3))); + int shift = 8 * (((uintptr_t)dest) - ((uintptr_t)aligned_dst)); // 0, 8, 16, 24 + + uint64_t mask = 0xfful << shift; // 0x00000000..FF.. + uint64_t remask = ~mask; // 0xFFFFFFFF..00.. + + uint64_t w_cv = ((uint64_t)(unsigned char)compare_value) << shift; // widen to 64-bit 0x00000000..CC.. + uint64_t w_ev = ((uint64_t)(unsigned char)exchange_value) << shift; // widen to 64-bit 0x00000000..EE.. + + uint64_t old_value; + uint64_t rc_temp; + + __asm__ __volatile__ ( + "1: lr.w %0, %2 \n\t" + " and %1, %0, %5 \n\t" // ignore unrelated bytes and widen to 64-bit 0x00000000..XX.. + " bne %1, %3, 2f \n\t" // compare 64-bit w_cv + " and %1, %0, %6 \n\t" // remove old byte + " or %1, %1, %4 \n\t" // add new byte + " sc.w %1, %1, %2 \n\t" // store new word + " bnez %1, 1b \n\t" + "2: \n\t" + : /*%0*/"=&r" (old_value), /*%1*/"=&r" (rc_temp), /*%2*/"+A" (*aligned_dst) + : /*%3*/"r" (w_cv), /*%4*/"r" (w_ev), /*%5*/"r" (mask), /*%6*/"r" (remask) + : "memory" ); + + if (order != memory_order_relaxed) { + FULL_MEM_BARRIER; + } + + return (T)((old_value & mask) >> shift); +} +#endif + template template inline T Atomic::PlatformXchg::operator()(T volatile* dest, T exchange_value, atomic_memory_order order) const { +#ifndef FULL_COMPILER_ATOMIC_SUPPORT + // If we add xchg for sub word and are using older compiler + // it must be added here due to not using lib atomic. + STATIC_ASSERT(byte_size >= 4); +#endif + STATIC_ASSERT(byte_size == sizeof(T)); + if (order != memory_order_relaxed) { FULL_MEM_BARRIER; } @@ -80,6 +146,11 @@ inline T Atomic::PlatformCmpxchg::operator()(T volatile* dest __attri T compare_value, T exchange_value, atomic_memory_order order) const { + +#ifndef FULL_COMPILER_ATOMIC_SUPPORT + STATIC_ASSERT(byte_size >= 4); +#endif + STATIC_ASSERT(byte_size == sizeof(T)); T value = compare_value; if (order != memory_order_relaxed) { @@ -148,4 +219,6 @@ struct Atomic::PlatformOrderedStore void operator()(volatile T* p, T v) const { release_store(p, v); OrderAccess::fence(); } }; +#undef FULL_COMPILER_ATOMIC_SUPPORT + #endif // OS_CPU_LINUX_RISCV_ATOMIC_LINUX_RISCV_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp index 2b500376f9b48..a7dc84770f84c 100644 --- a/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp +++ b/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp @@ -37,7 +37,7 @@ inline void OrderAccess::storestore() { release(); } inline void OrderAccess::loadstore() { acquire(); } inline void OrderAccess::storeload() { fence(); } -#define FULL_MEM_BARRIER __sync_synchronize() +#define FULL_MEM_BARRIER __atomic_thread_fence(__ATOMIC_SEQ_CST); #define READ_MEM_BARRIER __atomic_thread_fence(__ATOMIC_ACQUIRE); #define WRITE_MEM_BARRIER __atomic_thread_fence(__ATOMIC_RELEASE); 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 814ae19d639fe..eb3bf02d66cb5 100644 --- a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp @@ -232,7 +232,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, CompiledMethod* nm = (cb != nullptr) ? cb->as_compiled_method_or_null() : nullptr; bool is_unsafe_arraycopy = (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc)); if ((nm != nullptr && nm->has_unsafe_access()) || is_unsafe_arraycopy) { - address next_pc = pc + NativeCall::instruction_size; + address next_pc = Assembler::locate_next_instruction(pc); if (is_unsafe_arraycopy) { next_pc = UnsafeCopyMemory::page_error_continue_pc(pc); } @@ -273,7 +273,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, thread->thread_state() == _thread_in_native) && sig == SIGBUS && /* info->si_code == BUS_OBJERR && */ thread->doing_unsafe_access()) { - address next_pc = pc + NativeCall::instruction_size; + address next_pc = Assembler::locate_next_instruction(pc); if (UnsafeCopyMemory::contains_pc(pc)) { next_pc = UnsafeCopyMemory::page_error_continue_pc(pc); } @@ -367,7 +367,7 @@ void os::print_tos_pc(outputStream *st, const void *context) { // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::fetch_frame_from_context(uc).pc(); - print_instructions(st, pc, UseRVC ? sizeof(char) : (int)NativeInstruction::instruction_size); + print_instructions(st, pc); st->cr(); } diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp index f5b2f03ff1f89..243c4b850ee43 100644 --- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp @@ -45,6 +45,10 @@ #define RISCV_HWPROBE_KEY_IMA_EXT_0 4 #define RISCV_HWPROBE_IMA_FD (1 << 0) #define RISCV_HWPROBE_IMA_C (1 << 1) +#define RISCV_HWPROBE_IMA_V (1 << 2) +#define RISCV_HWPROBE_EXT_ZBA (1 << 3) +#define RISCV_HWPROBE_EXT_ZBB (1 << 4) +#define RISCV_HWPROBE_EXT_ZBS (1 << 5) #define RISCV_HWPROBE_KEY_CPUPERF_0 5 #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) @@ -100,7 +104,7 @@ static bool is_valid(int64_t key) { static bool is_set(int64_t key, uint64_t value_mask) { if (is_valid(key)) { - return query[key].value & value_mask != 0; + return (query[key].value & value_mask) != 0; } return false; } @@ -129,6 +133,18 @@ void RiscvHwprobe::add_features_from_query_result() { if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_IMA_C)) { VM_Version::ext_C.enable_feature(); } + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_IMA_V)) { + VM_Version::ext_V.enable_feature(); + } + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBA)) { + VM_Version::ext_Zba.enable_feature(); + } + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBB)) { + VM_Version::ext_Zbb.enable_feature(); + } + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBS)) { + VM_Version::ext_Zbs.enable_feature(); + } if (is_valid(RISCV_HWPROBE_KEY_CPUPERF_0)) { VM_Version::unaligned_access.enable_feature( query[RISCV_HWPROBE_KEY_CPUPERF_0].value & RISCV_HWPROBE_MISALIGNED_MASK); diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp index 54c8ae13bfa71..f890bfbdc028c 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 @@ -149,23 +149,32 @@ void VM_Version::setup_cpu_available_features() { void VM_Version::os_aux_features() { uint64_t auxv = getauxval(AT_HWCAP); - int i = 0; - while (_feature_list[i] != nullptr) { + for (int i = 0; _feature_list[i] != nullptr; i++) { + if (_feature_list[i]->feature_bit() == HWCAP_ISA_V) { + // Special case for V: some dev boards only support RVV version 0.7, while + // the OpenJDK only supports RVV version 1.0. These two versions are not + // compatible with each other. Given the V bit is set through HWCAP on + // some custom kernels, regardless of the version, it can lead to + // generating V instructions on boards that don't support RVV version 1.0 + // (ex: Sipeed LicheePi), leading to a SIGILL. + // That is an acceptable workaround as only Linux Kernel v6.5+ supports V, + // and that version already support hwprobe anyway + continue; + } if ((_feature_list[i]->feature_bit() & auxv) != 0) { _feature_list[i]->enable_feature(); } - i++; } } VM_Version::VM_MODE VM_Version::parse_satp_mode(const char* vm_mode) { - if (!strcmp(vm_mode, "sv39")) { + if (!strncmp(vm_mode, "sv39", sizeof "sv39" - 1)) { return VM_SV39; - } else if (!strcmp(vm_mode, "sv48")) { + } else if (!strncmp(vm_mode, "sv48", sizeof "sv48" - 1)) { return VM_SV48; - } else if (!strcmp(vm_mode, "sv57")) { + } else if (!strncmp(vm_mode, "sv57", sizeof "sv57" - 1)) { return VM_SV57; - } else if (!strcmp(vm_mode, "sv64")) { + } else if (!strncmp(vm_mode, "sv64", sizeof "sv64" - 1)) { return VM_SV64; } else { return VM_MBARE; @@ -187,7 +196,7 @@ char* VM_Version::os_uarch_additional_features() { if ((p = strchr(buf, ':')) != nullptr) { if (mode == VM_NOTSET) { if (strncmp(buf, "mmu", sizeof "mmu" - 1) == 0) { - mode = VM_Version::parse_satp_mode(p); + mode = VM_Version::parse_satp_mode(p + 2); } } if (ret == nullptr) { @@ -224,19 +233,11 @@ void VM_Version::vendor_features() { void VM_Version::rivos_features() { // Enable common features not dependent on marchid/mimpid. - ext_I.enable_feature(); - ext_M.enable_feature(); - ext_A.enable_feature(); - ext_F.enable_feature(); - ext_D.enable_feature(); - ext_C.enable_feature(); - ext_H.enable_feature(); - ext_V.enable_feature(); - ext_Zicbom.enable_feature(); ext_Zicboz.enable_feature(); ext_Zicbop.enable_feature(); + // If we running on a pre-6.5 kernel ext_Zba.enable_feature(); ext_Zbb.enable_feature(); ext_Zbs.enable_feature(); 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 206573b078ae5..033ea14ead6a4 100644 --- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp @@ -456,7 +456,7 @@ void os::print_tos_pc(outputStream *st, const void *context) { // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::Posix::ucontext_get_pc(uc); - print_instructions(st, pc, /*intrsize=*/4); + print_instructions(st, pc); st->cr(); } diff --git a/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp index 2e472a020683a..0156546ba9b77 100644 --- a/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp +++ b/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp @@ -153,6 +153,14 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest, return cmpxchg_using_helper(_Atomic_cmpxchg_long, dest, compare_value, exchange_value); } +// No direct support for 8-byte xchg; emulate using cmpxchg. +template<> +struct Atomic::PlatformXchg<8> : Atomic::XchgUsingCmpxchg<8> {}; + +// No direct support for 8-byte add; emulate using cmpxchg. +template<> +struct Atomic::PlatformAdd<8> : Atomic::AddUsingCmpxchg<8> {}; + template<> template inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const { 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 930cf3f2657d5..6cee67a867eee 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -571,7 +571,7 @@ void os::print_tos_pc(outputStream *st, const void *context) { // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::fetch_frame_from_context(uc).pc(); - print_instructions(st, pc, sizeof(char)); + print_instructions(st, pc); st->cr(); } diff --git a/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp b/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp index eefa8d5d06201..6409942c07de9 100644 --- a/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp +++ b/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp @@ -71,17 +71,9 @@ inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest, T exchange_value, atomic_memory_order order) const { STATIC_ASSERT(4 == sizeof(T)); - // __sync_lock_test_and_set is a bizarrely named atomic exchange - // operation. Note that some platforms only support this with the - // limitation that the only valid value to store is the immediate - // constant 1. There is a test for this in JNI_CreateJavaVM(). - T result = __sync_lock_test_and_set (dest, exchange_value); - // All atomic operations are expected to be full memory barriers - // (see atomic.hpp). However, __sync_lock_test_and_set is not - // a full memory barrier, but an acquire barrier. Hence, this added - // barrier. Some platforms (notably ARM) have peculiarities with - // their barrier implementations, delegate it to OrderAccess. - OrderAccess::fence(); + FULL_MEM_BARRIER; + T result = __atomic_exchange_n(dest, exchange_value, __ATOMIC_RELAXED); + FULL_MEM_BARRIER; return result; } @@ -91,8 +83,9 @@ inline T Atomic::PlatformXchg<8>::operator()(T volatile* dest, T exchange_value, atomic_memory_order order) const { STATIC_ASSERT(8 == sizeof(T)); - T result = __sync_lock_test_and_set (dest, exchange_value); - OrderAccess::fence(); + FULL_MEM_BARRIER; + T result = __atomic_exchange_n(dest, exchange_value, __ATOMIC_RELAXED); + FULL_MEM_BARRIER; return result; } @@ -134,54 +127,18 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest, // Atomically copy 64 bits of data inline void atomic_copy64(const volatile void *src, volatile void *dst) { -#if defined(PPC32) && !defined(__SPE__) - double tmp; - asm volatile ("lfd %0, %2\n" - "stfd %0, %1\n" - : "=&f"(tmp), "=Q"(*(volatile double*)dst) - : "Q"(*(volatile double*)src)); -#elif defined(PPC32) && defined(__SPE__) - long tmp; - asm volatile ("evldd %0, %2\n" - "evstdd %0, %1\n" - : "=&r"(tmp), "=Q"(*(volatile long*)dst) - : "Q"(*(volatile long*)src)); -#elif defined(S390) && !defined(_LP64) - double tmp; - asm volatile ("ld %0, %2\n" - "std %0, %1\n" - : "=&f"(tmp), "=Q"(*(volatile double*)dst) - : "Q"(*(volatile double*)src)); -#elif defined(__ARM_ARCH_7A__) - // The only way to perform the atomic 64-bit load/store - // is to use ldrexd/strexd for both reads and writes. - // For store, we need to have the matching (fake) load first. - // Put clrex between exclusive ops on src and dst for clarity. - uint64_t tmp_r, tmp_w; - uint32_t flag_w; - asm volatile ("ldrexd %[tmp_r], [%[src]]\n" - "clrex\n" - "1:\n" - "ldrexd %[tmp_w], [%[dst]]\n" - "strexd %[flag_w], %[tmp_r], [%[dst]]\n" - "cmp %[flag_w], 0\n" - "bne 1b\n" - : [tmp_r] "=&r" (tmp_r), [tmp_w] "=&r" (tmp_w), - [flag_w] "=&r" (flag_w) - : [src] "r" (src), [dst] "r" (dst) - : "cc", "memory"); -#else - *(jlong *) dst = *(const jlong *) src; -#endif + int64_t tmp; + __atomic_load(reinterpret_cast(src), &tmp, __ATOMIC_RELAXED); + __atomic_store(reinterpret_cast(dst), &tmp, __ATOMIC_RELAXED); } template<> template inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const { STATIC_ASSERT(8 == sizeof(T)); - volatile int64_t dest; - atomic_copy64(reinterpret_cast(src), reinterpret_cast(&dest)); - return PrimitiveConversions::cast(dest); + T dest; + __atomic_load(const_cast(src), &dest, __ATOMIC_RELAXED); + return dest; } template<> @@ -189,7 +146,7 @@ template inline void Atomic::PlatformStore<8>::operator()(T volatile* dest, T store_value) const { STATIC_ASSERT(8 == sizeof(T)); - atomic_copy64(reinterpret_cast(&store_value), reinterpret_cast(dest)); + __atomic_store(dest, &store_value, __ATOMIC_RELAXED); } #endif // OS_CPU_LINUX_ZERO_ATOMIC_LINUX_ZERO_HPP 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 101dbdcb4d10b..73adff11eddff 100644 --- a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp +++ b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp @@ -409,7 +409,7 @@ void os::print_tos_pc(outputStream *st, const void* ucVoid) { // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::Posix::ucontext_get_pc(uc); - print_instructions(st, pc, sizeof(char)); + print_instructions(st, pc); st->cr(); } @@ -492,22 +492,6 @@ extern "C" { } }; -///////////////////////////////////////////////////////////////////////////// -// Implementations of atomic operations not supported by processors. -// -- http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Atomic-Builtins.html - -#ifndef _LP64 -extern "C" { - long long unsigned int __sync_val_compare_and_swap_8( - volatile void *ptr, - long long unsigned int oldval, - long long unsigned int newval) { - ShouldNotCallThis(); - return 0; // silence compiler warnings - } -}; -#endif // !_LP64 - #ifndef PRODUCT void os::verify_stack_alignment() { } 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 73b8a46126d29..abd1a22ea2d60 100644 --- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp +++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp @@ -464,7 +464,7 @@ void os::print_tos_pc(outputStream *st, const void *context) { // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::fetch_frame_from_context(uc).pc(); - print_instructions(st, pc, sizeof(char)); + print_instructions(st, pc); st->cr(); } diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp index b0c4e7eff6b81..7c6ca6a38d428 100644 --- a/src/hotspot/share/adlc/output_c.cpp +++ b/src/hotspot/share/adlc/output_c.cpp @@ -3124,6 +3124,9 @@ static void define_fill_new_machnode(bool used, FILE *fp_cpp) { fprintf(fp_cpp, " if( i != cisc_operand() ) \n"); fprintf(fp_cpp, " to[i] = _opnds[i]->clone();\n"); fprintf(fp_cpp, " }\n"); + fprintf(fp_cpp, " // Do not increment node index counter, since node reuses my index\n"); + fprintf(fp_cpp, " Compile* C = Compile::current();\n"); + fprintf(fp_cpp, " C->set_unique(C->unique() - 1);\n"); fprintf(fp_cpp, "}\n"); } fprintf(fp_cpp, "\n"); diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index 37f1fcbe831b2..d40d7cfb119ba 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -2087,9 +2087,10 @@ void GraphBuilder::invoke(Bytecodes::Code code) { assert(singleton != declared_interface, "not a unique implementor"); cha_monomorphic_target = target->find_monomorphic_target(calling_klass, declared_interface, singleton); if (cha_monomorphic_target != nullptr) { - if (cha_monomorphic_target->holder() != compilation()->env()->Object_klass()) { - ciInstanceKlass* holder = cha_monomorphic_target->holder(); - ciInstanceKlass* constraint = (holder->is_subtype_of(singleton) ? holder : singleton); // avoid upcasts + ciInstanceKlass* holder = cha_monomorphic_target->holder(); + ciInstanceKlass* constraint = (holder->is_subtype_of(singleton) ? holder : singleton); // avoid upcasts + if (holder != compilation()->env()->Object_klass() && + (!type_is_exact || receiver_klass->is_subtype_of(constraint))) { actual_recv = declared_interface; // insert a check it's really the expected class. @@ -2102,7 +2103,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) { dependency_recorder()->assert_unique_implementor(declared_interface, singleton); } else { - cha_monomorphic_target = nullptr; // subtype check against Object is useless + cha_monomorphic_target = nullptr; } } } diff --git a/src/hotspot/share/c1/c1_Instruction.hpp b/src/hotspot/share/c1/c1_Instruction.hpp index 7308facda6f19..f4794297da8aa 100644 --- a/src/hotspot/share/c1/c1_Instruction.hpp +++ b/src/hotspot/share/c1/c1_Instruction.hpp @@ -954,7 +954,7 @@ LEAF(LoadIndexed, AccessIndexed) ciType* declared_type() const; // generic; - HASHING3(LoadIndexed, true, type()->tag(), array()->subst(), index()->subst()) + HASHING3(LoadIndexed, true, elt_type(), array()->subst(), index()->subst()) }; diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index 5013ad9c1b6ae..5dbb6d6574e2e 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -78,6 +78,7 @@ void PhiResolverState::reset() { PhiResolver::PhiResolver(LIRGenerator* gen) : _gen(gen) , _state(gen->resolver_state()) + , _loop(nullptr) , _temp(LIR_OprFact::illegalOpr) { // reinitialize the shared state arrays diff --git a/src/hotspot/share/c1/c1_LinearScan.cpp b/src/hotspot/share/c1/c1_LinearScan.cpp index a2663adacf079..0634d970c26f7 100644 --- a/src/hotspot/share/c1/c1_LinearScan.cpp +++ b/src/hotspot/share/c1/c1_LinearScan.cpp @@ -1949,6 +1949,14 @@ void LinearScan::resolve_exception_edge(XHandler* handler, int throwing_op_id, i // interval at the throwing instruction must be searched using the operands // of the phi function Value from_value = phi->operand_at(handler->phi_operand()); + if (from_value == nullptr) { + // We have reached here in a kotlin application running with JVMTI + // capability "can_access_local_variables". + // The illegal state is not yet propagated to this phi. Do it here. + phi->make_illegal(); + // We can skip the illegal phi edge. + return; + } // with phi functions it can happen that the same from_value is used in // multiple mappings, so notify move-resolver that this is allowed diff --git a/src/hotspot/share/c1/c1_RangeCheckElimination.cpp b/src/hotspot/share/c1/c1_RangeCheckElimination.cpp index 22bf4bc2cffb9..b03e277cfa996 100644 --- a/src/hotspot/share/c1/c1_RangeCheckElimination.cpp +++ b/src/hotspot/share/c1/c1_RangeCheckElimination.cpp @@ -404,8 +404,11 @@ void RangeCheckEliminator::add_access_indexed_info(InstructionList &indices, int aii->_max = idx; aii->_list = new AccessIndexedList(); } else if (idx >= aii->_min && idx <= aii->_max) { - remove_range_check(ai); - return; + // Guard against underflow/overflow (see 'range_cond' check in RangeCheckEliminator::in_block_motion) + if (aii->_max < 0 || (aii->_max + min_jint) <= aii->_min) { + remove_range_check(ai); + return; + } } aii->_min = MIN2(aii->_min, idx); aii->_max = MAX2(aii->_max, idx); @@ -448,9 +451,9 @@ void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList } } } else { - int last_integer = 0; + jint last_integer = 0; Instruction *last_instruction = index; - int base = 0; + jint base = 0; ArithmeticOp *ao = index->as_ArithmeticOp(); while (ao != nullptr && (ao->x()->as_Constant() || ao->y()->as_Constant()) && (ao->op() == Bytecodes::_iadd || ao->op() == Bytecodes::_isub)) { @@ -462,12 +465,12 @@ void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList } if (c) { - int value = c->type()->as_IntConstant()->value(); + jint value = c->type()->as_IntConstant()->value(); if (value != min_jint) { if (ao->op() == Bytecodes::_isub) { value = -value; } - base += value; + base = java_add(base, value); last_integer = base; last_instruction = other; } @@ -489,12 +492,12 @@ void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList assert(info != nullptr, "Info must not be null"); // if idx < 0, max > 0, max + idx may fall between 0 and - // length-1 and if min < 0, min + idx may overflow and be >= + // length-1 and if min < 0, min + idx may underflow/overflow and be >= // 0. The predicate wouldn't trigger but some accesses could // be with a negative index. This test guarantees that for the // min and max value that are kept the predicate can't let // some incorrect accesses happen. - bool range_cond = (info->_max < 0 || info->_max + min_jint <= info->_min); + bool range_cond = (info->_max < 0 || (info->_max + min_jint) <= info->_min); // Generate code only if more than 2 range checks can be eliminated because of that. // 2 because at least 2 comparisons are done @@ -843,7 +846,7 @@ void RangeCheckEliminator::process_access_indexed(BlockBegin *loop_header, Block ); remove_range_check(ai); - } else if (_optimistic && loop_header) { + } else if (false && _optimistic && loop_header) { assert(ai->array(), "Array must not be null!"); assert(ai->index(), "Index must not be null!"); diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 3183bb04e77d9..41a6b151b28a0 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -1504,6 +1504,19 @@ JRT_ENTRY(void, Runtime1::predicate_failed_trap(JavaThread* current)) JRT_END +// Check exception if AbortVMOnException flag set +JRT_LEAF(void, Runtime1::check_abort_on_vm_exception(oopDesc* ex)) + ResourceMark rm; + const char* message = nullptr; + if (ex->is_a(vmClasses::Throwable_klass())) { + oop msg = java_lang_Throwable::message(ex); + if (msg != nullptr) { + message = java_lang_String::as_utf8_string(msg); + } + } + Exceptions::debug_check_abort(ex->klass()->external_name(), message); +JRT_END + #ifndef PRODUCT void Runtime1::print_statistics() { tty->print_cr("C1 Runtime statistics:"); diff --git a/src/hotspot/share/c1/c1_Runtime1.hpp b/src/hotspot/share/c1/c1_Runtime1.hpp index 3dcb27476a6f9..525cfd7f92ee5 100644 --- a/src/hotspot/share/c1/c1_Runtime1.hpp +++ b/src/hotspot/share/c1/c1_Runtime1.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -191,6 +191,8 @@ class Runtime1: public AllStatic { static void predicate_failed_trap(JavaThread* current); + static void check_abort_on_vm_exception(oopDesc* ex); + static void print_statistics() PRODUCT_RETURN; }; diff --git a/src/hotspot/share/c1/c1_ValueMap.cpp b/src/hotspot/share/c1/c1_ValueMap.cpp index 9fe4ed8df67e4..2e600ff0f10d3 100644 --- a/src/hotspot/share/c1/c1_ValueMap.cpp +++ b/src/hotspot/share/c1/c1_ValueMap.cpp @@ -359,6 +359,33 @@ LoopInvariantCodeMotion::LoopInvariantCodeMotion(ShortLoopOptimizer *slo, Global } } +class CheckInsertionPoint : public ValueVisitor { + private: + Value _insert; + bool _valid = true; + + void visit(Value* vp) { + assert(*vp != nullptr, "value should not be null"); + if (_insert->dominator_depth() < (*vp)->dominator_depth()) { + _valid = false; + } + } + + public: + bool is_valid() { return _valid; } + CheckInsertionPoint(Value insert) + : _insert(insert) { + assert(insert != nullptr, "insertion point should not be null"); + } +}; + +// Check that insertion point has higher dom depth than all inputs to cur +static bool is_dominated_by_inputs(Instruction* insertion_point, Instruction* cur) { + CheckInsertionPoint v(insertion_point); + cur->input_values_do(&v); + return v.is_valid(); +} + void LoopInvariantCodeMotion::process_block(BlockBegin* block) { TRACE_VALUE_NUMBERING(tty->print_cr("processing block B%d", block->block_id())); @@ -394,7 +421,7 @@ void LoopInvariantCodeMotion::process_block(BlockBegin* block) { cur_invariant = is_invariant(cvt->value()); } - if (cur_invariant) { + if (cur_invariant && is_dominated_by_inputs(_insertion_point, cur)) { // perform value numbering and mark instruction as loop-invariant _gvn->substitute(cur); diff --git a/src/hotspot/share/cds/cdsProtectionDomain.cpp b/src/hotspot/share/cds/cdsProtectionDomain.cpp index d1020b992e5bc..3ad2af670f047 100644 --- a/src/hotspot/share/cds/cdsProtectionDomain.cpp +++ b/src/hotspot/share/cds/cdsProtectionDomain.cpp @@ -241,7 +241,7 @@ Handle CDSProtectionDomain::get_shared_protection_domain(Handle class_loader, TRAPS) { Handle protection_domain; if (shared_protection_domain(shared_path_index) == nullptr) { - Handle pd = get_protection_domain_from_classloader(class_loader, url, THREAD); + Handle pd = get_protection_domain_from_classloader(class_loader, url, CHECK_NH); atomic_set_shared_protection_domain(shared_path_index, pd()); } diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index b8fe625d12adb..7d12e1acaf8e4 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -368,7 +368,7 @@ void SharedClassPathEntry::copy_from(SharedClassPathEntry* ent, ClassLoaderData* _from_class_path_attr = ent->_from_class_path_attr; set_name(ent->name(), CHECK); - if (ent->is_jar() && !ent->is_signed() && ent->manifest() != nullptr) { + if (ent->is_jar() && ent->manifest() != nullptr) { Array* buf = MetadataFactory::new_array(loader_data, ent->manifest_size(), CHECK); @@ -622,29 +622,6 @@ class ManifestStream: public ResourceObj { buf[len] = 0; return buf; } - - // The return value indicates if the JAR is signed or not - bool check_is_signed() { - u1* attr = _current; - bool isSigned = false; - while (_current < _buffer_end) { - if (*_current == '\n') { - *_current = '\0'; - u1* value = (u1*)strchr((char*)attr, ':'); - if (value != nullptr) { - assert(*(value+1) == ' ', "Unrecognized format" ); - if (strstr((char*)attr, "-Digest") != nullptr) { - isSigned = true; - break; - } - } - *_current = '\n'; // restore - attr = _current + 1; - } - _current ++; - } - return isSigned; - } }; void FileMapInfo::update_jar_manifest(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS) { @@ -657,18 +634,14 @@ void FileMapInfo::update_jar_manifest(ClassPathEntry *cpe, SharedClassPathEntry* if (manifest != nullptr) { ManifestStream* stream = new ManifestStream((u1*)manifest, manifest_size); - if (stream->check_is_signed()) { - ent->set_is_signed(); - } else { - // Copy the manifest into the shared archive - manifest = ClassLoaderExt::read_raw_manifest(THREAD, cpe, &manifest_size); - Array* buf = MetadataFactory::new_array(loader_data, - manifest_size, - CHECK); - char* p = (char*)(buf->data()); - memcpy(p, manifest, manifest_size); - ent->set_manifest(buf); - } + // Copy the manifest into the shared archive + manifest = ClassLoaderExt::read_raw_manifest(THREAD, cpe, &manifest_size); + Array* buf = MetadataFactory::new_array(loader_data, + manifest_size, + CHECK); + char* p = (char*)(buf->data()); + memcpy(p, manifest, manifest_size); + ent->set_manifest(buf); } } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 160f598796dfc..9848e8f434a27 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -53,7 +53,6 @@ class SharedClassPathEntry : public MetaspaceObj { enum { modules_image_entry, jar_entry, - signed_jar_entry, dir_entry, non_existent_entry, unknown_entry @@ -90,10 +89,6 @@ class SharedClassPathEntry : public MetaspaceObj { bool is_dir() const { return _type == dir_entry; } bool is_modules_image() const { return _type == modules_image_entry; } bool is_jar() const { return _type == jar_entry; } - bool is_signed() const { return _type == signed_jar_entry; } - void set_is_signed() { - _type = signed_jar_entry; - } bool from_class_path_attr() { return _from_class_path_attr; } time_t timestamp() const { return _timestamp; } const char* name() const; diff --git a/src/hotspot/share/cds/unregisteredClasses.cpp b/src/hotspot/share/cds/unregisteredClasses.cpp index 53b9debcd6295..06d006ea1bb97 100644 --- a/src/hotspot/share/cds/unregisteredClasses.cpp +++ b/src/hotspot/share/cds/unregisteredClasses.cpp @@ -46,11 +46,9 @@ InstanceKlass* UnregisteredClasses::load_class(Symbol* name, const char* path, T assert(name != nullptr, "invariant"); assert(DumpSharedSpaces, "this function is only used with -Xshare:dump"); - { - PerfClassTraceTime vmtimer(ClassLoader::perf_sys_class_lookup_time(), - THREAD->get_thread_stat()->perf_timers_addr(), - PerfClassTraceTime::CLASS_LOAD); - } + PerfClassTraceTime vmtimer(ClassLoader::perf_app_classload_time(), + THREAD->get_thread_stat()->perf_timers_addr(), + PerfClassTraceTime::CLASS_LOAD); Symbol* path_symbol = SymbolTable::new_symbol(path); Handle url_classloader = get_url_classloader(path_symbol, CHECK_NULL); diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 7212b0d90235f..74208152988bd 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -1715,6 +1715,7 @@ void ciEnv::dump_replay_data(int compile_id) { tty->print_cr("# Compiler replay data is saved as: %s", buffer); } else { tty->print_cr("# Can't open file to dump replay data."); + close(fd); } } } @@ -1739,6 +1740,7 @@ void ciEnv::dump_inline_data(int compile_id) { tty->print_cr("%s", buffer); } else { tty->print_cr("# Can't open file to dump inline data."); + close(fd); } } } diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 4e1078a1cd9cd..20de43ad835d0 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -4321,6 +4321,7 @@ void ClassFileParser::check_super_interface_access(const InstanceKlass* this_kla (same_module) ? this_klass->joint_in_module_of_loader(k) : this_klass->class_in_module_of_loader(), (same_module) ? "" : "; ", (same_module) ? "" : k->class_in_module_of_loader()); + return; } else { // Add additional message content. Exceptions::fthrow( @@ -4328,6 +4329,7 @@ void ClassFileParser::check_super_interface_access(const InstanceKlass* this_kla vmSymbols::java_lang_IllegalAccessError(), "superinterface check failed: %s", msg); + return; } } } diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index ab29ec3524d40..5e89673a56063 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -122,7 +122,6 @@ PerfCounter* ClassLoader::_perf_class_verify_selftime = nullptr; PerfCounter* ClassLoader::_perf_classes_linked = nullptr; PerfCounter* ClassLoader::_perf_class_link_time = nullptr; PerfCounter* ClassLoader::_perf_class_link_selftime = nullptr; -PerfCounter* ClassLoader::_perf_sys_class_lookup_time = nullptr; PerfCounter* ClassLoader::_perf_shared_classload_time = nullptr; PerfCounter* ClassLoader::_perf_sys_classload_time = nullptr; PerfCounter* ClassLoader::_perf_app_classload_time = nullptr; @@ -521,7 +520,8 @@ void ClassLoader::setup_app_search_path(JavaThread* current, const char *class_p while (cp_stream.has_next()) { const char* path = cp_stream.get_next(); - update_class_path_entry_list(current, path, false, false, false); + update_class_path_entry_list(current, path, /* check_for_duplicates */ true, + /* is_boot_append */ false, /* from_class_path_attr */ false); } } @@ -666,7 +666,8 @@ void ClassLoader::setup_bootstrap_search_path_impl(JavaThread* current, const ch } else { // Every entry on the boot class path after the initial base piece, // which is set by os::set_boot_path(), is considered an appended entry. - update_class_path_entry_list(current, path, false, true, false); + update_class_path_entry_list(current, path, /* check_for_duplicates */ false, + /* is_boot_append */ true, /* from_class_path_attr */ false); } } } @@ -801,7 +802,7 @@ void ClassLoader::add_to_boot_append_entries(ClassPathEntry *new_entry) { // Note that at dump time, ClassLoader::_app_classpath_entries are NOT used for // loading app classes. Instead, the app class are loaded by the // jdk/internal/loader/ClassLoaders$AppClassLoader instance. -void ClassLoader::add_to_app_classpath_entries(JavaThread* current, +bool ClassLoader::add_to_app_classpath_entries(JavaThread* current, ClassPathEntry* entry, bool check_for_duplicates) { #if INCLUDE_CDS @@ -811,7 +812,7 @@ void ClassLoader::add_to_app_classpath_entries(JavaThread* current, while (e != nullptr) { if (strcmp(e->name(), entry->name()) == 0) { // entry already exists - return; + return false; } e = e->next(); } @@ -830,6 +831,7 @@ void ClassLoader::add_to_app_classpath_entries(JavaThread* current, ClassLoaderExt::process_jar_manifest(current, entry); } #endif + return true; } // Returns true IFF the file/dir exists and the entry was successfully created. @@ -852,7 +854,10 @@ bool ClassLoader::update_class_path_entry_list(JavaThread* current, if (is_boot_append) { add_to_boot_append_entries(new_entry); } else { - add_to_app_classpath_entries(current, new_entry, check_for_duplicates); + if (!add_to_app_classpath_entries(current, new_entry, check_for_duplicates)) { + // new_entry is not saved, free it now + delete new_entry; + } } return true; } else { @@ -1368,7 +1373,6 @@ void ClassLoader::initialize(TRAPS) { NEWPERFEVENTCOUNTER(_perf_classes_linked, SUN_CLS, "linkedClasses"); NEWPERFEVENTCOUNTER(_perf_classes_verified, SUN_CLS, "verifiedClasses"); - NEWPERFTICKCOUNTER(_perf_sys_class_lookup_time, SUN_CLS, "lookupSysClassTime"); NEWPERFTICKCOUNTER(_perf_shared_classload_time, SUN_CLS, "sharedClassLoadTime"); NEWPERFTICKCOUNTER(_perf_sys_classload_time, SUN_CLS, "sysClassLoadTime"); NEWPERFTICKCOUNTER(_perf_app_classload_time, SUN_CLS, "appClassLoadTime"); diff --git a/src/hotspot/share/classfile/classLoader.hpp b/src/hotspot/share/classfile/classLoader.hpp index 0733a5a347c82..4cb1967194ab9 100644 --- a/src/hotspot/share/classfile/classLoader.hpp +++ b/src/hotspot/share/classfile/classLoader.hpp @@ -168,7 +168,6 @@ class ClassLoader: AllStatic { static PerfCounter* _perf_classes_linked; static PerfCounter* _perf_class_link_time; static PerfCounter* _perf_class_link_selftime; - static PerfCounter* _perf_sys_class_lookup_time; static PerfCounter* _perf_shared_classload_time; static PerfCounter* _perf_sys_classload_time; static PerfCounter* _perf_app_classload_time; @@ -222,7 +221,7 @@ class ClassLoader: AllStatic { CDS_ONLY(static ClassPathEntry* _last_module_path_entry;) CDS_ONLY(static void setup_app_search_path(JavaThread* current, const char* class_path);) CDS_ONLY(static void setup_module_search_path(JavaThread* current, const char* path);) - static void add_to_app_classpath_entries(JavaThread* current, + static bool add_to_app_classpath_entries(JavaThread* current, ClassPathEntry* entry, bool check_for_duplicates); CDS_ONLY(static void add_to_module_path_entries(const char* path, @@ -289,7 +288,6 @@ class ClassLoader: AllStatic { static PerfCounter* perf_classes_linked() { return _perf_classes_linked; } static PerfCounter* perf_class_link_time() { return _perf_class_link_time; } static PerfCounter* perf_class_link_selftime() { return _perf_class_link_selftime; } - static PerfCounter* perf_sys_class_lookup_time() { return _perf_sys_class_lookup_time; } static PerfCounter* perf_shared_classload_time() { return _perf_shared_classload_time; } static PerfCounter* perf_sys_classload_time() { return _perf_sys_classload_time; } static PerfCounter* perf_app_classload_time() { return _perf_app_classload_time; } diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index aa1f6f531077b..282a025c31d3c 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -1009,7 +1009,11 @@ void ClassLoaderData::print_on(outputStream* out) const { _holder.print_on(out); out->print_cr(""); } - out->print_cr(" - class loader " INTPTR_FORMAT, p2i(_class_loader.ptr_raw())); + if (!_unloading) { + out->print_cr(" - class loader " INTPTR_FORMAT, p2i(_class_loader.peek())); + } else { + out->print_cr(" - class loader "); + } out->print_cr(" - metaspace " INTPTR_FORMAT, p2i(_metaspace)); out->print_cr(" - unloading %s", _unloading ? "true" : "false"); out->print_cr(" - class mirror holder %s", _has_class_mirror_holder ? "true" : "false"); diff --git a/src/hotspot/share/classfile/dictionary.cpp b/src/hotspot/share/classfile/dictionary.cpp index f60d426f5fbce..f1f02e11d8133 100644 --- a/src/hotspot/share/classfile/dictionary.cpp +++ b/src/hotspot/share/classfile/dictionary.cpp @@ -229,11 +229,13 @@ class DictionaryLookup : StackObj { uintx get_hash() const { return _name->identity_hash(); } - bool equals(DictionaryEntry** value, bool* is_dead) { + bool equals(DictionaryEntry** value) { DictionaryEntry *entry = *value; - *is_dead = false; return (entry->instance_klass()->name() == _name); } + bool is_dead(DictionaryEntry** value) { + return false; + } }; // Add a loaded class to the dictionary. diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index a7582e535e6e5..3e00a3fab4e1f 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -86,6 +86,7 @@ #include "runtime/vframe.inline.hpp" #include "runtime/vm_version.hpp" #include "utilities/align.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" #include "utilities/preserveException.hpp" #include "utilities/utf8.hpp" @@ -2761,15 +2762,19 @@ Handle java_lang_Throwable::create_initialization_error(JavaThread* current, Han assert(throwable.not_null(), "shouldn't be"); // Now create the message from the original exception and thread name. - Symbol* message = java_lang_Throwable::detail_message(throwable()); ResourceMark rm(current); + const char *message = nullptr; + oop detailed_message = java_lang_Throwable::message(throwable()); + if (detailed_message != nullptr) { + message = java_lang_String::as_utf8_string(detailed_message); + } stringStream st; st.print("Exception %s%s ", throwable()->klass()->name()->as_klass_external_name(), message == nullptr ? "" : ":"); if (message == nullptr) { st.print("[in thread \"%s\"]", current->name()); } else { - st.print("%s [in thread \"%s\"]", message->as_C_string(), current->name()); + st.print("%s [in thread \"%s\"]", message, current->name()); } Symbol* exception_name = vmSymbols::java_lang_ExceptionInInitializerError(); @@ -4721,7 +4726,7 @@ class UnsafeConstantsFixup : public FieldClosure { UnsafeConstantsFixup() { // round up values for all static final fields _address_size = sizeof(void*); - _page_size = (int)os::vm_page_size(); + _page_size = AIX_ONLY(sysconf(_SC_PAGESIZE)) NOT_AIX((int)os::vm_page_size()); _big_endian = LITTLE_ENDIAN_ONLY(false) BIG_ENDIAN_ONLY(true); _use_unaligned_access = UseUnalignedAccesses; _data_cache_line_flush_size = (int)VM_Version::data_cache_line_flush_size(); diff --git a/src/hotspot/share/classfile/loaderConstraints.cpp b/src/hotspot/share/classfile/loaderConstraints.cpp index 261ec96604a46..3a34800c05172 100644 --- a/src/hotspot/share/classfile/loaderConstraints.cpp +++ b/src/hotspot/share/classfile/loaderConstraints.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -348,7 +348,7 @@ bool LoaderConstraintTable::add_entry(Symbol* class_name, } else if (pp1 == nullptr) { pp2->extend_loader_constraint(class_name, loader1, klass); } else if (pp2 == nullptr) { - pp1->extend_loader_constraint(class_name, loader1, klass); + pp1->extend_loader_constraint(class_name, loader2, klass); } else { merge_loader_constraints(class_name, pp1, pp2, klass); } diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index 89381b1a785f1..19ac5cc7709de 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -53,6 +53,7 @@ #include "runtime/mutexLocker.hpp" #include "runtime/safepointVerifiers.hpp" #include "runtime/timerTrace.hpp" +#include "runtime/trimNativeHeap.hpp" #include "services/diagnosticCommand.hpp" #include "utilities/concurrentHashTable.inline.hpp" #include "utilities/concurrentHashTableTasks.inline.hpp" @@ -175,11 +176,9 @@ class StringTableLookupJchar : StackObj { uintx get_hash() const { return _hash; } - bool equals(WeakHandle* value, bool* is_dead) { + bool equals(WeakHandle* value) { oop val_oop = value->peek(); if (val_oop == nullptr) { - // dead oop, mark this hash dead for cleaning - *is_dead = true; return false; } bool equals = java_lang_String::equals(val_oop, _str, _len); @@ -190,6 +189,10 @@ class StringTableLookupJchar : StackObj { _found = Handle(_thread, value->resolve()); return true; } + bool is_dead(WeakHandle* value) { + oop val_oop = value->peek(); + return val_oop == nullptr; + } }; class StringTableLookupOop : public StackObj { @@ -207,11 +210,9 @@ class StringTableLookupOop : public StackObj { return _hash; } - bool equals(WeakHandle* value, bool* is_dead) { + bool equals(WeakHandle* value) { oop val_oop = value->peek(); if (val_oop == nullptr) { - // dead oop, mark this hash dead for cleaning - *is_dead = true; return false; } bool equals = java_lang_String::equals(_find(), val_oop); @@ -222,6 +223,11 @@ class StringTableLookupOop : public StackObj { _found = Handle(_thread, value->resolve()); return true; } + + bool is_dead(WeakHandle* value) { + oop val_oop = value->peek(); + return val_oop == nullptr; + } }; void StringTable::create_table() { @@ -456,6 +462,7 @@ void StringTable::clean_dead_entries(JavaThread* jt) { StringTableDeleteCheck stdc; StringTableDoDelete stdd; + NativeHeapTrimmer::SuspendMark sm("stringtable"); { TraceTime timer("Clean", TRACETIME_LOG(Debug, stringtable, perf)); while(bdt.do_task(jt, stdc, stdd)) { diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp index 61d5ba576b54a..91eacc923c250 100644 --- a/src/hotspot/share/classfile/symbolTable.cpp +++ b/src/hotspot/share/classfile/symbolTable.cpp @@ -37,6 +37,7 @@ #include "runtime/atomic.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/timerTrace.hpp" +#include "runtime/trimNativeHeap.hpp" #include "services/diagnosticCommand.hpp" #include "utilities/concurrentHashTable.inline.hpp" #include "utilities/concurrentHashTableTasks.inline.hpp" @@ -337,6 +338,7 @@ Symbol* SymbolTable::lookup_common(const char* name, } Symbol* SymbolTable::new_symbol(const char* name, int len) { + assert(len <= Symbol::max_length(), "sanity"); unsigned int hash = hash_symbol(name, len, _alt_hash); Symbol* sym = lookup_common(name, len, hash); if (sym == nullptr) { @@ -352,6 +354,7 @@ Symbol* SymbolTable::new_symbol(const Symbol* sym, int begin, int end) { assert(sym->refcount() != 0, "require a valid symbol"); const char* name = (const char*)sym->base() + begin; int len = end - begin; + assert(len <= Symbol::max_length(), "sanity"); unsigned int hash = hash_symbol(name, len, _alt_hash); Symbol* found = lookup_common(name, len, hash); if (found == nullptr) { @@ -371,7 +374,11 @@ class SymbolTableLookup : StackObj { uintx get_hash() const { return _hash; } - bool equals(Symbol* value, bool* is_dead) { + // Note: When equals() returns "true", the symbol's refcount is incremented. This is + // needed to ensure that the symbol is kept alive before equals() returns to the caller, + // so that another thread cannot clean the symbol up concurrently. The caller is + // responsible for decrementing the refcount, when the symbol is no longer needed. + bool equals(Symbol* value) { assert(value != nullptr, "expected valid value"); Symbol *sym = value; if (sym->equals(_str, _len)) { @@ -380,14 +387,15 @@ class SymbolTableLookup : StackObj { return true; } else { assert(sym->refcount() == 0, "expected dead symbol"); - *is_dead = true; return false; } } else { - *is_dead = (sym->refcount() == 0); return false; } } + bool is_dead(Symbol* value) { + return value->refcount() == 0; + } }; class SymbolTableGet : public StackObj { @@ -737,6 +745,7 @@ void SymbolTable::clean_dead_entries(JavaThread* jt) { SymbolTableDeleteCheck stdc; SymbolTableDoDelete stdd; + NativeHeapTrimmer::SuspendMark sm("symboltable"); { TraceTime timer("Clean", TRACETIME_LOG(Debug, symboltable, perf)); while (bdt.do_task(jt, stdc, stdd)) { diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index 13ee901371ac9..34f65a0e90743 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -2250,11 +2250,12 @@ void ClassVerifier::verify_switch( "low must be less than or equal to high in tableswitch"); return; } - keys = high - low + 1; - if (keys < 0) { + int64_t keys64 = ((int64_t)high - low) + 1; + if (keys64 > 65535) { // Max code length verify_error(ErrorContext::bad_code(bci), "too many keys in tableswitch"); return; } + keys = (int)keys64; delta = 1; } else { keys = (int)Bytes::get_Java_u4(aligned_bcp + jintSize); diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 18843ad962266..afb807065ab0b 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -204,7 +204,8 @@ void RuntimeBlob::trace_new_stub(RuntimeBlob* stub, const char* name1, const cha if (PrintStubCode) { ttyLocker ttyl; tty->print_cr("- - - [BEGIN] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); - tty->print_cr("Decoding %s " INTPTR_FORMAT, stub_id, (intptr_t) stub); + tty->print_cr("Decoding %s " PTR_FORMAT " [" PTR_FORMAT ", " PTR_FORMAT "] (%d bytes)", + stub_id, p2i(stub), p2i(stub->code_begin()), p2i(stub->code_end()), stub->code_size()); Disassembler::decode(stub->code_begin(), stub->code_end(), tty NOT_PRODUCT(COMMA &stub->asm_remarks())); if ((stub->oop_maps() != nullptr) && AbstractDisassembler::show_structs()) { diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index eb7f49b185af0..6c40fe992aea0 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -119,11 +119,6 @@ class CodeBlob { #ifndef PRODUCT AsmRemarks _asm_remarks; DbgStrings _dbg_strings; - - ~CodeBlob() { - _asm_remarks.clear(); - _dbg_strings.clear(); - } #endif // not PRODUCT CodeBlob(const char* name, CompilerType type, const CodeBlobLayout& layout, int frame_complete_offset, @@ -132,10 +127,17 @@ class CodeBlob { CodeBlob(const char* name, CompilerType type, const CodeBlobLayout& layout, CodeBuffer* cb, int frame_complete_offset, int frame_size, OopMapSet* oop_maps, bool caller_must_gc_arguments, bool compiled = false); + + void operator delete(void* p) { } + public: // Only used by unit test. CodeBlob() : _type(compiler_none) {} + virtual ~CodeBlob() { + assert(_oop_maps == nullptr, "Not flushed"); + } + // Returns the space needed for CodeBlob static unsigned int allocation_size(CodeBuffer* cb, int header_size); static unsigned int align_code_offset(int offset); @@ -404,10 +406,6 @@ class BufferBlob: public RuntimeBlob { BufferBlob(const char* name, int size); BufferBlob(const char* name, int size, CodeBuffer* cb); - // This ordinary operator delete is needed even though not used, so the - // below two-argument operator delete will be treated as a placement - // delete rather than an ordinary sized delete; see C++14 3.7.4.2/p2. - void operator delete(void* p); void* operator new(size_t s, unsigned size) throw(); public: @@ -492,10 +490,6 @@ class RuntimeStub: public RuntimeBlob { bool caller_must_gc_arguments ); - // This ordinary operator delete is needed even though not used, so the - // below two-argument operator delete will be treated as a placement - // delete rather than an ordinary sized delete; see C++14 3.7.4.2/p2. - void operator delete(void* p); void* operator new(size_t s, unsigned size) throw(); public: @@ -532,10 +526,6 @@ class SingletonBlob: public RuntimeBlob { friend class VMStructs; protected: - // This ordinary operator delete is needed even though not used, so the - // below two-argument operator delete will be treated as a placement - // delete rather than an ordinary sized delete; see C++14 3.7.4.2/p2. - void operator delete(void* p); void* operator new(size_t s, unsigned size) throw(); public: @@ -750,10 +740,6 @@ class UpcallStub: public RuntimeBlob { intptr_t exception_handler_offset, jobject receiver, ByteSize frame_data_offset); - // This ordinary operator delete is needed even though not used, so the - // below two-argument operator delete will be treated as a placement - // delete rather than an ordinary sized delete; see C++14 3.7.4.2/p2. - void operator delete(void* p); void* operator new(size_t s, unsigned size) throw(); struct FrameData { diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index 2ea72a1fcbdaa..3bc1db70251b3 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -310,9 +310,20 @@ void CodeCache::initialize_heaps() { FLAG_SET_ERGO(ProfiledCodeHeapSize, profiled_size); FLAG_SET_ERGO(NonProfiledCodeHeapSize, non_profiled_size); + const size_t ps = page_size(false, 8); + // Print warning if using large pages but not able to use the size given + if (UseLargePages) { + const size_t lg_ps = page_size(false, 1); + if (ps < lg_ps) { + log_warning(codecache)("Code cache size too small for " PROPERFMT " pages. " + "Reverting to smaller page size (" PROPERFMT ").", + PROPERFMTARGS(lg_ps), PROPERFMTARGS(ps)); + } + } + // If large page support is enabled, align code heaps according to large // page size to make sure that code cache is covered by large pages. - const size_t alignment = MAX2(page_size(false, 8), os::vm_allocation_granularity()); + const size_t alignment = MAX2(ps, os::vm_allocation_granularity()); non_nmethod_size = align_up(non_nmethod_size, alignment); profiled_size = align_down(profiled_size, alignment); non_profiled_size = align_down(non_profiled_size, alignment); @@ -324,7 +335,7 @@ void CodeCache::initialize_heaps() { // Non-nmethods // Profiled nmethods // ---------- low ------------ - ReservedCodeSpace rs = reserve_heap_memory(cache_size); + ReservedCodeSpace rs = reserve_heap_memory(cache_size, ps); ReservedSpace profiled_space = rs.first_part(profiled_size); ReservedSpace rest = rs.last_part(profiled_size); ReservedSpace non_method_space = rest.first_part(non_nmethod_size); @@ -354,9 +365,8 @@ size_t CodeCache::page_size(bool aligned, size_t min_pages) { } } -ReservedCodeSpace CodeCache::reserve_heap_memory(size_t size) { +ReservedCodeSpace CodeCache::reserve_heap_memory(size_t size, size_t rs_ps) { // Align and reserve space for code cache - const size_t rs_ps = page_size(); const size_t rs_align = MAX2(rs_ps, os::vm_allocation_granularity()); const size_t rs_size = align_up(size, rs_align); ReservedCodeSpace rs(rs_size, rs_align, rs_ps); @@ -462,10 +472,10 @@ CodeHeap* CodeCache::get_code_heap_containing(void* start) { return nullptr; } -CodeHeap* CodeCache::get_code_heap(const CodeBlob* cb) { +CodeHeap* CodeCache::get_code_heap(const void* cb) { assert(cb != nullptr, "CodeBlob is null"); FOR_ALL_HEAPS(heap) { - if ((*heap)->contains_blob(cb)) { + if ((*heap)->contains(cb)) { return *heap; } } @@ -594,6 +604,7 @@ void CodeCache::free(CodeBlob* cb) { heap->set_adapter_count(heap->adapter_count() - 1); } + cb->~CodeBlob(); // Get heap for given CodeBlob and deallocate get_code_heap(cb)->deallocate(cb); @@ -1194,7 +1205,7 @@ void CodeCache::initialize() { FLAG_SET_ERGO(NonNMethodCodeHeapSize, (uintx)os::vm_page_size()); FLAG_SET_ERGO(ProfiledCodeHeapSize, 0); FLAG_SET_ERGO(NonProfiledCodeHeapSize, 0); - ReservedCodeSpace rs = reserve_heap_memory(ReservedCodeCacheSize); + ReservedCodeSpace rs = reserve_heap_memory(ReservedCodeCacheSize, page_size(false, 8)); // Register CodeHeaps with LSan as we sometimes embed pointers to malloc memory. LSAN_REGISTER_ROOT_REGION(rs.base(), rs.size()); add_heap(rs, "CodeCache", CodeBlobType::All); diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 6fb3a6bd981a8..8abc4043ae6dd 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -117,11 +117,11 @@ class CodeCache : AllStatic { // Creates a new heap with the given name and size, containing CodeBlobs of the given type static void add_heap(ReservedSpace rs, const char* name, CodeBlobType code_blob_type); static CodeHeap* get_code_heap_containing(void* p); // Returns the CodeHeap containing the given pointer, or nullptr - static CodeHeap* get_code_heap(const CodeBlob* cb); // Returns the CodeHeap for the given CodeBlob + static CodeHeap* get_code_heap(const void* cb); // Returns the CodeHeap for the given CodeBlob static CodeHeap* get_code_heap(CodeBlobType code_blob_type); // Returns the CodeHeap for the given CodeBlobType // Returns the name of the VM option to set the size of the corresponding CodeHeap static const char* get_code_heap_flag_name(CodeBlobType code_blob_type); - static ReservedCodeSpace reserve_heap_memory(size_t size); // Reserves one continuous chunk of memory for the CodeHeaps + static ReservedCodeSpace reserve_heap_memory(size_t size, size_t rs_ps); // Reserves one continuous chunk of memory for the CodeHeaps // Iteration static CodeBlob* first_blob(CodeHeap* heap); // Returns the first CodeBlob on the given CodeHeap @@ -397,10 +397,10 @@ template class CodeBlobIterator : publi // If set to nullptr, initialized by first call to next() _code_blob = nm; if (nm != nullptr) { - while(!(*_heap)->contains_blob(_code_blob)) { + while(!(*_heap)->contains(_code_blob)) { ++_heap; } - assert((*_heap)->contains_blob(_code_blob), "match not found"); + assert((*_heap)->contains(_code_blob), "match not found"); } } diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp index c19ee182d5186..c6294ff56279b 100644 --- a/src/hotspot/share/code/compiledIC.cpp +++ b/src/hotspot/share/code/compiledIC.cpp @@ -128,11 +128,13 @@ void CompiledIC::internal_set_ic_destination(address entry_point, bool is_icstub tty->cr(); } +#ifdef ASSERT { CodeBlob* cb = CodeCache::find_blob(_call->instruction_address()); assert(cb != nullptr && cb->is_compiled(), "must be compiled"); - _call->set_destination_mt_safe(entry_point); } +#endif + _call->set_destination_mt_safe(entry_point); if (is_optimized() || is_icstub) { // Optimized call sites don't have a cache value and ICStub call diff --git a/src/hotspot/share/code/icBuffer.cpp b/src/hotspot/share/code/icBuffer.cpp index a43d3678ad31b..520a8c7525906 100644 --- a/src/hotspot/share/code/icBuffer.cpp +++ b/src/hotspot/share/code/icBuffer.cpp @@ -140,7 +140,7 @@ void ICStub::print() { void InlineCacheBuffer::initialize() { if (_buffer != nullptr) return; // already initialized - _buffer = new StubQueue(new ICStubInterface, 10*K, InlineCacheBuffer_lock, "InlineCacheBuffer"); + _buffer = new StubQueue(new ICStubInterface, checked_cast(InlineCacheBufferSize), InlineCacheBuffer_lock, "InlineCacheBuffer"); assert (_buffer != nullptr, "cannot allocate InlineCacheBuffer"); } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index ded61f989487f..fb2e5bd78b083 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -394,6 +394,7 @@ PcDesc* PcDescCache::find_pc_desc(int pc_offset, bool approximate) { } void PcDescCache::add_pc_desc(PcDesc* pc_desc) { + MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current());) NOT_PRODUCT(++pc_nmethod_stats.pc_desc_adds); // Update the LRU cache by shifting pc_desc forward. for (int i = 0; i < cache_size; i++) { @@ -2751,9 +2752,6 @@ void nmethod::decode2(outputStream* ost) const { AbstractDisassembler::show_block_comment()); #endif - // Decoding an nmethod can write to a PcDescCache (see PcDescCache::add_pc_desc) - MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current());) - st->cr(); this->print(st); st->cr(); diff --git a/src/hotspot/share/code/stubs.cpp b/src/hotspot/share/code/stubs.cpp index 55e0207c87d6e..6037b683b12dc 100644 --- a/src/hotspot/share/code/stubs.cpp +++ b/src/hotspot/share/code/stubs.cpp @@ -217,8 +217,6 @@ void StubQueue::verify() { guarantee(0 <= _queue_begin && _queue_begin < _buffer_limit, "_queue_begin out of bounds"); guarantee(0 <= _queue_end && _queue_end <= _buffer_limit, "_queue_end out of bounds"); // verify alignment - guarantee(_buffer_size % stub_alignment() == 0, "_buffer_size not aligned"); - guarantee(_buffer_limit % stub_alignment() == 0, "_buffer_limit not aligned"); guarantee(_queue_begin % stub_alignment() == 0, "_queue_begin not aligned"); guarantee(_queue_end % stub_alignment() == 0, "_queue_end not aligned"); // verify buffer limit/size relationship diff --git a/src/hotspot/share/code/vtableStubs.cpp b/src/hotspot/share/code/vtableStubs.cpp index 42a8a63a38fc1..934f805eefcd6 100644 --- a/src/hotspot/share/code/vtableStubs.cpp +++ b/src/hotspot/share/code/vtableStubs.cpp @@ -230,8 +230,9 @@ address VtableStubs::find_stub(bool is_vtable_stub, int vtable_index) { enter(is_vtable_stub, vtable_index, s); if (PrintAdapterHandlers) { - tty->print_cr("Decoding VtableStub %s[%d]@" INTX_FORMAT, - is_vtable_stub? "vtbl": "itbl", vtable_index, p2i(VtableStub::receiver_location())); + tty->print_cr("Decoding VtableStub %s[%d]@" PTR_FORMAT " [" PTR_FORMAT ", " PTR_FORMAT "] (" SIZE_FORMAT " bytes)", + is_vtable_stub? "vtbl": "itbl", vtable_index, p2i(VtableStub::receiver_location()), + p2i(s->code_begin()), p2i(s->code_end()), pointer_delta(s->code_end(), s->code_begin(), 1)); Disassembler::decode(s->code_begin(), s->code_end()); } // Notify JVMTI about this stub. The event will be recorded by the enclosing diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index de8cce86578ad..8a83a864f62d9 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -1772,17 +1772,22 @@ bool CompileBroker::init_compiler_runtime() { return true; } +void CompileBroker::free_buffer_blob_if_allocated(CompilerThread* thread) { + BufferBlob* blob = thread->get_buffer_blob(); + if (blob != nullptr) { + blob->flush(); + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + CodeCache::free(blob); + } +} + /** * If C1 and/or C2 initialization failed, we shut down all compilation. * We do this to keep things simple. This can be changed if it ever turns * out to be a problem. */ void CompileBroker::shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread) { - // Free buffer blob, if allocated - if (thread->get_buffer_blob() != nullptr) { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - CodeCache::free(thread->get_buffer_blob()); - } + free_buffer_blob_if_allocated(thread); if (comp->should_perform_shutdown()) { // There are two reasons for shutting down the compiler @@ -1921,11 +1926,7 @@ void CompileBroker::compiler_thread_loop() { // Notify compiler that the compiler thread is about to stop thread->compiler()->stopping_compiler_thread(thread); - // Free buffer blob, if allocated - if (thread->get_buffer_blob() != nullptr) { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - CodeCache::free(thread->get_buffer_blob()); - } + free_buffer_blob_if_allocated(thread); return; // Stop this thread. } } @@ -2651,8 +2652,8 @@ void CompileBroker::print_times(bool per_compiler, bool aggregate) { int total_bailout_count = CompileBroker::_total_bailout_count; int total_invalidated_count = CompileBroker::_total_invalidated_count; - int nmethods_size = CompileBroker::_sum_nmethod_code_size; - int nmethods_code_size = CompileBroker::_sum_nmethod_size; + int nmethods_code_size = CompileBroker::_sum_nmethod_code_size; + int nmethods_size = CompileBroker::_sum_nmethod_size; tty->cr(); tty->print_cr("Accumulated compiler times"); diff --git a/src/hotspot/share/compiler/compileBroker.hpp b/src/hotspot/share/compiler/compileBroker.hpp index e87c7f35555ba..b7f09259fa8e8 100644 --- a/src/hotspot/share/compiler/compileBroker.hpp +++ b/src/hotspot/share/compiler/compileBroker.hpp @@ -252,6 +252,8 @@ class CompileBroker: AllStatic { static bool wait_for_jvmci_completion(JVMCICompiler* comp, CompileTask* task, JavaThread* thread); #endif + static void free_buffer_blob_if_allocated(CompilerThread* thread); + static void invoke_compiler_on_method(CompileTask* task); static void handle_compile_error(CompilerThread* thread, CompileTask* task, ciEnv* ci_env, int compilable, const char* failure_reason); diff --git a/src/hotspot/share/compiler/compilerDefinitions.cpp b/src/hotspot/share/compiler/compilerDefinitions.cpp index 23af57f3910fd..54bd1cbc7fcdb 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.cpp +++ b/src/hotspot/share/compiler/compilerDefinitions.cpp @@ -497,6 +497,11 @@ bool CompilerConfig::check_args_consistency(bool status) { "Invalid NonNMethodCodeHeapSize=%dK. Must be at least %uK.\n", NonNMethodCodeHeapSize/K, min_code_cache_size/K); status = false; + } else if (InlineCacheBufferSize > NonNMethodCodeHeapSize / 2) { + jio_fprintf(defaultStream::error_stream(), + "Invalid InlineCacheBufferSize=" SIZE_FORMAT "K. Must be less than or equal to " SIZE_FORMAT "K.\n", + InlineCacheBufferSize/K, NonNMethodCodeHeapSize/2/K); + status = false; } #ifdef _LP64 @@ -614,6 +619,7 @@ void CompilerConfig::ergo_initialize() { IncrementalInline = false; IncrementalInlineMH = false; IncrementalInlineVirtual = false; + StressIncrementalInlining = false; } #ifndef PRODUCT if (!IncrementalInline) { diff --git a/src/hotspot/share/compiler/compilerOracle.cpp b/src/hotspot/share/compiler/compilerOracle.cpp index 739c7cc5b9dc1..125a56a113f23 100644 --- a/src/hotspot/share/compiler/compilerOracle.cpp +++ b/src/hotspot/share/compiler/compilerOracle.cpp @@ -1050,21 +1050,10 @@ void CompilerOracle::parse_compile_only(char* line) { } } - if (*line == method_sep) { - if (className == nullptr) { - className = ""; - c_match = MethodMatcher::Any; - } - } else { - // got foo or foo/bar - if (className == nullptr) { - ShouldNotReachHere(); - } else { - // missing class name handled as "Any" class match - if (className[0] == '\0') { - c_match = MethodMatcher::Any; - } - } + if (className == nullptr || className[0] == '\0') { + // missing class name handled as "Any" class match + className = ""; + c_match = MethodMatcher::Any; } // each directive is terminated by , or NUL or . followed by NUL diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index 4e3f08ddc9d21..f39e206673977 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -258,10 +258,13 @@ class G1CardSetHashTable : public CHeapObj { uintx get_hash() const { return G1CardSetHashTable::get_hash(_region_idx); } - bool equals(G1CardSetHashTableValue* value, bool* is_dead) { - *is_dead = false; + bool equals(G1CardSetHashTableValue* value) { return value->_region_idx == _region_idx; } + + bool is_dead(G1CardSetHashTableValue*) { + return false; + } }; class G1CardSetHashTableFound : public StackObj { diff --git a/src/hotspot/share/gc/parallel/psCardTable.cpp b/src/hotspot/share/gc/parallel/psCardTable.cpp index d08ad1572612e..4d63cdb9a3f3a 100644 --- a/src/hotspot/share/gc/parallel/psCardTable.cpp +++ b/src/hotspot/share/gc/parallel/psCardTable.cpp @@ -33,6 +33,7 @@ #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/prefetch.inline.hpp" +#include "utilities/spinYield.hpp" #include "utilities/align.hpp" // Checks an individual oop for missing precise marks. Mark @@ -123,70 +124,184 @@ static void prefetch_write(void *p) { } } -// postcondition: ret is a dirty card or end_card -CardTable::CardValue* PSCardTable::find_first_dirty_card(CardValue* const start_card, - CardValue* const end_card) { - for (CardValue* i_card = start_card; i_card < end_card; ++i_card) { - if (*i_card != PSCardTable::clean_card_val()) { - return i_card; - } +void PSCardTable::scan_obj_with_limit(PSPromotionManager* pm, + oop obj, + HeapWord* start, + HeapWord* end) { + if (!obj->is_typeArray()) { + prefetch_write(start); + pm->push_contents_bounded(obj, start, end); } - return end_card; } -// postcondition: ret is a clean card or end_card -// Note: if a part of an object is on a dirty card, all cards this object -// resides on are considered dirty. -CardTable::CardValue* PSCardTable::find_first_clean_card(ObjectStartArray* const start_array, - CardValue* const start_card, - CardValue* const end_card) { - assert(start_card == end_card || - *start_card != PSCardTable::clean_card_val(), "precondition"); - // Skip the first dirty card. - CardValue* i_card = start_card + 1; - while (i_card < end_card) { - if (*i_card != PSCardTable::clean_card_val()) { - i_card++; - continue; - } - assert(i_card - 1 >= start_card, "inv"); - assert(*(i_card - 1) != PSCardTable::clean_card_val(), "prev card must be dirty"); - // Find the final obj on the prev dirty card. - HeapWord* obj_addr = start_array->object_start(addr_for(i_card)-1); - HeapWord* obj_end_addr = obj_addr + cast_to_oop(obj_addr)->size(); - CardValue* final_card_by_obj = byte_for(obj_end_addr - 1); - assert(final_card_by_obj < end_card, "inv"); - if (final_card_by_obj <= i_card) { - return i_card; +void PSCardTable::pre_scavenge(HeapWord* old_gen_bottom, uint active_workers) { + _preprocessing_active_workers = active_workers; +} + +// The "shadow" table is a copy of the card table entries of the current stripe. +// It is used to separate card reading, clearing and redirtying which reduces +// complexity significantly. +class PSStripeShadowCardTable { + typedef CardTable::CardValue CardValue; + + const uint _card_shift; + const uint _card_size; + CardValue _table[PSCardTable::num_cards_in_stripe]; + const CardValue* _table_base; + +public: + PSStripeShadowCardTable(PSCardTable* pst, HeapWord* const start, HeapWord* const end) : + _card_shift(CardTable::card_shift()), + _card_size(CardTable::card_size()), + _table_base(_table - (uintptr_t(start) >> _card_shift)) { + size_t stripe_byte_size = pointer_delta(end, start) * HeapWordSize; + size_t copy_length = align_up(stripe_byte_size, _card_size) >> _card_shift; + // The end of the last stripe may not be card aligned as it is equal to old + // gen top at scavenge start. We should not clear the card containing old gen + // top if not card aligned because there can be promoted objects on that + // same card. If it was marked dirty because of the promoted objects and we + // cleared it, we would loose a card mark. + size_t clear_length = align_down(stripe_byte_size, _card_size) >> _card_shift; + CardValue* stripe_start_card = pst->byte_for(start); + memcpy(_table, stripe_start_card, copy_length); + memset(stripe_start_card, CardTable::clean_card_val(), clear_length); + } + + HeapWord* addr_for(const CardValue* const card) { + assert(card >= _table && card <= &_table[PSCardTable::num_cards_in_stripe], "out of bounds"); + return (HeapWord*) ((card - _table_base) << _card_shift); + } + + const CardValue* card_for(HeapWord* addr) { + return &_table_base[uintptr_t(addr) >> _card_shift]; + } + + bool is_dirty(const CardValue* const card) { + return !is_clean(card); + } + + bool is_clean(const CardValue* const card) { + assert(card >= _table && card < &_table[PSCardTable::num_cards_in_stripe], "out of bounds"); + return *card == PSCardTable::clean_card_val(); + } + + const CardValue* find_first_dirty_card(const CardValue* const start, + const CardValue* const end) { + for (const CardValue* i = start; i < end; ++i) { + if (is_dirty(i)) { + return i; + } } - // This final obj extends beyond i_card, check if this new card is dirty. - if (*final_card_by_obj == PSCardTable::clean_card_val()) { - return final_card_by_obj; + return end; + } + + const CardValue* find_first_clean_card(const CardValue* const start, + const CardValue* const end) { + for (const CardValue* i = start; i < end; ++i) { + if (is_clean(i)) { + return i; + } } - // This new card is dirty, continuing the search... - i_card = final_card_by_obj + 1; + return end; } - return end_card; -} +}; + +template +void PSCardTable::process_range(Func&& object_start, + PSPromotionManager* pm, + HeapWord* const start, + HeapWord* const end) { + assert(start < end, "precondition"); + assert(is_card_aligned(start), "precondition"); + + PSStripeShadowCardTable sct(this, start, end); + + // end might not be card-aligned. + const CardValue* end_card = sct.card_for(end - 1) + 1; -void PSCardTable::clear_cards(CardValue* const start, CardValue* const end) { - for (CardValue* i_card = start; i_card < end; ++i_card) { - *i_card = clean_card; + for (HeapWord* i_addr = start; i_addr < end; /* empty */) { + const CardValue* dirty_l = sct.find_first_dirty_card(sct.card_for(i_addr), end_card); + const CardValue* dirty_r = sct.find_first_clean_card(dirty_l, end_card); + + assert(dirty_l <= dirty_r, "inv"); + + if (dirty_l == dirty_r) { + assert(dirty_r == end_card, "inv"); + break; + } + + // Located a non-empty dirty chunk [dirty_l, dirty_r). + HeapWord* addr_l = sct.addr_for(dirty_l); + HeapWord* addr_r = MIN2(sct.addr_for(dirty_r), end); + + // Scan objects overlapping [addr_l, addr_r) limited to [start, end). + HeapWord* obj_addr = object_start(addr_l); + + while (true) { + assert(obj_addr < addr_r, "inv"); + + oop obj = cast_to_oop(obj_addr); + const bool is_obj_array = obj->is_objArray(); + HeapWord* const obj_end_addr = obj_addr + obj->size(); + + if (is_obj_array) { + // Always scan obj arrays precisely (they are always marked precisely) + // to avoid unnecessary work. + scan_obj_with_limit(pm, obj, addr_l, addr_r); + } else { + if (obj_addr < i_addr && i_addr > start) { + // Already scanned this object. Has been one that spans multiple dirty chunks. + // The second condition makes sure objects reaching in the stripe are scanned once. + } else { + scan_obj_with_limit(pm, obj, addr_l, end); + } + } + + if (obj_end_addr >= addr_r) { + i_addr = is_obj_array ? addr_r : obj_end_addr; + break; + } + + // Move to next obj inside this dirty chunk. + obj_addr = obj_end_addr; + } + + // Finished a dirty chunk. + pm->drain_stacks_cond_depth(); } } -void PSCardTable::scan_objects_in_range(PSPromotionManager* pm, - HeapWord* start, - HeapWord* end) { - HeapWord* obj_addr = start; - while (obj_addr < end) { - oop obj = cast_to_oop(obj_addr); - assert(oopDesc::is_oop(obj), "inv"); - prefetch_write(obj_addr); - pm->push_contents(obj); - obj_addr += obj->size(); +template +void PSCardTable::preprocess_card_table_parallel(Func&& object_start, + HeapWord* old_gen_bottom, + HeapWord* old_gen_top, + uint stripe_index, + uint n_stripes) { + const size_t num_cards_in_slice = num_cards_in_stripe * n_stripes; + CardValue* cur_card = byte_for(old_gen_bottom) + stripe_index * num_cards_in_stripe; + CardValue* const end_card = byte_for(old_gen_top - 1) + 1; + + for (/* empty */; cur_card < end_card; cur_card += num_cards_in_slice) { + HeapWord* stripe_addr = addr_for(cur_card); + if (is_dirty(cur_card)) { + // The first card of this stripe is already dirty, no need to see if the + // reaching-in object is a potentially imprecisely marked non-array + // object. + continue; + } + HeapWord* first_obj_addr = object_start(stripe_addr); + if (first_obj_addr == stripe_addr) { + // No object reaching into this stripe. + continue; + } + oop first_obj = cast_to_oop(first_obj_addr); + if (!first_obj->is_array() && is_dirty(byte_for(first_obj_addr))) { + // Found a non-array object reaching into the stripe that has + // potentially been marked imprecisely. Mark first card of the stripe + // dirty so it will be processed later. + *cur_card = dirty_card_val(); + } } - pm->drain_stacks_cond_depth(); } // We get passed the space_top value to prevent us from traversing into @@ -227,103 +342,61 @@ void PSCardTable::scan_objects_in_range(PSPromotionManager* pm, // slice_size_in_words to the start of stripe 0 in slice 0 to get to the start // of stripe 0 in slice 1. +// Scavenging and accesses to the card table are strictly limited to the stripe. +// In particular scavenging of an object crossing stripe boundaries is shared +// among the threads assigned to the stripes it resides on. This reduces +// complexity and enables shared scanning of large objects. +// It requires preprocessing of the card table though where imprecise card marks of +// objects crossing stripe boundaries are propagated to the first card of +// each stripe covered by the individual object. + void PSCardTable::scavenge_contents_parallel(ObjectStartArray* start_array, - MutableSpace* sp, - HeapWord* space_top, + HeapWord* old_gen_bottom, + HeapWord* old_gen_top, PSPromotionManager* pm, uint stripe_index, uint n_stripes) { - const size_t num_cards_in_stripe = 128; - const size_t stripe_size_in_words = num_cards_in_stripe * _card_size_in_words; - const size_t slice_size_in_words = stripe_size_in_words * n_stripes; - - HeapWord* cur_stripe_addr = sp->bottom() + stripe_index * stripe_size_in_words; - - for (/* empty */; cur_stripe_addr < space_top; cur_stripe_addr += slice_size_in_words) { - // exclusive - HeapWord* const cur_stripe_end_addr = MIN2(cur_stripe_addr + stripe_size_in_words, - space_top); - - // Process a stripe iff it contains any obj-start - if (!start_array->object_starts_in_range(cur_stripe_addr, cur_stripe_end_addr)) { - continue; + // ObjectStartArray queries can be expensive for large objects. We cache known objects. + struct { + HeapWord* start_addr; + HeapWord* end_addr; + } cached_obj {nullptr, old_gen_bottom}; + + // Queries must be monotonic because we don't check addr >= cached_obj.start_addr. + auto object_start = [&] (HeapWord* addr) { + if (addr < cached_obj.end_addr) { + assert(cached_obj.start_addr != nullptr, "inv"); + return cached_obj.start_addr; } + HeapWord* result = start_array->object_start(addr); - // Constraints: - // 1. range of cards checked for being dirty or clean: [iter_limit_l, iter_limit_r) - // 2. range of cards can be cleared: [clear_limit_l, clear_limit_r) - // 3. range of objs (obj-start) can be scanned: [first_obj_addr, cur_stripe_end_addr) - - CardValue* iter_limit_l; - CardValue* iter_limit_r; - CardValue* clear_limit_l; - CardValue* clear_limit_r; - - // Identify left ends and the first obj-start inside this stripe. - HeapWord* first_obj_addr = start_array->object_start(cur_stripe_addr); - if (first_obj_addr < cur_stripe_addr) { - // this obj belongs to previous stripe; can't clear any cards it occupies - first_obj_addr += cast_to_oop(first_obj_addr)->size(); - clear_limit_l = byte_for(first_obj_addr - 1) + 1; - iter_limit_l = byte_for(first_obj_addr); - } else { - assert(first_obj_addr == cur_stripe_addr, "inv"); - iter_limit_l = clear_limit_l = byte_for(cur_stripe_addr); - } + cached_obj.start_addr = result; + cached_obj.end_addr = result + cast_to_oop(result)->size(); - assert(cur_stripe_addr <= first_obj_addr, "inside this stripe"); - assert(first_obj_addr <= cur_stripe_end_addr, "can be empty"); + return result; + }; - { - // Identify right ends. - HeapWord* obj_addr = start_array->object_start(cur_stripe_end_addr - 1); - HeapWord* obj_end_addr = obj_addr + cast_to_oop(obj_addr)->size(); - assert(obj_end_addr >= cur_stripe_end_addr, "inv"); - clear_limit_r = byte_for(obj_end_addr); - iter_limit_r = byte_for(obj_end_addr - 1) + 1; - } - - assert(iter_limit_l <= clear_limit_l && - clear_limit_r <= iter_limit_r, "clear cards only if we iterate over them"); - - // Process dirty chunks, i.e. consecutive dirty cards [dirty_l, dirty_r), - // chunk by chunk inside [iter_limit_l, iter_limit_r). - CardValue* dirty_l; - CardValue* dirty_r; - - for (CardValue* cur_card = iter_limit_l; cur_card < iter_limit_r; cur_card = dirty_r + 1) { - dirty_l = find_first_dirty_card(cur_card, iter_limit_r); - dirty_r = find_first_clean_card(start_array, dirty_l, iter_limit_r); - assert(dirty_l <= dirty_r, "inv"); - - // empty - if (dirty_l == dirty_r) { - assert(dirty_r == iter_limit_r, "no more dirty cards in this stripe"); - break; - } - - assert(*dirty_l != clean_card, "inv"); - assert(*dirty_r == clean_card || dirty_r >= clear_limit_r, - "clean card or belonging to next stripe"); + // Prepare scavenge. + preprocess_card_table_parallel(object_start, old_gen_bottom, old_gen_top, stripe_index, n_stripes); - // Process this non-empty dirty chunk in two steps: - { - // 1. Clear card in [dirty_l, dirty_r) subject to [clear_limit_l, clear_limit_r) constraint - clear_cards(MAX2(dirty_l, clear_limit_l), - MIN2(dirty_r, clear_limit_r)); - } - - { - // 2. Scan objs in [dirty_l, dirty_r) subject to [first_obj_addr, cur_stripe_end_addr) constraint - HeapWord* obj_l = MAX2(start_array->object_start(addr_for(dirty_l)), - first_obj_addr); + // Sync with other workers. + Atomic::dec(&_preprocessing_active_workers); + SpinYield spin_yield; + while (Atomic::load_acquire(&_preprocessing_active_workers) > 0) { + spin_yield.wait(); + } - HeapWord* obj_r = MIN2(addr_for(dirty_r), - cur_stripe_end_addr); + // Scavenge + cached_obj = {nullptr, old_gen_bottom}; + const size_t stripe_size_in_words = num_cards_in_stripe * _card_size_in_words; + const size_t slice_size_in_words = stripe_size_in_words * n_stripes; + HeapWord* cur_addr = old_gen_bottom + stripe_index * stripe_size_in_words; + for (/* empty */; cur_addr < old_gen_top; cur_addr += slice_size_in_words) { + HeapWord* const stripe_l = cur_addr; + HeapWord* const stripe_r = MIN2(cur_addr + stripe_size_in_words, + old_gen_top); - scan_objects_in_range(pm, obj_l, obj_r); - } - } + process_range(object_start, pm, stripe_l, stripe_r); } } diff --git a/src/hotspot/share/gc/parallel/psCardTable.hpp b/src/hotspot/share/gc/parallel/psCardTable.hpp index 6953c15d37c2f..b0634d5c0b084 100644 --- a/src/hotspot/share/gc/parallel/psCardTable.hpp +++ b/src/hotspot/share/gc/parallel/psCardTable.hpp @@ -33,7 +33,35 @@ class ObjectStartArray; class PSPromotionManager; class PSCardTable: public CardTable { - private: + friend class PSStripeShadowCardTable; + static constexpr size_t num_cards_in_stripe = 128; + static_assert(num_cards_in_stripe >= 1, "progress"); + + volatile int _preprocessing_active_workers; + + bool is_dirty(CardValue* card) { + return !is_clean(card); + } + + bool is_clean(CardValue* card) { + return *card == clean_card_val(); + } + + // Iterate the stripes with the given index and copy imprecise card marks of + // objects reaching into a stripe to its first card. + template + void preprocess_card_table_parallel(Func&& object_start, + HeapWord* old_gen_bottom, + HeapWord* old_gen_top, + uint stripe_index, + uint n_stripes); + + // Scavenge contents on dirty cards of the given stripe [start, end). + template + void process_range(Func&& object_start, + PSPromotionManager* pm, + HeapWord* const start, + HeapWord* const end); void verify_all_young_refs_precise_helper(MemRegion mr); @@ -42,29 +70,24 @@ class PSCardTable: public CardTable { verify_card = CT_MR_BS_last_reserved + 5 }; - CardValue* find_first_dirty_card(CardValue* const start_card, - CardValue* const end_card); - - CardValue* find_first_clean_card(ObjectStartArray* start_array, - CardValue* const start_card, - CardValue* const end_card); - - void clear_cards(CardValue* const start, CardValue* const end); - - void scan_objects_in_range(PSPromotionManager* pm, - HeapWord* start, - HeapWord* end); + void scan_obj_with_limit(PSPromotionManager* pm, + oop obj, + HeapWord* start, + HeapWord* end); public: - PSCardTable(MemRegion whole_heap) : CardTable(whole_heap) {} + PSCardTable(MemRegion whole_heap) : CardTable(whole_heap), + _preprocessing_active_workers(0) {} static CardValue youngergen_card_val() { return youngergen_card; } static CardValue verify_card_val() { return verify_card; } // Scavenge support + void pre_scavenge(HeapWord* old_gen_bottom, uint active_workers); + // Scavenge contents of stripes with the given index. void scavenge_contents_parallel(ObjectStartArray* start_array, - MutableSpace* sp, - HeapWord* space_top, + HeapWord* old_gen_bottom, + HeapWord* old_gen_top, PSPromotionManager* pm, uint stripe_index, uint n_stripes); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.hpp index a1d2b38db31fa..d053ffb6cc949 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.hpp @@ -177,6 +177,7 @@ class PSPromotionManager { TASKQUEUE_STATS_ONLY(inline void record_steal(ScannerTask task);) void push_contents(oop obj); + void push_contents_bounded(oop obj, HeapWord* left, HeapWord* right); }; #endif // SHARE_GC_PARALLEL_PSPROMOTIONMANAGER_HPP diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index f702bc483481c..c1cbeb0f597bb 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -131,6 +131,11 @@ inline void PSPromotionManager::push_contents(oop obj) { } } +inline void PSPromotionManager::push_contents_bounded(oop obj, HeapWord* left, HeapWord* right) { + PSPushContentsClosure pcc(this); + obj->oop_iterate(&pcc, MemRegion(left, right)); +} + template inline oop PSPromotionManager::copy_to_survivor_space(oop o) { assert(should_scavenge(&o), "Sanity"); diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index e148d0cebe86e..6c35ed6b593b8 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -87,7 +87,6 @@ static void scavenge_roots_work(ParallelRootType::Value root_type, uint worker_i assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(worker_id); - PSScavengeRootsClosure roots_closure(pm); PSPromoteRootsClosure roots_to_old_closure(pm); switch (root_type) { @@ -301,6 +300,11 @@ class ScavengeRootsTask : public WorkerTask { _is_old_gen_empty(old_gen->object_space()->is_empty()), _terminator(active_workers, PSPromotionManager::vm_thread_promotion_manager()->stack_array_depth()) { assert(_old_gen != nullptr, "Sanity"); + + if (!_is_old_gen_empty) { + PSCardTable* card_table = ParallelScavengeHeap::heap()->card_table(); + card_table->pre_scavenge(_old_gen->object_space()->bottom(), active_workers); + } } virtual void work(uint worker_id) { @@ -314,8 +318,9 @@ class ScavengeRootsTask : public WorkerTask { PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(worker_id); PSCardTable* card_table = ParallelScavengeHeap::heap()->card_table(); + // The top of the old gen changes during scavenge when objects are promoted. card_table->scavenge_contents_parallel(_old_gen->start_array(), - _old_gen->object_space(), + _old_gen->object_space()->bottom(), _gen_top, pm, worker_id, diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp index 274744d5de256..adf0527681b5e 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp @@ -186,6 +186,14 @@ int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) { // Called upon first entry after being armed bool may_enter = bs_nm->nmethod_entry_barrier(nm); + // In case a concurrent thread disarmed the nmethod, we need to ensure the new instructions + // are made visible, by using a cross modify fence. Note that this is synchronous cross modifying + // code, where the existence of new instructions is communicated via data (the guard value). + // This cross modify fence is only needed when the nmethod entry barrier modifies the + // instructions. Not all platforms currently do that, so if this check becomes expensive, + // it can be made conditional on the nmethod_patching_type. + OrderAccess::cross_modify_fence(); + // Diagnostic option to force deoptimization 1 in 3 times. It is otherwise // a very rare event. if (DeoptimizeNMethodBarriersALot) { @@ -214,6 +222,7 @@ bool BarrierSetNMethod::nmethod_osr_entry_barrier(nmethod* nm) { assert(nm->is_osr_method(), "Should not reach here"); log_trace(nmethod, barrier)("Running osr nmethod entry barrier: " PTR_FORMAT, p2i(nm)); + bool result = nmethod_entry_barrier(nm); OrderAccess::cross_modify_fence(); - return nmethod_entry_barrier(nm); + return result; } diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp index 90fae8c358841..41bd15ab0000f 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp @@ -675,8 +675,15 @@ void BarrierSetC2::clone(GraphKit* kit, Node* src_base, Node* dst_base, Node* si Node* payload_size = size; Node* offset = kit->MakeConX(base_off); payload_size = kit->gvn().transform(new SubXNode(payload_size, offset)); + if (is_array) { + // Ensure the array payload size is rounded up to the next BytesPerLong + // multiple when converting to double-words. This is necessary because array + // size does not include object alignment padding, so it might not be a + // multiple of BytesPerLong for sub-long element types. + payload_size = kit->gvn().transform(new AddXNode(payload_size, kit->MakeConX(BytesPerLong - 1))); + } payload_size = kit->gvn().transform(new URShiftXNode(payload_size, kit->intcon(LogBytesPerLong))); - ArrayCopyNode* ac = ArrayCopyNode::make(kit, false, src_base, offset, dst_base, offset, payload_size, true, false); + ArrayCopyNode* ac = ArrayCopyNode::make(kit, false, src_base, offset, dst_base, offset, payload_size, true, false); if (is_array) { ac->set_clone_array(); } else { diff --git a/src/hotspot/share/gc/shared/memAllocator.cpp b/src/hotspot/share/gc/shared/memAllocator.cpp index e5189abed5740..ed54128d34a1a 100644 --- a/src/hotspot/share/gc/shared/memAllocator.cpp +++ b/src/hotspot/share/gc/shared/memAllocator.cpp @@ -400,15 +400,6 @@ oop ObjAllocator::initialize(HeapWord* mem) const { return finish(mem); } -MemRegion ObjArrayAllocator::obj_memory_range(oop obj) const { - if (_do_zero) { - return MemAllocator::obj_memory_range(obj); - } - ArrayKlass* array_klass = ArrayKlass::cast(_klass); - const size_t hs = arrayOopDesc::header_size(array_klass->element_type()); - return MemRegion(cast_from_oop(obj) + hs, _word_size - hs); -} - oop ObjArrayAllocator::initialize(HeapWord* mem) const { // Set array length before setting the _klass field because a // non-null klass field indicates that the object is parsable by diff --git a/src/hotspot/share/gc/shared/memAllocator.hpp b/src/hotspot/share/gc/shared/memAllocator.hpp index e42399cdffdb4..48faded1337f9 100644 --- a/src/hotspot/share/gc/shared/memAllocator.hpp +++ b/src/hotspot/share/gc/shared/memAllocator.hpp @@ -78,10 +78,6 @@ class MemAllocator: StackObj { // back to calling CollectedHeap::mem_allocate(). HeapWord* mem_allocate(Allocation& allocation) const; - virtual MemRegion obj_memory_range(oop obj) const { - return MemRegion(cast_from_oop(obj), _word_size); - } - public: // Allocate and fully construct the object, and perform various instrumentation. Could safepoint. oop allocate() const; @@ -100,8 +96,6 @@ class ObjArrayAllocator: public MemAllocator { const int _length; const bool _do_zero; - virtual MemRegion obj_memory_range(oop obj) const; - public: ObjArrayAllocator(Klass* klass, size_t word_size, int length, bool do_zero, Thread* thread = Thread::current()) diff --git a/src/hotspot/share/gc/shared/tlab_globals.hpp b/src/hotspot/share/gc/shared/tlab_globals.hpp index 8ecc5283642ba..0b047b4b9e8ac 100644 --- a/src/hotspot/share/gc/shared/tlab_globals.hpp +++ b/src/hotspot/share/gc/shared/tlab_globals.hpp @@ -70,10 +70,13 @@ "Allocation averaging weight") \ range(0, 100) \ \ + /* At GC all TLABs are retired, and each thread's active */ \ + /* TLAB is assumed to be half full on average. The */ \ + /* remaining space is waste, proportional to TLAB size. */ \ + product(uintx, TLABWasteTargetPercent, 1, \ + "Percentage of Eden that can be wasted (half-full TLABs at GC)") \ /* Limit the lower bound of this flag to 1 as it is used */ \ /* in a division expression. */ \ - product(uintx, TLABWasteTargetPercent, 1, \ - "Percentage of Eden that can be wasted") \ range(1, 100) \ \ product(uintx, TLABRefillWasteFraction, 64, \ diff --git a/src/hotspot/share/gc/shared/workerThread.cpp b/src/hotspot/share/gc/shared/workerThread.cpp index b64c5050a2230..49e43c284fad9 100644 --- a/src/hotspot/share/gc/shared/workerThread.cpp +++ b/src/hotspot/share/gc/shared/workerThread.cpp @@ -31,6 +31,7 @@ #include "runtime/init.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" +#include "runtime/safepoint.hpp" WorkerTaskDispatcher::WorkerTaskDispatcher() : _task(nullptr), @@ -141,40 +142,44 @@ void WorkerThreads::threads_do(ThreadClosure* tc) const { } } -void WorkerThreads::set_indirectly_suspendible_threads() { +template +void WorkerThreads::threads_do_f(Function function) const { + for (uint i = 0; i < _created_workers; i++) { + function(_workers[i]); + } +} + +void WorkerThreads::set_indirect_states() { #ifdef ASSERT - class SetIndirectlySuspendibleThreadClosure : public ThreadClosure { - virtual void do_thread(Thread* thread) { + const bool is_suspendible = Thread::current()->is_suspendible_thread(); + const bool is_safepointed = Thread::current()->is_VM_thread() && SafepointSynchronize::is_at_safepoint(); + + threads_do_f([&](Thread* thread) { + assert(!thread->is_indirectly_suspendible_thread(), "Unexpected"); + assert(!thread->is_indirectly_safepoint_thread(), "Unexpected"); + if (is_suspendible) { thread->set_indirectly_suspendible_thread(); } - }; - - if (Thread::current()->is_suspendible_thread()) { - SetIndirectlySuspendibleThreadClosure cl; - threads_do(&cl); - } + if (is_safepointed) { + thread->set_indirectly_safepoint_thread(); + } + }); #endif } -void WorkerThreads::clear_indirectly_suspendible_threads() { +void WorkerThreads::clear_indirect_states() { #ifdef ASSERT - class ClearIndirectlySuspendibleThreadClosure : public ThreadClosure { - virtual void do_thread(Thread* thread) { - thread->clear_indirectly_suspendible_thread(); - } - }; - - if (Thread::current()->is_suspendible_thread()) { - ClearIndirectlySuspendibleThreadClosure cl; - threads_do(&cl); - } + threads_do_f([&](Thread* thread) { + thread->clear_indirectly_suspendible_thread(); + thread->clear_indirectly_safepoint_thread(); + }); #endif } void WorkerThreads::run_task(WorkerTask* task) { - set_indirectly_suspendible_threads(); + set_indirect_states(); _dispatcher.coordinator_distribute_task(task, _active_workers); - clear_indirectly_suspendible_threads(); + clear_indirect_states(); } void WorkerThreads::run_task(WorkerTask* task, uint num_workers) { diff --git a/src/hotspot/share/gc/shared/workerThread.hpp b/src/hotspot/share/gc/shared/workerThread.hpp index d3b246c0930b4..f22e48d7bbc90 100644 --- a/src/hotspot/share/gc/shared/workerThread.hpp +++ b/src/hotspot/share/gc/shared/workerThread.hpp @@ -93,8 +93,8 @@ class WorkerThreads : public CHeapObj { WorkerThread* create_worker(uint name_suffix); - void set_indirectly_suspendible_threads(); - void clear_indirectly_suspendible_threads(); + void set_indirect_states(); + void clear_indirect_states(); protected: virtual void on_create_worker(WorkerThread* worker) {} @@ -111,6 +111,8 @@ class WorkerThreads : public CHeapObj { uint set_active_workers(uint num_workers); void threads_do(ThreadClosure* tc) const; + template + void threads_do_f(Function function) const; const char* name() const { return _name; } diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index 56a91f234359b..ac3afa774e151 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -530,7 +530,7 @@ Node* ShenandoahBarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& Node* ShenandoahBarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) const { // 1: non-reference load, no additional barrier is needed if (!access.is_oop()) { - return BarrierSetC2::load_at_resolved(access, val_type);; + return BarrierSetC2::load_at_resolved(access, val_type); } Node* load = BarrierSetC2::load_at_resolved(access, val_type); diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 71068f76043c9..da75706ac4cfa 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -50,20 +50,18 @@ bool ShenandoahBarrierC2Support::expand(Compile* C, PhaseIterGVN& igvn) { state->load_reference_barriers_count()) > 0) { assert(C->post_loop_opts_phase(), "no loop opts allowed"); C->reset_post_loop_opts_phase(); // ... but we know what we are doing - bool attempt_more_loopopts = ShenandoahLoopOptsAfterExpansion; C->clear_major_progress(); PhaseIdealLoop::optimize(igvn, LoopOptsShenandoahExpand); if (C->failing()) return false; - PhaseIdealLoop::verify(igvn); - if (attempt_more_loopopts) { - C->set_major_progress(); - if (!C->optimize_loops(igvn, LoopOptsShenandoahPostExpand)) { - return false; - } - C->clear_major_progress(); - C->process_for_post_loop_opts_igvn(igvn); + C->set_major_progress(); + if (!C->optimize_loops(igvn, LoopOptsShenandoahPostExpand)) { + return false; } + C->clear_major_progress(); + C->process_for_post_loop_opts_igvn(igvn); + if (C->failing()) return false; + C->set_post_loop_opts_phase(); // now for real! } return true; @@ -1385,11 +1383,9 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { Node* result_mem = nullptr; Node* addr; - if (ShenandoahSelfFixing) { + { VectorSet visited; addr = get_load_addr(phase, visited, lrb); - } else { - addr = phase->igvn().zerocon(T_OBJECT); } if (addr->Opcode() == Op_AddP) { Node* orig_base = addr->in(AddPNode::Base); diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp index 819f1e8d74e24..a8f71c8c5dfc0 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp @@ -354,10 +354,6 @@ bool ShenandoahAllocationRate::is_spiking(double rate, double threshold) const { return false; } -double ShenandoahAllocationRate::instantaneous_rate(size_t allocated) const { - return instantaneous_rate(os::elapsedTime(), allocated); -} - double ShenandoahAllocationRate::instantaneous_rate(double time, size_t allocated) const { size_t last_value = _last_sample_value; double last_time = _last_sample_time; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp index a1a0e6321fafe..17214391383c2 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp @@ -36,7 +36,6 @@ class ShenandoahAllocationRate : public CHeapObj { double sample(size_t allocated); - double instantaneous_rate(size_t allocated) const; double upper_bound(double sds) const; bool is_spiking(double rate, double threshold) const; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp index 4ba3a0315b7c5..be758d14ed1be 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp @@ -37,12 +37,6 @@ ShenandoahAggressiveHeuristics::ShenandoahAggressiveHeuristics() : ShenandoahHeu // Aggressive evacuates everything, so it needs as much evac space as it can get SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahEvacReserveOverflow); - - // If class unloading is globally enabled, aggressive does unloading even with - // concurrent cycles. - if (ClassUnloading) { - SHENANDOAH_ERGO_OVERRIDE_DEFAULT(ShenandoahUnloadClassesFrequency, 1); - } } void ShenandoahAggressiveHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, @@ -62,7 +56,7 @@ bool ShenandoahAggressiveHeuristics::should_start_gc() { } bool ShenandoahAggressiveHeuristics::should_unload_classes() { - if (!can_unload_classes_normal()) return false; + if (!can_unload_classes()) return false; if (has_metaspace_oom()) return true; // Randomly unload classes with 50% chance. return (os::random() & 1) == 1; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp index e571d39f6b3a1..ad924f87b677e 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp @@ -53,11 +53,6 @@ ShenandoahHeuristics::ShenandoahHeuristics() : _gc_time_history(new TruncatedSeq(10, ShenandoahAdaptiveDecayFactor)), _metaspace_oom() { - // No unloading during concurrent mark? Communicate that to heuristics - if (!ClassUnloadingWithConcurrentMark) { - FLAG_SET_DEFAULT(ShenandoahUnloadClassesFrequency, 0); - } - size_t num_regions = ShenandoahHeap::heap()->num_regions(); assert(num_regions > 0, "Sanity"); @@ -262,23 +257,10 @@ bool ShenandoahHeuristics::can_unload_classes() { return true; } -bool ShenandoahHeuristics::can_unload_classes_normal() { - if (!can_unload_classes()) return false; - if (has_metaspace_oom()) return true; - if (!ClassUnloadingWithConcurrentMark) return false; - if (ShenandoahUnloadClassesFrequency == 0) return false; - return true; -} - bool ShenandoahHeuristics::should_unload_classes() { - if (!can_unload_classes_normal()) return false; + if (!can_unload_classes()) return false; if (has_metaspace_oom()) return true; - size_t cycle = ShenandoahHeap::heap()->shenandoah_policy()->cycle_counter(); - // Unload classes every Nth GC cycle. - // This should not happen in the same cycle as process_references to amortize costs. - // Offsetting by one is enough to break the rendezvous when periods are equal. - // When periods are not equal, offsetting by one is just as good as any other guess. - return (cycle + 1) % ShenandoahUnloadClassesFrequency == 0; + return ClassUnloadingWithConcurrentMark; } void ShenandoahHeuristics::initialize() { diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp index 288d306d08962..8efe321692eac 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp @@ -121,7 +121,6 @@ class ShenandoahHeuristics : public CHeapObj { virtual void choose_collection_set(ShenandoahCollectionSet* collection_set); virtual bool can_unload_classes(); - virtual bool can_unload_classes_normal(); virtual bool should_unload_classes(); virtual const char* name() = 0; diff --git a/src/hotspot/share/gc/shenandoah/mode/shenandoahIUMode.cpp b/src/hotspot/share/gc/shenandoah/mode/shenandoahIUMode.cpp index d4fa5a06305d7..d94ade25977b6 100644 --- a/src/hotspot/share/gc/shenandoah/mode/shenandoahIUMode.cpp +++ b/src/hotspot/share/gc/shenandoah/mode/shenandoahIUMode.cpp @@ -59,7 +59,6 @@ void ShenandoahIUMode::initialize_flags() const { SHENANDOAH_CHECK_FLAG_SET(ShenandoahIUBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahNMethodBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahStackWatermarkBarrier); } diff --git a/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp b/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp index 36de17d2d79db..c22c88217e9e7 100644 --- a/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp +++ b/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp @@ -49,7 +49,6 @@ void ShenandoahPassiveMode::initialize_flags() const { SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahIUBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahCASBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahCloneBarrier); - SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahNMethodBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahStackWatermarkBarrier); // Final configuration checks diff --git a/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp b/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp index 5b4e1df49e0df..ff1ff5c2ed343 100644 --- a/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp +++ b/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp @@ -47,7 +47,6 @@ void ShenandoahSATBMode::initialize_flags() const { SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahNMethodBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahStackWatermarkBarrier); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp index 6d4dce4575cf8..d2857daccf6f3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp @@ -45,7 +45,7 @@ ShenandoahBarrierSet::ShenandoahBarrierSet(ShenandoahHeap* heap) : BarrierSet(make_barrier_set_assembler(), make_barrier_set_c1(), make_barrier_set_c2(), - ShenandoahNMethodBarrier ? new ShenandoahBarrierSetNMethod(heap) : nullptr, + new ShenandoahBarrierSetNMethod(heap), new ShenandoahBarrierSetStackChunk(), BarrierSet::FakeRtti(BarrierSet::ShenandoahBarrierSet)), _heap(heap), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp index 413dfe10faad9..b8da50dd6e109 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp @@ -123,7 +123,7 @@ inline oop ShenandoahBarrierSet::load_reference_barrier(DecoratorSet decorators, } oop fwd = load_reference_barrier(obj); - if (ShenandoahSelfFixing && load_addr != nullptr && fwd != obj) { + if (load_addr != nullptr && fwd != obj) { // Since we are here and we know the load address, update the reference. ShenandoahHeap::atomic_update_oop(fwd, load_addr, obj); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp index 1c8daba3d24af..6674c40f76854 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp @@ -220,4 +220,4 @@ void ShenandoahAssertNotForwardedClosure::do_oop(narrowOop* p) { do_oop_work(p); void ShenandoahAssertNotForwardedClosure::do_oop(oop* p) { do_oop_work(p); } #endif -#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_HPP +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_INLINE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp index 932252f9ee18f..92d447258f2a8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp @@ -36,74 +36,24 @@ #include "runtime/atomic.hpp" #include "utilities/powerOfTwo.hpp" -ShenandoahParallelCodeCacheIterator::ShenandoahParallelCodeCacheIterator(const GrowableArray* heaps) { - _length = heaps->length(); - _iters = NEW_C_HEAP_ARRAY(ShenandoahParallelCodeHeapIterator, _length, mtGC); - for (int h = 0; h < _length; h++) { - _iters[h] = ShenandoahParallelCodeHeapIterator(heaps->at(h)); - } -} - -ShenandoahParallelCodeCacheIterator::~ShenandoahParallelCodeCacheIterator() { - FREE_C_HEAP_ARRAY(ParallelCodeHeapIterator, _iters); -} - -void ShenandoahParallelCodeCacheIterator::parallel_blobs_do(CodeBlobClosure* f) { - for (int c = 0; c < _length; c++) { - _iters[c].parallel_blobs_do(f); - } -} - -ShenandoahParallelCodeHeapIterator::ShenandoahParallelCodeHeapIterator(CodeHeap* heap) : - _heap(heap), _claimed_idx(0), _finished(false) { -} - -void ShenandoahParallelCodeHeapIterator::parallel_blobs_do(CodeBlobClosure* f) { - assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint"); - - /* - * Parallel code heap walk. - * - * This code makes all threads scan all code heaps, but only one thread would execute the - * closure on given blob. This is achieved by recording the "claimed" blocks: if a thread - * had claimed the block, it can process all blobs in it. Others have to fast-forward to - * next attempt without processing. - * - * Late threads would return immediately if iterator is finished. - */ - - if (_finished) { - return; - } - int stride = 256; // educated guess - int stride_mask = stride - 1; - assert (is_power_of_2(stride), "sanity"); +ShenandoahNMethodTable* ShenandoahCodeRoots::_nmethod_table; +int ShenandoahCodeRoots::_disarmed_value = 1; - int count = 0; - bool process_block = true; +bool ShenandoahCodeRoots::use_nmethod_barriers_for_mark() { + // Continuations need nmethod barriers for scanning stack chunk nmethods. + if (Continuations::enabled()) return true; - for (CodeBlob *cb = CodeCache::first_blob(_heap); cb != nullptr; cb = CodeCache::next_blob(_heap, cb)) { - int current = count++; - if ((current & stride_mask) == 0) { - process_block = (current >= _claimed_idx) && - (Atomic::cmpxchg(&_claimed_idx, current, current + stride, memory_order_relaxed) == current); - } - if (process_block) { - f->do_code_blob(cb); -#ifdef ASSERT - if (cb->is_nmethod()) - Universe::heap()->verify_nmethod((nmethod*)cb); -#endif - } - } + // Concurrent class unloading needs nmethod barriers. + // When a nmethod is about to be executed, we need to make sure that all its + // metadata are marked. The alternative is to remark thread roots at final mark + // pause, which would cause latency issues. + if (ShenandoahHeap::heap()->unload_classes()) return true; - _finished = true; + // Otherwise, we can go without nmethod barriers. + return false; } -ShenandoahNMethodTable* ShenandoahCodeRoots::_nmethod_table; -int ShenandoahCodeRoots::_disarmed_value = 1; - void ShenandoahCodeRoots::initialize() { _nmethod_table = new ShenandoahNMethodTable(); } @@ -118,8 +68,13 @@ void ShenandoahCodeRoots::unregister_nmethod(nmethod* nm) { _nmethod_table->unregister_nmethod(nm); } -void ShenandoahCodeRoots::arm_nmethods() { - assert(BarrierSet::barrier_set()->barrier_set_nmethod() != nullptr, "Sanity"); +void ShenandoahCodeRoots::arm_nmethods_for_mark() { + if (use_nmethod_barriers_for_mark()) { + BarrierSet::barrier_set()->barrier_set_nmethod()->arm_all_nmethods(); + } +} + +void ShenandoahCodeRoots::arm_nmethods_for_evac() { BarrierSet::barrier_set()->barrier_set_nmethod()->arm_all_nmethods(); } @@ -163,7 +118,7 @@ class ShenandoahDisarmNMethodsTask : public WorkerTask { }; void ShenandoahCodeRoots::disarm_nmethods() { - if (ShenandoahNMethodBarrier) { + if (use_nmethod_barriers_for_mark()) { ShenandoahDisarmNMethodsTask task; ShenandoahHeap::heap()->workers()->run_task(&task); } @@ -284,7 +239,6 @@ void ShenandoahCodeRoots::purge() { } ShenandoahCodeRootsIterator::ShenandoahCodeRootsIterator() : - _par_iterator(CodeCache::heaps()), _table_snapshot(nullptr) { assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint"); MutexLocker locker(CodeCache_lock, Mutex::_no_safepoint_check_flag); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp index 3493d118a9bc6..b8870e71ed06c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp @@ -39,38 +39,9 @@ class ShenandoahNMethodTable; class ShenandoahNMethodTableSnapshot; class WorkerThreads; -class ShenandoahParallelCodeHeapIterator { - friend class CodeCache; -private: - CodeHeap* _heap; - shenandoah_padding(0); - volatile int _claimed_idx; - volatile bool _finished; - shenandoah_padding(1); -public: - ShenandoahParallelCodeHeapIterator(CodeHeap* heap); - void parallel_blobs_do(CodeBlobClosure* f); -}; - -class ShenandoahParallelCodeCacheIterator { - friend class CodeCache; -private: - ShenandoahParallelCodeHeapIterator* _iters; - int _length; - - NONCOPYABLE(ShenandoahParallelCodeCacheIterator); - -public: - ShenandoahParallelCodeCacheIterator(const GrowableArray* heaps); - ~ShenandoahParallelCodeCacheIterator(); - void parallel_blobs_do(CodeBlobClosure* f); -}; - class ShenandoahCodeRootsIterator { friend class ShenandoahCodeRoots; protected: - ShenandoahParallelCodeCacheIterator _par_iterator; - ShenandoahSharedFlag _seq_claimed; ShenandoahNMethodTableSnapshot* _table_snapshot; public: @@ -88,7 +59,6 @@ class ShenandoahCodeRoots : public AllStatic { static void initialize(); static void register_nmethod(nmethod* nm); static void unregister_nmethod(nmethod* nm); - static void flush_nmethod(nmethod* nm); static ShenandoahNMethodTable* table() { return _nmethod_table; @@ -97,11 +67,14 @@ class ShenandoahCodeRoots : public AllStatic { // Concurrent nmethod unloading support static void unlink(WorkerThreads* workers, bool unloading_occurred); static void purge(); - static void arm_nmethods(); + static void arm_nmethods_for_mark(); + static void arm_nmethods_for_evac(); static void disarm_nmethods(); static int disarmed_value() { return _disarmed_value; } static int* disarmed_value_address() { return &_disarmed_value; } + static bool use_nmethod_barriers_for_mark(); + private: static ShenandoahNMethodTable* _nmethod_table; static int _disarmed_value; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.hpp index 6f30f88e57ef1..a6ea6e976ae4d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.hpp @@ -40,7 +40,8 @@ class ShenandoahCollectorPolicy : public CHeapObj { private: size_t _success_concurrent_gcs; size_t _success_degenerated_gcs; - size_t _success_full_gcs; + // Written by control thread, read by mutators + volatile size_t _success_full_gcs; size_t _alloc_failure_degenerated; size_t _alloc_failure_degenerated_upgrade_to_full; size_t _alloc_failure_full; @@ -82,6 +83,10 @@ class ShenandoahCollectorPolicy : public CHeapObj { size_t cycle_counter() const; void print_gc_stats(outputStream* out) const; + + size_t full_gc_count() const { + return _success_full_gcs + _alloc_failure_degenerated_upgrade_to_full; + } }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHCOLLECTORPOLICY_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 375a797cdf897..7564af5f6b7c1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -545,12 +545,9 @@ void ShenandoahConcurrentGC::op_init_mark() { // Make above changes visible to worker threads OrderAccess::fence(); - // Arm nmethods for concurrent marking. When a nmethod is about to be executed, - // we need to make sure that all its metadata are marked. alternative is to remark - // thread roots at final mark pause, but it can be potential latency killer. - if (heap->unload_classes()) { - ShenandoahCodeRoots::arm_nmethods(); - } + + // Arm nmethods for concurrent mark + ShenandoahCodeRoots::arm_nmethods_for_mark(); ShenandoahStackWatermark::change_epoch_id(); if (ShenandoahPacing) { @@ -603,7 +600,7 @@ void ShenandoahConcurrentGC::op_final_mark() { } // Arm nmethods/stack for concurrent processing - ShenandoahCodeRoots::arm_nmethods(); + ShenandoahCodeRoots::arm_nmethods_for_evac(); ShenandoahStackWatermark::change_epoch_id(); if (ShenandoahPacing) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 1fde1944cac62..956cf8cc908f4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -57,8 +57,7 @@ class ShenandoahConcurrentMarkingTask : public WorkerTask { void work(uint worker_id) { ShenandoahHeap* heap = ShenandoahHeap::heap(); ShenandoahConcurrentWorkerSession worker_session(worker_id); - ShenandoahSuspendibleThreadSetJoiner stsj(ShenandoahSuspendibleWorkers); - ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id); + ShenandoahSuspendibleThreadSetJoiner stsj; ShenandoahReferenceProcessor* rp = heap->ref_processor(); assert(rp != nullptr, "need reference processor"); StringDedup::Requests requests; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index 1fcf554429307..e7cf402a52785 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -131,6 +131,27 @@ void ShenandoahDegenGC::op_degenerated() { // and we can do evacuation. Otherwise, it would be the shortcut cycle. if (heap->is_evacuation_in_progress()) { + if (_degen_point == _degenerated_evac) { + // Degeneration under oom-evac protocol allows the mutator LRB to expose + // references to from-space objects. This is okay, in theory, because we + // will come to the safepoint here to complete the evacuations and update + // the references. However, if the from-space reference is written to a + // region that was EC during final mark or was recycled after final mark + // it will not have TAMS or UWM updated. Such a region is effectively + // skipped during update references which can lead to crashes and corruption + // if the from-space reference is accessed. + if (UseTLAB) { + heap->labs_make_parsable(); + } + + for (size_t i = 0; i < heap->num_regions(); i++) { + ShenandoahHeapRegion* r = heap->get_region(i); + if (r->is_active() && r->top() > r->get_update_watermark()) { + r->set_update_watermark_at_safepoint(r->top()); + } + } + } + // Degeneration under oom-evac protocol might have left some objects in // collection set un-evacuated. Restart evacuation from the beginning to // capture all objects. For all the objects that are already evacuated, @@ -181,11 +202,9 @@ void ShenandoahDegenGC::op_degenerated() { assert(!heap->cancelled_gc(), "STW reference update can not OOM"); } - if (ClassUnloading) { - // Disarm nmethods that armed in concurrent cycle. - // In above case, update roots should disarm them - ShenandoahCodeRoots::disarm_nmethods(); - } + // Disarm nmethods that armed in concurrent cycle. + // In above case, update roots should disarm them + ShenandoahCodeRoots::disarm_nmethods(); op_cleanup_complete(); break; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 4589183831281..72a3f411ea09c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -154,7 +154,7 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah HeapWord* result = nullptr; size_t size = req.size(); - if (ShenandoahElasticTLAB && req.is_lab_alloc()) { + if (req.is_lab_alloc()) { size_t free = align_down(r->free() >> LogHeapWordSize, MinObjAlignment); if (size > free) { size = free; @@ -279,7 +279,7 @@ HeapWord* ShenandoahFreeSet::allocate_contiguous(ShenandoahAllocRequest& req) { } end++; - }; + } size_t remainder = words_size & ShenandoahHeapRegion::region_size_words_mask(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index 18fd09ead0ade..4cef5378d30bc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -910,6 +910,9 @@ class ShenandoahPostCompactClosure : public ShenandoahHeapRegionClosure { // Make empty regions that have been allocated into regular if (r->is_empty() && live > 0) { r->make_regular_bypass(); + if (ZapUnusedHeapArea) { + SpaceMangler::mangle_region(MemRegion(r->top(), r->end())); + } } // Reclaim regular regions that became empty diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGC.cpp index fa1938802933b..922f54edf3c0c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGC.cpp @@ -66,7 +66,6 @@ class ShenandoahUpdateRootsTask : public WorkerTask { assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint"); ShenandoahParallelWorkerSession worker_session(worker_id); - ShenandoahHeap* heap = ShenandoahHeap::heap(); ShenandoahUpdateRefsClosure cl; if (_check_alive) { ShenandoahForwardedIsAliveClosure is_alive; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index a2159f71a5ae0..f1dcbf5a8bcfd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -838,25 +838,14 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) { // It might happen that one of the threads requesting allocation would unblock // way later after GC happened, only to fail the second allocation, because // other threads have already depleted the free storage. In this case, a better - // strategy is to try again, as long as GC makes progress. - // - // Then, we need to make sure the allocation was retried after at least one - // Full GC, which means we want to try more than ShenandoahFullGCThreshold times. - - size_t tries = 0; - - while (result == nullptr && _progress_last_gc.is_set()) { - tries++; - control_thread()->handle_alloc_failure(req); - result = allocate_memory_under_lock(req, in_new_region); - } - - while (result == nullptr && tries <= ShenandoahFullGCThreshold) { - tries++; + // strategy is to try again, as long as GC makes progress (or until at least + // one full GC has completed). + size_t original_count = shenandoah_policy()->full_gc_count(); + while (result == nullptr + && (_progress_last_gc.is_set() || original_count == shenandoah_policy()->full_gc_count())) { control_thread()->handle_alloc_failure(req); result = allocate_memory_under_lock(req, in_new_region); } - } else { assert(req.is_gc_alloc(), "Can only accept GC allocs here"); result = allocate_memory_under_lock(req, in_new_region); @@ -974,7 +963,7 @@ class ShenandoahEvacuationTask : public WorkerTask { void work(uint worker_id) { if (_concurrent) { ShenandoahConcurrentWorkerSession worker_session(worker_id); - ShenandoahSuspendibleThreadSetJoiner stsj(ShenandoahSuspendibleWorkers); + ShenandoahSuspendibleThreadSetJoiner stsj; ShenandoahEvacOOMScope oom_evac_scope; do_work(); } else { @@ -1138,13 +1127,9 @@ void ShenandoahHeap::gclabs_retire(bool resize) { // Returns size in bytes size_t ShenandoahHeap::unsafe_max_tlab_alloc(Thread *thread) const { - if (ShenandoahElasticTLAB) { - // With Elastic TLABs, return the max allowed size, and let the allocation path - // figure out the safe size for current allocation. - return ShenandoahHeapRegion::max_tlab_size_bytes(); - } else { - return MIN2(_free_set->unsafe_peek_free(), ShenandoahHeapRegion::max_tlab_size_bytes()); - } + // Return the max allowed size, and let the allocation path + // figure out the safe size for current allocation. + return ShenandoahHeapRegion::max_tlab_size_bytes(); } size_t ShenandoahHeap::max_tlab_size() const { @@ -1864,14 +1849,6 @@ address ShenandoahHeap::in_cset_fast_test_addr() { return (address) heap->collection_set()->biased_map_address(); } -address ShenandoahHeap::cancelled_gc_addr() { - return (address) ShenandoahHeap::heap()->_cancelled_gc.addr_of(); -} - -address ShenandoahHeap::gc_state_addr() { - return (address) ShenandoahHeap::heap()->_gc_state.addr_of(); -} - size_t ShenandoahHeap::bytes_allocated_since_gc_start() { return Atomic::load(&_bytes_allocated_since_gc_start); } @@ -2012,7 +1989,7 @@ class ShenandoahUpdateHeapRefsTask : public WorkerTask { void work(uint worker_id) { if (CONCURRENT) { ShenandoahConcurrentWorkerSession worker_session(worker_id); - ShenandoahSuspendibleThreadSetJoiner stsj(ShenandoahSuspendibleWorkers); + ShenandoahSuspendibleThreadSetJoiner stsj; do_work(); } else { ShenandoahParallelWorkerSession worker_session(worker_id); @@ -2194,15 +2171,11 @@ bool ShenandoahHeap::uncommit_bitmap_slice(ShenandoahHeapRegion *r) { } void ShenandoahHeap::safepoint_synchronize_begin() { - if (ShenandoahSuspendibleWorkers) { - SuspendibleThreadSet::synchronize(); - } + SuspendibleThreadSet::synchronize(); } void ShenandoahHeap::safepoint_synchronize_end() { - if (ShenandoahSuspendibleWorkers) { - SuspendibleThreadSet::desynchronize(); - } + SuspendibleThreadSet::desynchronize(); } void ShenandoahHeap::entry_uncommit(double shrink_before, size_t shrink_until) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index ac1804237d0a9..642faef807e40 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -293,7 +293,6 @@ class ShenandoahHeap : public CollectedHeap { public: char gc_state() const; - static address gc_state_addr(); void set_concurrent_mark_in_progress(bool in_progress); void set_evacuation_in_progress(bool in_progress); @@ -314,7 +313,7 @@ class ShenandoahHeap : public CollectedHeap { inline bool is_full_gc_in_progress() const; inline bool is_full_gc_move_in_progress() const; inline bool has_forwarded_objects() const; - inline bool is_gc_in_progress_mask(uint mask) const; + inline bool is_stw_gc_in_progress() const; inline bool is_concurrent_strong_root_in_progress() const; inline bool is_concurrent_weak_root_in_progress() const; @@ -334,7 +333,6 @@ class ShenandoahHeap : public CollectedHeap { bool try_cancel_gc(); public: - static address cancelled_gc_addr(); inline bool cancelled_gc() const; inline bool check_cancelled_gc_and_yield(bool sts_active = true); @@ -354,7 +352,6 @@ class ShenandoahHeap : public CollectedHeap { void prepare_gc(); void prepare_regions_and_collection_set(bool concurrent); // Evacuation - void prepare_evacuation(bool concurrent); void evacuate_collection_set(bool concurrent); // Concurrent root processing void prepare_concurrent_roots(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index 4158f4bee2293..226190822a158 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -244,7 +244,7 @@ inline bool ShenandoahHeap::cancelled_gc() const { } inline bool ShenandoahHeap::check_cancelled_gc_and_yield(bool sts_active) { - if (sts_active && ShenandoahSuspendibleWorkers && !cancelled_gc()) { + if (sts_active && !cancelled_gc()) { if (SuspendibleThreadSet::should_yield()) { SuspendibleThreadSet::yield(); } @@ -383,10 +383,6 @@ inline bool ShenandoahHeap::is_evacuation_in_progress() const { return _gc_state.is_set(EVACUATION); } -inline bool ShenandoahHeap::is_gc_in_progress_mask(uint mask) const { - return _gc_state.is_set(mask); -} - inline bool ShenandoahHeap::is_degenerated_gc_in_progress() const { return _degenerated_gc_in_progress.is_set(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index 6cac61f848a00..a46c7edc3482a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -607,26 +607,8 @@ size_t ShenandoahHeapRegion::setup_sizes(size_t max_heap_size) { HumongousThresholdBytes = HumongousThresholdWords * HeapWordSize; assert (HumongousThresholdBytes <= RegionSizeBytes, "sanity"); - // The rationale for trimming the TLAB sizes has to do with the raciness in - // TLAB allocation machinery. It may happen that TLAB sizing policy polls Shenandoah - // about next free size, gets the answer for region #N, goes away for a while, then - // tries to allocate in region #N, and fail because some other thread have claimed part - // of the region #N, and then the freeset allocation code has to retire the region #N, - // before moving the allocation to region #N+1. - // - // The worst case realizes when "answer" is "region size", which means it could - // prematurely retire an entire region. Having smaller TLABs does not fix that - // completely, but reduces the probability of too wasteful region retirement. - // With current divisor, we will waste no more than 1/8 of region size in the worst - // case. This also has a secondary effect on collection set selection: even under - // the race, the regions would be at least 7/8 used, which allows relying on - // "used" - "live" for cset selection. Otherwise, we can get the fragmented region - // below the garbage threshold that would never be considered for collection. - // - // The whole thing is mitigated if Elastic TLABs are enabled. - // guarantee(MaxTLABSizeWords == 0, "we should only set it once"); - MaxTLABSizeWords = MIN2(ShenandoahElasticTLAB ? RegionSizeWords : (RegionSizeWords / 8), HumongousThresholdWords); + MaxTLABSizeWords = MIN2(RegionSizeWords, HumongousThresholdWords); MaxTLABSizeWords = align_down(MaxTLABSizeWords, MinObjAlignment); guarantee(MaxTLABSizeBytes == 0, "we should only set it once"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.hpp b/src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.hpp index 2ce1cd0b95faf..1553787265ce1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.hpp @@ -38,4 +38,4 @@ class ShenandoahJFRSupport { static void register_jfr_type_serializers(); }; -#endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHJFRSUPPORT_HPP +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHJFRSUPPORT_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index ffae4f068bc4b..4725b8c3dfae7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -185,7 +185,7 @@ void ShenandoahMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint w if (work == 0) { // No work encountered in current stride, try to terminate. // Need to leave the STS here otherwise it might block safepoints. - ShenandoahSuspendibleThreadSetLeaver stsl(CANCELLABLE && ShenandoahSuspendibleWorkers); + ShenandoahSuspendibleThreadSetLeaver stsl(CANCELLABLE); ShenandoahTerminatorTerminator tt(heap); if (terminator->offer_termination(&tt)) return; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp index 9130207ba9932..078b89a4ce72c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp @@ -30,14 +30,10 @@ #include "gc/shenandoah/shenandoahOopClosures.hpp" #include "gc/shenandoah/shenandoahTaskqueue.hpp" -class ShenandoahCMDrainMarkingStackClosure; - // Base class for mark // Mark class does not maintain states. Instead, mark states are // maintained by task queues, mark bitmap and SATB buffers (concurrent mark) class ShenandoahMark: public StackObj { - friend class ShenandoahCMDrainMarkingStackClosure; - protected: ShenandoahObjToScanQueueSet* const _task_queues; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp index 74aafeb3831b9..980050b8b00f8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp @@ -52,39 +52,6 @@ ShenandoahNMethod::~ShenandoahNMethod() { } } -class ShenandoahHasCSetOopClosure : public OopClosure { -private: - ShenandoahHeap* const _heap; - bool _has_cset_oops; - -public: - ShenandoahHasCSetOopClosure(ShenandoahHeap *heap) : - _heap(heap), - _has_cset_oops(false) { - } - - bool has_cset_oops() const { - return _has_cset_oops; - } - - void do_oop(oop* p) { - oop value = RawAccess<>::oop_load(p); - if (!_has_cset_oops && _heap->in_collection_set(value)) { - _has_cset_oops = true; - } - } - - void do_oop(narrowOop* p) { - ShouldNotReachHere(); - } -}; - -bool ShenandoahNMethod::has_cset_oops(ShenandoahHeap *heap) { - ShenandoahHasCSetOopClosure cl(heap); - oops_do(&cl); - return cl.has_cset_oops(); -} - void ShenandoahNMethod::update() { ResourceMark rm; bool non_immediate_oops = false; @@ -209,10 +176,6 @@ class ShenandoahNMethodOopDetector : public OopClosure { GrowableArray* oops() { return &_oops; } - - bool has_oops() { - return !_oops.is_empty(); - } }; void ShenandoahNMethod::assert_same_oops(bool allow_dead) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp index 4fc90b03bedc9..6a856e684031b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp @@ -55,12 +55,6 @@ class ShenandoahNMethod : public CHeapObj { // Update oops when the nmethod is re-registered void update(); - bool has_cset_oops(ShenandoahHeap* heap); - - inline int oop_count() const; - inline bool has_oops() const; - - inline void mark_unregistered(); inline bool is_unregistered() const; static ShenandoahNMethod* for_nmethod(nmethod* nm); @@ -77,7 +71,6 @@ class ShenandoahNMethod : public CHeapObj { void assert_same_oops(bool allow_dead = false) NOT_DEBUG_RETURN; private: - bool has_non_immed_oops() const { return _has_non_immed_oops; } static void detect_reloc_oops(nmethod* nm, GrowableArray& oops, bool& _has_non_immed_oops); }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.inline.hpp index eb9659219a24e..df721c0a695fc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.inline.hpp @@ -39,18 +39,6 @@ ShenandoahReentrantLock* ShenandoahNMethod::lock() { return &_lock; } -int ShenandoahNMethod::oop_count() const { - return _oops_count + static_cast(nm()->oops_end() - nm()->oops_begin()); -} - -bool ShenandoahNMethod::has_oops() const { - return oop_count() > 0; -} - -void ShenandoahNMethod::mark_unregistered() { - _unregistered = true; -} - bool ShenandoahNMethod::is_unregistered() const { return _unregistered; } @@ -80,9 +68,7 @@ void ShenandoahNMethod::heal_nmethod_metadata(ShenandoahNMethod* nmethod_data) { void ShenandoahNMethod::disarm_nmethod(nmethod* nm) { BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod(); - assert(bs != nullptr || !ShenandoahNMethodBarrier, - "Must have nmethod barrier for concurrent GC"); - if (bs != nullptr && bs->is_armed(nm)) { + if (bs->is_armed(nm)) { bs->disarm(nm); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp index caa5416cd2295..0bd92da1b5d10 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp @@ -362,7 +362,7 @@ bool ShenandoahReferenceProcessor::discover_reference(oop reference, ReferenceTy log_trace(gc, ref)("Encountered Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type)); uint worker_id = WorkerThread::worker_id(); - _ref_proc_thread_locals->inc_encountered(type); + _ref_proc_thread_locals[worker_id].inc_encountered(type); if (UseCompressedOops) { return discover(reference, type, worker_id); @@ -402,7 +402,7 @@ T* ShenandoahReferenceProcessor::keep(oop reference, ReferenceType type, uint wo } template -void ShenandoahReferenceProcessor::process_references(ShenandoahRefProcThreadLocal& refproc_data, uint worker_id) {; +void ShenandoahReferenceProcessor::process_references(ShenandoahRefProcThreadLocal& refproc_data, uint worker_id) { log_trace(gc, ref)("Processing discovered list #%u : " PTR_FORMAT, worker_id, p2i(refproc_data.discovered_list_head())); T* list = refproc_data.discovered_list_addr(); // The list head is basically a GC root, we need to resolve and update it, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp index 586835d35ad02..639b35deca375 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp @@ -89,7 +89,6 @@ void ShenandoahCodeCacheRoots::code_blobs_do(CodeBlobClosure* blob_cl, uint work ShenandoahRootProcessor::ShenandoahRootProcessor(ShenandoahPhaseTimings::Phase phase) : _heap(ShenandoahHeap::heap()), - _phase(phase), _worker_phase(phase) { } @@ -206,7 +205,7 @@ ShenandoahRootAdjuster::ShenandoahRootAdjuster(uint n_workers, ShenandoahPhaseTi void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) { CodeBlobToOopClosure code_blob_cl(oops, CodeBlobToOopClosure::FixRelocations); ShenandoahCodeBlobAndDisarmClosure blobs_and_disarm_Cl(oops); - CodeBlobToOopClosure* adjust_code_closure = (ClassUnloading && ShenandoahNMethodBarrier) ? + CodeBlobToOopClosure* adjust_code_closure = ShenandoahCodeRoots::use_nmethod_barriers_for_mark() ? static_cast(&blobs_and_disarm_Cl) : static_cast(&code_blob_cl); CLDToOopClosure adjust_cld_closure(oops, ClassLoaderData::_claim_strong); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp index 75a23aea04534..fcb28dfbce016 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp @@ -134,7 +134,6 @@ class ShenandoahClassLoaderDataRoots { class ShenandoahRootProcessor : public StackObj { private: ShenandoahHeap* const _heap; - const ShenandoahPhaseTimings::Phase _phase; const ShenandoahGCWorkerPhase _worker_phase; public: ShenandoahRootProcessor(ShenandoahPhaseTimings::Phase phase); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp index 8bbc742a556b4..3872a5a391c32 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp @@ -172,7 +172,7 @@ template void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAlive* keep_alive) { CodeBlobToOopClosure update_blobs(keep_alive, CodeBlobToOopClosure::FixRelocations); ShenandoahCodeBlobAndDisarmClosure blobs_and_disarm_Cl(keep_alive); - CodeBlobToOopClosure* codes_cl = (ClassUnloading && ShenandoahNMethodBarrier) ? + CodeBlobToOopClosure* codes_cl = ShenandoahCodeRoots::use_nmethod_barriers_for_mark() ? static_cast(&blobs_and_disarm_Cl) : static_cast(&update_blobs); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 7cc8af7361f2d..1462bc052dc5b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -89,8 +89,13 @@ ShenandoahSTWMark::ShenandoahSTWMark(bool full_gc) : } void ShenandoahSTWMark::mark() { - // Weak reference processing ShenandoahHeap* const heap = ShenandoahHeap::heap(); + + // Arm all nmethods. Even though this is STW mark, some marking code + // piggybacks on nmethod barriers for special instances. + ShenandoahCodeRoots::arm_nmethods_for_mark(); + + // Weak reference processing ShenandoahReferenceProcessor* rp = heap->ref_processor(); rp->reset_thread_locals(); rp->set_soft_reference_policy(heap->soft_ref_policy()->should_clear_all_soft_refs()); @@ -120,6 +125,9 @@ void ShenandoahSTWMark::mark() { heap->mark_complete_marking_context(); end_mark(); + // Mark is finished, can disarm the nmethods now. + ShenandoahCodeRoots::disarm_nmethods(); + assert(task_queues()->is_empty(), "Should be empty"); TASKQUEUE_STATS_ONLY(task_queues()->print_taskqueue_stats()); TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats()); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp index d6be092055820..4a97e599f3e5b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp @@ -32,6 +32,7 @@ #include "gc/shenandoah/shenandoahOopClosures.inline.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahVMOperations.hpp" +#include "interpreter/oopMapCache.hpp" #include "memory/universe.hpp" bool VM_ShenandoahReferenceOperation::doit_prologue() { @@ -40,6 +41,7 @@ bool VM_ShenandoahReferenceOperation::doit_prologue() { } void VM_ShenandoahReferenceOperation::doit_epilogue() { + OopMapCache::cleanup_old_entries(); if (Universe::has_reference_pending_list()) { Heap_lock->notify_all(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index 88c460b5f19bc..14212d48b099f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -76,11 +76,6 @@ " compact - run GC more frequently and with deeper targets to " \ "free up more memory.") \ \ - product(uintx, ShenandoahUnloadClassesFrequency, 1, EXPERIMENTAL, \ - "Unload the classes every Nth cycle. Normally affects concurrent "\ - "GC cycles, as degenerated and full GCs would try to unload " \ - "classes regardless. Set to zero to disable class unloading.") \ - \ product(uintx, ShenandoahGarbageThreshold, 25, EXPERIMENTAL, \ "How much garbage a region has to contain before it would be " \ "taken for collection. This a guideline only, as GC heuristics " \ @@ -220,9 +215,6 @@ " 3 = previous level, plus all reachable objects; " \ " 4 = previous level, plus all marked objects") \ \ - product(bool, ShenandoahElasticTLAB, true, DIAGNOSTIC, \ - "Use Elastic TLABs with Shenandoah") \ - \ product(uintx, ShenandoahEvacReserve, 5, EXPERIMENTAL, \ "How much of heap to reserve for evacuations. Larger values make "\ "GC evacuate more live objects on every cycle, while leaving " \ @@ -334,9 +326,6 @@ "How many times to maximum attempt to flush SATB buffers at the " \ "end of concurrent marking.") \ \ - product(bool, ShenandoahSuspendibleWorkers, true, EXPERIMENTAL, \ - "Suspend concurrent GC worker threads at safepoints") \ - \ product(bool, ShenandoahSATBBarrier, true, DIAGNOSTIC, \ "Turn on/off SATB barriers in Shenandoah") \ \ @@ -352,21 +341,12 @@ product(bool, ShenandoahLoadRefBarrier, true, DIAGNOSTIC, \ "Turn on/off load-reference barriers in Shenandoah") \ \ - product(bool, ShenandoahNMethodBarrier, true, DIAGNOSTIC, \ - "Turn on/off NMethod entry barriers in Shenandoah") \ - \ product(bool, ShenandoahStackWatermarkBarrier, true, DIAGNOSTIC, \ "Turn on/off stack watermark barriers in Shenandoah") \ \ - develop(bool, ShenandoahVerifyOptoBarriers, false, \ + develop(bool, ShenandoahVerifyOptoBarriers, trueInDebug, \ "Verify no missing barriers in C2.") \ \ - product(bool, ShenandoahLoopOptsAfterExpansion, true, DIAGNOSTIC, \ - "Attempt more loop opts after barrier expansion.") \ - \ - product(bool, ShenandoahSelfFixing, true, DIAGNOSTIC, \ - "Fix references with load reference barrier. Disabling this " \ - "might degrade performance.") // end of GC_SHENANDOAH_FLAGS diff --git a/src/hotspot/share/gc/x/xArguments.cpp b/src/hotspot/share/gc/x/xArguments.cpp index 8c02c80024773..60e78d2c756ed 100644 --- a/src/hotspot/share/gc/x/xArguments.cpp +++ b/src/hotspot/share/gc/x/xArguments.cpp @@ -37,6 +37,10 @@ void XArguments::initialize_alignments() { HeapAlignment = SpaceAlignment; } +void XArguments::initialize_heap_flags_and_sizes() { + // Nothing extra to do +} + void XArguments::initialize() { // Check mark stack size const size_t mark_stack_space_limit = XAddressSpaceLimit::mark_stack(); diff --git a/src/hotspot/share/gc/x/xArguments.hpp b/src/hotspot/share/gc/x/xArguments.hpp index aaa586a2df2f1..196dd994cad9b 100644 --- a/src/hotspot/share/gc/x/xArguments.hpp +++ b/src/hotspot/share/gc/x/xArguments.hpp @@ -31,6 +31,7 @@ class CollectedHeap; class XArguments : AllStatic { public: static void initialize_alignments(); + static void initialize_heap_flags_and_sizes(); static void initialize(); static size_t heap_virtual_to_physical_ratio(); static CollectedHeap* create_heap(); diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp index e5fb50a26e4fb..70b9bd6eaa7de 100644 --- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp +++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp @@ -42,6 +42,7 @@ #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/type.hpp" +#include "utilities/debug.hpp" #include "utilities/growableArray.hpp" #include "utilities/macros.hpp" @@ -226,6 +227,7 @@ Label* ZBarrierStubC2::continuation() { } ZLoadBarrierStubC2* ZLoadBarrierStubC2::create(const MachNode* node, Address ref_addr, Register ref) { + AARCH64_ONLY(fatal("Should use ZLoadBarrierStubC2Aarch64::create")); ZLoadBarrierStubC2* const stub = new (Compile::current()->comp_arena()) ZLoadBarrierStubC2(node, ref_addr, ref); register_stub(stub); @@ -275,6 +277,7 @@ void ZLoadBarrierStubC2::emit_code(MacroAssembler& masm) { } ZStoreBarrierStubC2* ZStoreBarrierStubC2::create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic) { + AARCH64_ONLY(fatal("Should use ZStoreBarrierStubC2Aarch64::create")); ZStoreBarrierStubC2* const stub = new (Compile::current()->comp_arena()) ZStoreBarrierStubC2(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic); register_stub(stub); diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp index a0f29fbc51076..7af70c6409678 100644 --- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp +++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp @@ -52,9 +52,9 @@ static void inc_trampoline_stubs_count(); static int trampoline_stubs_count(); static int stubs_start_offset(); -public: ZBarrierStubC2(const MachNode* node); +public: RegMask& live() const; Label* entry(); Label* continuation(); diff --git a/src/hotspot/share/gc/z/shared/zSharedArguments.cpp b/src/hotspot/share/gc/z/shared/zSharedArguments.cpp index 8a00a851acb08..4d7e9827f18a0 100644 --- a/src/hotspot/share/gc/z/shared/zSharedArguments.cpp +++ b/src/hotspot/share/gc/z/shared/zSharedArguments.cpp @@ -38,6 +38,16 @@ void ZSharedArguments::initialize_alignments() { } } +void ZSharedArguments::initialize_heap_flags_and_sizes() { + GCArguments::initialize_heap_flags_and_sizes(); + + if (ZGenerational) { + ZArguments::initialize_heap_flags_and_sizes(); + } else { + XArguments::initialize_heap_flags_and_sizes(); + } +} + void ZSharedArguments::initialize() { GCArguments::initialize(); diff --git a/src/hotspot/share/gc/z/shared/zSharedArguments.hpp b/src/hotspot/share/gc/z/shared/zSharedArguments.hpp index 74659f581b918..c53f28ee0f97c 100644 --- a/src/hotspot/share/gc/z/shared/zSharedArguments.hpp +++ b/src/hotspot/share/gc/z/shared/zSharedArguments.hpp @@ -31,6 +31,7 @@ class CollectedHeap; class ZSharedArguments : public GCArguments { private: virtual void initialize_alignments(); + virtual void initialize_heap_flags_and_sizes(); virtual void initialize(); virtual size_t conservative_max_heap_alignment(); diff --git a/src/hotspot/share/gc/z/zArguments.cpp b/src/hotspot/share/gc/z/zArguments.cpp index 01ecf8f3fc4b8..192cad86e67d3 100644 --- a/src/hotspot/share/gc/z/zArguments.cpp +++ b/src/hotspot/share/gc/z/zArguments.cpp @@ -37,6 +37,19 @@ void ZArguments::initialize_alignments() { HeapAlignment = SpaceAlignment; } +void ZArguments::initialize_heap_flags_and_sizes() { + if (!FLAG_IS_CMDLINE(MaxHeapSize) && + !FLAG_IS_CMDLINE(MaxRAMFraction) && + !FLAG_IS_CMDLINE(MaxRAMPercentage) && + !FLAG_IS_CMDLINE(SoftMaxHeapSize)) { + // We are really just guessing how much memory the program needs. + // When that is the case, we don't want the soft and hard limits to be the same + // as it can cause flakyness in the number of GC threads used, in order to keep + // to a random number we just pulled out of thin air. + FLAG_SET_ERGO(SoftMaxHeapSize, MaxHeapSize * 90 / 100); + } +} + void ZArguments::select_max_gc_threads() { // Select number of parallel threads if (FLAG_IS_DEFAULT(ParallelGCThreads)) { @@ -126,20 +139,13 @@ void ZArguments::initialize() { FLAG_SET_ERGO_IF_DEFAULT(ZCollectionIntervalMajor, ZCollectionInterval); } - if (!FLAG_IS_CMDLINE(MaxHeapSize) && - !FLAG_IS_CMDLINE(MaxRAMFraction) && - !FLAG_IS_CMDLINE(MaxRAMPercentage)) { - // We are really just guessing how much memory the program needs. - // When that is the case, we don't want the soft and hard limits to be the same - // as it can cause flakyness in the number of GC threads used, in order to keep - // to a random number we just pulled out of thin air. - FLAG_SET_ERGO_IF_DEFAULT(SoftMaxHeapSize, MaxHeapSize * 90 / 100); - } - if (FLAG_IS_DEFAULT(ZFragmentationLimit)) { FLAG_SET_DEFAULT(ZFragmentationLimit, 5.0); } + // Set medium page size here because MaxTenuringThreshold may use it. + ZHeuristics::set_medium_page_size(); + if (!FLAG_IS_DEFAULT(ZTenuringThreshold) && ZTenuringThreshold != -1) { FLAG_SET_ERGO_IF_DEFAULT(MaxTenuringThreshold, ZTenuringThreshold); if (MaxTenuringThreshold == 0) { diff --git a/src/hotspot/share/gc/z/zArguments.hpp b/src/hotspot/share/gc/z/zArguments.hpp index ac1e613d4ccbb..7d1c00d30d1cc 100644 --- a/src/hotspot/share/gc/z/zArguments.hpp +++ b/src/hotspot/share/gc/z/zArguments.hpp @@ -34,6 +34,7 @@ class ZArguments : AllStatic { public: static void initialize_alignments(); + static void initialize_heap_flags_and_sizes(); static void initialize(); static size_t heap_virtual_to_physical_ratio(); static CollectedHeap* create_heap(); diff --git a/src/hotspot/share/gc/z/zBarrier.inline.hpp b/src/hotspot/share/gc/z/zBarrier.inline.hpp index e0d83619934da..2c81c14865b51 100644 --- a/src/hotspot/share/gc/z/zBarrier.inline.hpp +++ b/src/hotspot/share/gc/z/zBarrier.inline.hpp @@ -26,14 +26,13 @@ #include "gc/z/zBarrier.hpp" -#include "code/codeCache.hpp" #include "gc/z/zAddress.inline.hpp" #include "gc/z/zGeneration.inline.hpp" #include "gc/z/zHeap.inline.hpp" #include "gc/z/zResurrection.inline.hpp" +#include "gc/z/zVerify.hpp" #include "oops/oop.hpp" #include "runtime/atomic.hpp" -#include "runtime/continuation.hpp" // A self heal must always "upgrade" the address metadata bits in // accordance with the metadata bits state machine. The following @@ -320,17 +319,9 @@ inline zaddress ZBarrier::make_load_good_no_relocate(zpointer o) { return remap(ZPointer::uncolor_unsafe(o), remap_generation(o)); } -inline void z_assert_is_barrier_safe() { - assert(!Thread::current()->is_ConcurrentGC_thread() || /* Need extra checks for ConcurrentGCThreads */ - Thread::current()->is_suspendible_thread() || /* Thread prevents safepoints */ - Thread::current()->is_indirectly_suspendible_thread() || /* Coordinator thread prevents safepoints */ - SafepointSynchronize::is_at_safepoint(), /* Is at safepoint */ - "Shouldn't perform load barrier"); -} - template inline zaddress ZBarrier::barrier(ZBarrierFastPath fast_path, ZBarrierSlowPath slow_path, ZBarrierColor color, volatile zpointer* p, zpointer o, bool allow_null) { - z_assert_is_barrier_safe(); + z_verify_safepoints_are_blocked(); // Fast path if (fast_path(o)) { diff --git a/src/hotspot/share/gc/z/zBarrierSet.cpp b/src/hotspot/share/gc/z/zBarrierSet.cpp index 160673e8059bf..48228a3e1abc3 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.cpp +++ b/src/hotspot/share/gc/z/zBarrierSet.cpp @@ -152,6 +152,20 @@ void ZBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) { deoptimize_allocation(thread); } +void ZBarrierSet::clone_obj_array(objArrayOop src_obj, objArrayOop dst_obj) { + volatile zpointer* src = (volatile zpointer*)src_obj->base(); + volatile zpointer* dst = (volatile zpointer*)dst_obj->base(); + const int length = src_obj->length(); + + for (const volatile zpointer* const end = src + length; src < end; src++, dst++) { + zaddress elem = ZBarrier::load_barrier_on_oop_field(src); + // We avoid healing here because the store below colors the pointer store good, + // hence avoiding the cost of a CAS. + ZBarrier::store_barrier_on_heap_oop_field(dst, false /* heal */); + Atomic::store(dst, ZAddress::store_good(elem)); + } +} + void ZBarrierSet::print_on(outputStream* st) const { st->print_cr("ZBarrierSet"); } diff --git a/src/hotspot/share/gc/z/zBarrierSet.hpp b/src/hotspot/share/gc/z/zBarrierSet.hpp index 213f85dcea8c7..bf233df683afb 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.hpp +++ b/src/hotspot/share/gc/z/zBarrierSet.hpp @@ -39,6 +39,8 @@ class ZBarrierSet : public BarrierSet { static ZBarrierSetAssembler* assembler(); static bool barrier_needed(DecoratorSet decorators, BasicType type); + static void clone_obj_array(objArrayOop src, objArrayOop dst); + virtual void on_thread_create(Thread* thread); virtual void on_thread_destroy(Thread* thread); virtual void on_thread_attach(Thread* thread); diff --git a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp index bfbae74972d80..d53b69345dd98 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp @@ -403,14 +403,13 @@ inline bool ZBarrierSet::AccessBarrier::oop_arraycopy_i return oop_arraycopy_in_heap_no_check_cast(dst, src, length); } -class ZStoreBarrierOopClosure : public BasicOopIterateClosure { +class ZColorStoreGoodOopClosure : public BasicOopIterateClosure { public: virtual void do_oop(oop* p_) { volatile zpointer* const p = (volatile zpointer*)p_; const zpointer ptr = ZBarrier::load_atomic(p); const zaddress addr = ZPointer::uncolor(ptr); - ZBarrier::store_barrier_on_heap_oop_field(p, false /* heal */); - *p = ZAddress::store_good(addr); + Atomic::store(p, ZAddress::store_good(addr)); } virtual void do_oop(narrowOop* p) { @@ -433,6 +432,17 @@ template inline void ZBarrierSet::AccessBarrier::clone_in_heap(oop src, oop dst, size_t size) { assert_is_valid(to_zaddress(src)); + if (dst->is_objArray()) { + // Cloning an object array is similar to performing array copy. + // If an array is large enough to have its allocation segmented, + // this operation might require GC barriers. However, the intrinsics + // for cloning arrays transform the clone to an optimized allocation + // and arraycopy sequence, so the performance of this runtime call + // does not matter for object arrays. + clone_obj_array(objArrayOop(src), objArrayOop(dst)); + return; + } + // Fix the oops ZLoadBarrierOopClosure cl; ZIterator::oop_iterate(src, &cl); @@ -440,10 +450,10 @@ inline void ZBarrierSet::AccessBarrier::clone_in_heap(o // Clone the object Raw::clone_in_heap(src, dst, size); - assert(ZHeap::heap()->is_young(to_zaddress(dst)), "ZColorStoreGoodOopClosure is only valid for young objects"); + assert(dst->is_typeArray() || ZHeap::heap()->is_young(to_zaddress(dst)), "ZColorStoreGoodOopClosure is only valid for young objects"); // Color store good before handing out - ZStoreBarrierOopClosure cl_sg; + ZColorStoreGoodOopClosure cl_sg; ZIterator::oop_iterate(dst, &cl_sg); } diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 0ee5ce7a6c89e..1b4afd4eefbe4 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -285,6 +285,10 @@ void ZGeneration::desynchronize_relocation() { _relocate.desynchronize(); } +bool ZGeneration::is_relocate_queue_active() const { + return _relocate.is_queue_active(); +} + void ZGeneration::reset_statistics() { assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); _freed = 0; @@ -1492,7 +1496,7 @@ void ZGenerationOld::remap_young_roots() { uint remap_nworkers = clamp(ZGeneration::young()->workers()->active_workers() + prev_nworkers, 1u, ZOldGCThreads); _workers.set_active_workers(remap_nworkers); - // TODO: The STS joiner is only needed to satisfy z_assert_is_barrier_safe that doesn't + // TODO: The STS joiner is only needed to satisfy ZBarrier::assert_is_state_barrier_safe that doesn't // understand the driver locker. Consider making the assert aware of the driver locker. SuspendibleThreadSetJoiner sts_joiner; diff --git a/src/hotspot/share/gc/z/zGeneration.hpp b/src/hotspot/share/gc/z/zGeneration.hpp index 23736f45b7be7..32762a50b6278 100644 --- a/src/hotspot/share/gc/z/zGeneration.hpp +++ b/src/hotspot/share/gc/z/zGeneration.hpp @@ -166,6 +166,7 @@ class ZGeneration { // Relocation void synchronize_relocation(); void desynchronize_relocation(); + bool is_relocate_queue_active() const; zaddress relocate_or_remap_object(zaddress_unsafe addr); zaddress remap_object(zaddress_unsafe addr); diff --git a/src/hotspot/share/gc/z/zHeuristics.cpp b/src/hotspot/share/gc/z/zHeuristics.cpp index bcd9dd844052b..36ca1177c326a 100644 --- a/src/hotspot/share/gc/z/zHeuristics.cpp +++ b/src/hotspot/share/gc/z/zHeuristics.cpp @@ -101,9 +101,9 @@ uint ZHeuristics::nconcurrent_workers() { } size_t ZHeuristics::significant_heap_overhead() { - return MaxHeapSize * ZFragmentationLimit; + return MaxHeapSize * (ZFragmentationLimit / 100); } size_t ZHeuristics::significant_young_overhead() { - return MaxHeapSize * ZYoungCompactionLimit; + return MaxHeapSize * (ZYoungCompactionLimit / 100); } diff --git a/src/hotspot/share/gc/z/zInitialize.cpp b/src/hotspot/share/gc/z/zInitialize.cpp index 0c0dc6e87a6c4..bf8cb96a4cbd6 100644 --- a/src/hotspot/share/gc/z/zInitialize.cpp +++ b/src/hotspot/share/gc/z/zInitialize.cpp @@ -28,7 +28,6 @@ #include "gc/z/zDriver.hpp" #include "gc/z/zGCIdPrinter.hpp" #include "gc/z/zGlobals.hpp" -#include "gc/z/zHeuristics.hpp" #include "gc/z/zInitialize.hpp" #include "gc/z/zJNICritical.hpp" #include "gc/z/zLargePages.hpp" @@ -54,7 +53,6 @@ ZInitialize::ZInitialize(ZBarrierSet* barrier_set) { ZThreadLocalAllocBuffer::initialize(); ZTracer::initialize(); ZLargePages::initialize(); - ZHeuristics::set_medium_page_size(); ZBarrierSet::set_barrier_set(barrier_set); ZJNICritical::initialize(); ZDriver::initialize(); diff --git a/src/hotspot/share/gc/z/zIterator.inline.hpp b/src/hotspot/share/gc/z/zIterator.inline.hpp index 9ccacdc9a3ca1..af97a549b0de3 100644 --- a/src/hotspot/share/gc/z/zIterator.inline.hpp +++ b/src/hotspot/share/gc/z/zIterator.inline.hpp @@ -26,11 +26,21 @@ #include "gc/z/zIterator.hpp" +#include "gc/z/zVerify.hpp" #include "memory/iterator.inline.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" inline bool ZIterator::is_invisible_object(oop obj) { + // This is a good place to make sure that we can't concurrently iterate over + // objects while VMThread operations think they have exclusive access to the + // object graph. + // + // One example that have caused problems is the JFR Leak Profiler, which + // sets the mark word to a value that makes the object arrays look like + // invisible objects. + z_verify_safepoints_are_blocked(); + return obj->mark_acquire().is_marked(); } diff --git a/src/hotspot/share/gc/z/zReferenceProcessor.cpp b/src/hotspot/share/gc/z/zReferenceProcessor.cpp index 1037093523dd6..df8cb2b0e959f 100644 --- a/src/hotspot/share/gc/z/zReferenceProcessor.cpp +++ b/src/hotspot/share/gc/z/zReferenceProcessor.cpp @@ -113,6 +113,7 @@ static void list_append(zaddress& head, zaddress& tail, zaddress reference) { ZReferenceProcessor::ZReferenceProcessor(ZWorkers* workers) : _workers(workers), _soft_reference_policy(nullptr), + _clear_all_soft_refs(false), _encountered_count(), _discovered_count(), _enqueued_count(), @@ -124,8 +125,9 @@ void ZReferenceProcessor::set_soft_reference_policy(bool clear) { static AlwaysClearPolicy always_clear_policy; static LRUMaxHeapPolicy lru_max_heap_policy; + _clear_all_soft_refs = clear; + if (clear) { - log_info(gc, ref)("Clearing All SoftReferences"); _soft_reference_policy = &always_clear_policy; } else { _soft_reference_policy = &lru_max_heap_policy; @@ -438,6 +440,10 @@ class ZReferenceProcessorTask : public ZTask { void ZReferenceProcessor::process_references() { ZStatTimerOld timer(ZSubPhaseConcurrentReferencesProcess); + if (_clear_all_soft_refs) { + log_info(gc, ref)("Clearing All SoftReferences"); + } + // Process discovered lists ZReferenceProcessorTask task(this); _workers->run(&task); diff --git a/src/hotspot/share/gc/z/zReferenceProcessor.hpp b/src/hotspot/share/gc/z/zReferenceProcessor.hpp index d39cc8634cd22..7a8900827da83 100644 --- a/src/hotspot/share/gc/z/zReferenceProcessor.hpp +++ b/src/hotspot/share/gc/z/zReferenceProcessor.hpp @@ -41,6 +41,7 @@ class ZReferenceProcessor : public ReferenceDiscoverer { ZWorkers* const _workers; ReferencePolicy* _soft_reference_policy; + bool _clear_all_soft_refs; ZPerWorker _encountered_count; ZPerWorker _discovered_count; ZPerWorker _enqueued_count; diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index d4e3e92b3aa0b..281553f7fdfbd 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -87,6 +87,7 @@ ZRelocateQueue::ZRelocateQueue() _nworkers(0), _nsynchronized(0), _synchronize(false), + _is_active(false), _needs_attention(0) {} bool ZRelocateQueue::needs_attention() const { @@ -103,6 +104,20 @@ void ZRelocateQueue::dec_needs_attention() { assert(needs_attention == 0 || needs_attention == 1, "Invalid state"); } +void ZRelocateQueue::activate(uint nworkers) { + _is_active = true; + join(nworkers); +} + +void ZRelocateQueue::deactivate() { + Atomic::store(&_is_active, false); + clear(); +} + +bool ZRelocateQueue::is_active() const { + return Atomic::load(&_is_active); +} + void ZRelocateQueue::join(uint nworkers) { assert(nworkers != 0, "Must request at least one worker"); assert(_nworkers == 0, "Invalid state"); @@ -327,7 +342,7 @@ ZWorkers* ZRelocate::workers() const { } void ZRelocate::start() { - _queue.join(workers()->active_workers()); + _queue.activate(workers()->active_workers()); } void ZRelocate::add_remset(volatile zpointer* p) { @@ -1088,6 +1103,9 @@ class ZRelocateTask : public ZRestartableTask { ~ZRelocateTask() { _generation->stat_relocation()->at_relocate_end(_small_allocator.in_place_count(), _medium_allocator.in_place_count()); + + // Signal that we're not using the queue anymore. Used mostly for asserts. + _queue->deactivate(); } virtual void work() { @@ -1232,8 +1250,6 @@ void ZRelocate::relocate(ZRelocationSet* relocation_set) { ZRelocateAddRemsetForFlipPromoted task(relocation_set->flip_promoted_pages()); workers()->run(&task); } - - _queue.clear(); } ZPageAge ZRelocate::compute_to_age(ZPageAge from_age) { @@ -1316,3 +1332,7 @@ void ZRelocate::desynchronize() { ZRelocateQueue* ZRelocate::queue() { return &_queue; } + +bool ZRelocate::is_queue_active() const { + return _queue.is_active(); +} diff --git a/src/hotspot/share/gc/z/zRelocate.hpp b/src/hotspot/share/gc/z/zRelocate.hpp index ed54103d53c18..1b35abdf521fb 100644 --- a/src/hotspot/share/gc/z/zRelocate.hpp +++ b/src/hotspot/share/gc/z/zRelocate.hpp @@ -41,6 +41,7 @@ class ZRelocateQueue { uint _nworkers; uint _nsynchronized; bool _synchronize; + volatile bool _is_active; volatile int _needs_attention; bool needs_attention() const; @@ -53,6 +54,10 @@ class ZRelocateQueue { public: ZRelocateQueue(); + void activate(uint nworkers); + void deactivate(); + bool is_active() const; + void join(uint nworkers); void resize_workers(uint nworkers); void leave(); @@ -99,6 +104,8 @@ class ZRelocate { void desynchronize(); ZRelocateQueue* queue(); + + bool is_queue_active() const; }; #endif // SHARE_GC_Z_ZRELOCATE_HPP diff --git a/src/hotspot/share/gc/z/zRelocationSet.cpp b/src/hotspot/share/gc/z/zRelocationSet.cpp index 83bdf13b2bb02..92f245777b4e9 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.cpp +++ b/src/hotspot/share/gc/z/zRelocationSet.cpp @@ -106,11 +106,16 @@ class ZRelocationSetInstallTask : public ZTask { } virtual void work() { + // Join the STS to block out VMThreads while running promote_barrier_on_young_oop_field + SuspendibleThreadSetJoiner sts_joiner; + // Allocate and install forwardings for small pages for (size_t page_index; _small_iter.next_index(&page_index);) { ZPage* page = _small->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); install_small(forwarding, _medium->length() + page_index); + + SuspendibleThreadSet::yield(); } // Allocate and install forwardings for medium pages @@ -118,6 +123,8 @@ class ZRelocationSetInstallTask : public ZTask { ZPage* page = _medium->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); install_medium(forwarding, page_index); + + SuspendibleThreadSet::yield(); } } diff --git a/src/hotspot/share/gc/z/zRootsIterator.cpp b/src/hotspot/share/gc/z/zRootsIterator.cpp index 130ab5e4627a8..086d90781dd63 100644 --- a/src/hotspot/share/gc/z/zRootsIterator.cpp +++ b/src/hotspot/share/gc/z/zRootsIterator.cpp @@ -101,7 +101,7 @@ void ZParallelApply::apply(ClosureType* cl) { } void ZOopStorageSetIteratorStrong::apply(OopClosure* cl) { - ZRootStatTimer timer(ZSubPhaseConcurrentWeakRootsOopStorageSet, _generation); + ZRootStatTimer timer(ZSubPhaseConcurrentRootsOopStorageSet, _generation); _iter.oops_do(cl); } diff --git a/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp b/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp index 3eb28d3cafe26..a7d39e5ed9cc5 100644 --- a/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp +++ b/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp @@ -29,11 +29,12 @@ #include "gc/z/zAddress.inline.hpp" #include "gc/z/zBarrier.inline.hpp" #include "gc/z/zHeap.inline.hpp" +#include "gc/z/zBarrier.hpp" #include "oops/oop.hpp" template inline void ZUncoloredRoot::barrier(ObjectFunctionT function, zaddress_unsafe* p, uintptr_t color) { - z_assert_is_barrier_safe(); + z_verify_safepoints_are_blocked(); const zaddress_unsafe addr = Atomic::load(p); assert_is_valid(addr); diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index 6950f66915871..b168610db3af1 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -43,16 +43,67 @@ #include "runtime/frame.inline.hpp" #include "runtime/globals.hpp" #include "runtime/handles.hpp" -#include "runtime/javaThread.hpp" +#include "runtime/javaThread.inline.hpp" +#include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" #include "runtime/stackFrameStream.inline.hpp" #include "runtime/stackWatermark.inline.hpp" #include "runtime/stackWatermarkSet.inline.hpp" +#include "runtime/thread.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/preserveException.hpp" #include "utilities/resourceHash.hpp" +#ifdef ASSERT + +// Used to verify that safepoints operations can't be scheduled concurrently +// with callers to this function. Typically used to verify that object oops +// and headers are safe to access. +void z_verify_safepoints_are_blocked() { + Thread* current = Thread::current(); + + if (current->is_ConcurrentGC_thread()) { + assert(current->is_suspendible_thread(), // Thread prevents safepoints + "Safepoints are not blocked by current thread"); + + } else if (current->is_Worker_thread()) { + assert(// Check if ... + // the thread prevents safepoints + current->is_suspendible_thread() || + // the coordinator thread is the safepointing VMThread + current->is_indirectly_safepoint_thread() || + // the coordinator thread prevents safepoints + current->is_indirectly_suspendible_thread() || + // the RelocateQueue prevents safepoints + // + // RelocateQueue acts as a pseudo STS leaver/joiner and blocks + // safepoints. There's currently no infrastructure to check if the + // current thread is active or not, so check the global states instead. + ZGeneration::young()->is_relocate_queue_active() || + ZGeneration::old()->is_relocate_queue_active(), + "Safepoints are not blocked by current thread"); + + } else if (current->is_Java_thread()) { + JavaThreadState state = JavaThread::cast(current)->thread_state(); + assert(state == _thread_in_Java || state == _thread_in_vm || state == _thread_new, + "Safepoints are not blocked by current thread from state: %d", state); + + } else if (current->is_JfrSampler_thread()) { + // The JFR sampler thread blocks out safepoints with this lock. + assert_lock_strong(Threads_lock); + + } else if (current->is_VM_thread()) { + // The VM Thread doesn't schedule new safepoints while executing + // other safepoint or handshake operations. + + } else { + fatal("Unexpected thread type"); + } +} + +#endif + #define BAD_OOP_ARG(o, p) "Bad oop " PTR_FORMAT " found at " PTR_FORMAT, untype(o), p2i(p) static bool z_is_null_relaxed(zpointer o) { diff --git a/src/hotspot/share/gc/z/zVerify.hpp b/src/hotspot/share/gc/z/zVerify.hpp index e9ada2cefa9ca..447d38504a262 100644 --- a/src/hotspot/share/gc/z/zVerify.hpp +++ b/src/hotspot/share/gc/z/zVerify.hpp @@ -30,6 +30,8 @@ class frame; class ZForwarding; class ZPageAllocator; +NOT_DEBUG(inline) void z_verify_safepoints_are_blocked() NOT_DEBUG_RETURN; + class ZVerify : public AllStatic { private: static void roots_strong(bool verify_after_old_mark); diff --git a/src/hotspot/share/interpreter/bytecodes.cpp b/src/hotspot/share/interpreter/bytecodes.cpp index 5db3ab5fe6b0d..181024bffc6c6 100644 --- a/src/hotspot/share/interpreter/bytecodes.cpp +++ b/src/hotspot/share/interpreter/bytecodes.cpp @@ -385,12 +385,18 @@ int Bytecodes::special_length_at(Bytecodes::Code code, address bcp, address end) if (end != nullptr && aligned_bcp + 3*jintSize >= end) { return -1; // don't read past end of code buffer } + // Promote calculation to signed 64 bits to do range checks, used by the verifier. jlong lo = (jint)Bytes::get_Java_u4(aligned_bcp + 1*jintSize); jlong hi = (jint)Bytes::get_Java_u4(aligned_bcp + 2*jintSize); jlong len = (aligned_bcp - bcp) + (3 + hi - lo + 1)*jintSize; - // only return len if it can be represented as a positive int; - // return -1 otherwise - return (len > 0 && len == (int)len) ? len : -1; + // Only return len if it can be represented as a positive int and lo <= hi. + // The caller checks for bytecode stream overflow. + if (lo <= hi && len == (int)len) { + assert(len > 0, "must be"); + return (int)len; + } else { + return -1; + } } case _lookupswitch: // fall through @@ -402,9 +408,13 @@ int Bytecodes::special_length_at(Bytecodes::Code code, address bcp, address end) } jlong npairs = (jint)Bytes::get_Java_u4(aligned_bcp + jintSize); jlong len = (aligned_bcp - bcp) + (2 + 2*npairs)*jintSize; - // only return len if it can be represented as a positive int; - // return -1 otherwise - return (len > 0 && len == (int)len) ? len : -1; + // Only return len if it can be represented as a positive int and npairs >= 0. + if (npairs >= 0 && len == (int)len) { + assert(len > 0, "must be"); + return (int)len; + } else { + return -1; + } } default: // Note: Length functions must return <=0 for invalid bytecodes. diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 458dfe5bc605b..ac73a0b36c7c4 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -932,10 +932,11 @@ - + - + + Copyright (c) 2012-2014 Daniel J. Bernstein + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + You should have received a copy of the CC0 Public Domain Dedication along + with + this software. If not, see + . +``` + +### Licenses +The code is dual-licensed CCO and MIT + +#### MIT License +``` +Copyright 2012-2024 JP Aumasson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +``` + +#### CC0 1.0 Universal +``` +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific +works ("Commons") that the public can reliably and without fear of later +claims of infringement build upon, modify, incorporate in other works, reuse +and redistribute as freely as possible in any form whatsoever and for any +purposes, including without limitation commercial purposes. These owners may +contribute to the Commons to promote the ideal of a free culture and the +further production of creative, cultural and scientific works, or to gain +reputation or greater distribution for their Work in part through the use and +efforts of others. + +For these and/or other purposes and motivations, and without any expectation +of additional consideration or compensation, the person associating CC0 with a +Work (the "Affirmer"), to the extent that he or she is an owner of Copyright +and Related Rights in the Work, voluntarily elects to apply CC0 to the Work +and publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not limited +to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, communicate, + and translate a Work; + + ii. moral rights retained by the original author(s) and/or performer(s); + + iii. publicity and privacy rights pertaining to a person's image or likeness + depicted in a Work; + + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + + v. rights protecting the extraction, dissemination, use and reuse of data in + a Work; + + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation thereof, + including any amended or successor version of such directive); and + + vii. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, +applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and +unconditionally waives, abandons, and surrenders all of Affirmer's Copyright +and Related Rights and associated claims and causes of action, whether now +known or unknown (including existing as well as future claims and causes of +action), in the Work (i) in all territories worldwide, (ii) for the maximum +duration provided by applicable law or treaty (including future time +extensions), (iii) in any current or future medium and for any number of +copies, and (iv) for any purpose whatsoever, including without limitation +commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes +the Waiver for the benefit of each member of the public at large and to the +detriment of Affirmer's heirs and successors, fully intending that such Waiver +shall not be subject to revocation, rescission, cancellation, termination, or +any other legal or equitable action to disrupt the quiet enjoyment of the Work +by the public as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be +judged legally invalid or ineffective under applicable law, then the Waiver +shall be preserved to the maximum extent permitted taking into account +Affirmer's express Statement of Purpose. In addition, to the extent the Waiver +is so judged Affirmer hereby grants to each affected person a royalty-free, +non transferable, non sublicensable, non exclusive, irrevocable and +unconditional license to exercise Affirmer's Copyright and Related Rights in +the Work (i) in all territories worldwide, (ii) for the maximum duration +provided by applicable law or treaty (including future time extensions), (iii) +in any current or future medium and for any number of copies, and (iv) for any +purpose whatsoever, including without limitation commercial, advertising or +promotional purposes (the "License"). The License shall be deemed effective as +of the date CC0 was applied by Affirmer to the Work. Should any part of the +License for any reason be judged legally invalid or ineffective under +applicable law, such partial invalidity or ineffectiveness shall not +invalidate the remainder of the License, and in such case Affirmer hereby +affirms that he or she will not (i) exercise any of his or her remaining +Copyright and Related Rights in the Work or (ii) assert any associated claims +and causes of action with respect to the Work, in either case contrary to +Affirmer's express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + + b. Affirmer offers the Work as-is and makes no representations or warranties + of any kind concerning the Work, express, implied, statutory or otherwise, + including without limitation warranties of title, merchantability, fitness + for a particular purpose, non infringement, or the absence of latent or + other defects, accuracy, or the present or absence of errors, whether or not + discoverable, all to the greatest extent permissible under applicable law. + + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without limitation + any person's Copyright and Related Rights in the Work. Further, Affirmer + disclaims responsibility for obtaining any necessary consents, permissions + or other rights required for any use of the Work. + + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to this + CC0 or use of the Work. + +For more information, please see + + +``` diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp index 8e04ae11046af..99adff4844741 100644 --- a/src/hotspot/share/logging/logTag.hpp +++ b/src/hotspot/share/logging/logTag.hpp @@ -196,6 +196,7 @@ class outputStream; LOG_TAG(timer) \ LOG_TAG(tlab) \ LOG_TAG(tracking) \ + LOG_TAG(trimnative) /* trim native heap */ \ LOG_TAG(unload) /* Trace unloading of classes */ \ LOG_TAG(unmap) \ LOG_TAG(unshareable) \ diff --git a/src/hotspot/share/memory/arena.cpp b/src/hotspot/share/memory/arena.cpp index 53946e5cd4725..1c2dc593b9f4a 100644 --- a/src/hotspot/share/memory/arena.cpp +++ b/src/hotspot/share/memory/arena.cpp @@ -30,6 +30,7 @@ #include "runtime/os.hpp" #include "runtime/task.hpp" #include "runtime/threadCritical.hpp" +#include "runtime/trimNativeHeap.hpp" #include "services/memTracker.inline.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" @@ -92,6 +93,7 @@ class ChunkPool { } static void clean() { + NativeHeapTrimmer::SuspendMark sm("chunk pool cleaner"); for (int i = 0; i < _num_pools; i++) { _pools[i].prune(); } diff --git a/src/hotspot/share/memory/heap.hpp b/src/hotspot/share/memory/heap.hpp index 97ac11708c1c0..da02eecae4988 100644 --- a/src/hotspot/share/memory/heap.hpp +++ b/src/hotspot/share/memory/heap.hpp @@ -171,9 +171,6 @@ class CodeHeap : public CHeapObj { // Containment means "contained in committed space". bool contains(const void* p) const { return low() <= p && p < high(); } - bool contains_blob(const CodeBlob* blob) const { - return contains((void*)blob); - } void* find_start(void* p) const; // returns the block containing p or null CodeBlob* find_blob(void* start) const; diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index b71c213f4781d..f30080842540d 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -567,12 +567,6 @@ void Metaspace::initialize_class_space(ReservedSpace rs) { "wrong alignment"); MetaspaceContext::initialize_class_space_context(rs); - - // This does currently not work because rs may be the result of a split - // operation and NMT seems not to be able to handle splits. - // Will be fixed with JDK-8243535. - // MemTracker::record_virtual_memory_type((address)rs.base(), mtClass); - } // Returns true if class space has been setup (initialize_class_space). @@ -635,11 +629,13 @@ ReservedSpace Metaspace::reserve_address_space_for_compressed_classes(size_t siz // (the OS already assigned it for something else), go to the next position, wrapping // around if necessary, until we exhaust all the items. os::init_random((int)os::javaTimeNanos()); - r = os::random(); + r = ABS(os::random()) % len; + assert(r >= 0, "must be"); log_info(metaspace)("Randomizing compressed class space: start from %d out of %d locations", - r % len, len); + r, len); } for (int i = 0; i < len; i++) { + assert((i + r) >= 0, "should never underflow because len is small integer"); address a = list.at((i + r) % len); ReservedSpace rs(size, Metaspace::reserve_alignment(), os::vm_page_size(), (char*)a); @@ -835,6 +831,9 @@ void Metaspace::global_initialize() { CompressedClassSpaceSize)); } + // Mark class space as such + MemTracker::record_virtual_memory_type((address)rs.base(), mtClass); + // Initialize space Metaspace::initialize_class_space(rs); diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 58c1792633e13..de479d3e9e4cf 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -335,7 +335,7 @@ void Universe::genesis(TRAPS) { // Initialization of the fillerArrayKlass must come before regular // int-TypeArrayKlass so that the int-Array mirror points to the // int-TypeArrayKlass. - _fillerArrayKlassObj = TypeArrayKlass::create_klass(T_INT, "Ljdk/internal/vm/FillerArray;", CHECK); + _fillerArrayKlassObj = TypeArrayKlass::create_klass(T_INT, "[Ljdk/internal/vm/FillerElement;", CHECK); for (int i = T_BOOLEAN; i < T_LONG+1; i++) { _typeArrayKlassObjs[i] = TypeArrayKlass::create_klass((BasicType)i, CHECK); } diff --git a/src/hotspot/share/oops/constMethodFlags.cpp b/src/hotspot/share/oops/constMethodFlags.cpp index 3664cb12e0181..69b017cb18055 100644 --- a/src/hotspot/share/oops/constMethodFlags.cpp +++ b/src/hotspot/share/oops/constMethodFlags.cpp @@ -29,7 +29,7 @@ void ConstMethodFlags::print_on(outputStream* st) const { #define CM_PRINT(name, ignore) \ - if (name()) st->print(" " #name " "); + if (name()) st->print(#name " "); CM_FLAGS_DO(CM_PRINT) #undef CM_PRINT } diff --git a/src/hotspot/share/oops/fieldStreams.hpp b/src/hotspot/share/oops/fieldStreams.hpp index 31f3fa6ca40eb..54619f4d472b4 100644 --- a/src/hotspot/share/oops/fieldStreams.hpp +++ b/src/hotspot/share/oops/fieldStreams.hpp @@ -37,6 +37,7 @@ // iterates over fields that have been injected by the JVM. // AllFieldStream exposes all fields and should only be used in rare // cases. +// HierarchicalFieldStream allows to also iterate over fields of supertypes. class FieldStreamBase : public StackObj { protected: const Array* _fieldinfo_stream; @@ -135,7 +136,7 @@ class FieldStreamBase : public StackObj { } }; -// Iterate over only the internal fields +// Iterate over only the Java fields class JavaFieldStream : public FieldStreamBase { public: JavaFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants(), 0, k->java_fields_count()) {} @@ -179,4 +180,104 @@ class AllFieldStream : public FieldStreamBase { AllFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants()) {} }; +// Iterate over fields including the ones declared in supertypes +template +class HierarchicalFieldStream : public StackObj { + private: + const Array* _interfaces; + InstanceKlass* _next_klass; // null indicates no more type to visit + FieldStreamType _current_stream; + int _interface_index; + + void prepare() { + _next_klass = next_klass_with_fields(); + // special case: the initial klass has no fields. If any supertype has any fields, use that directly. + // if no such supertype exists, done() will return false already. + next_stream_if_done(); + } + + InstanceKlass* next_klass_with_fields() { + assert(_next_klass != nullptr, "reached end of types already"); + InstanceKlass* result = _next_klass; + do { + if (!result->is_interface() && result->super() != nullptr) { + result = result->java_super(); + } else if (_interface_index > 0) { + result = _interfaces->at(--_interface_index); + } else { + return nullptr; // we did not find any more supertypes with fields + } + } while (FieldStreamType(result).done()); + return result; + } + + // sets _current_stream to the next if the current is done and any more is available + void next_stream_if_done() { + if (_next_klass != nullptr && _current_stream.done()) { + _current_stream = FieldStreamType(_next_klass); + assert(!_current_stream.done(), "created empty stream"); + _next_klass = next_klass_with_fields(); + } + } + + public: + HierarchicalFieldStream(InstanceKlass* klass) : + _interfaces(klass->transitive_interfaces()), + _next_klass(klass), + _current_stream(FieldStreamType(klass)), + _interface_index(_interfaces->length()) { + prepare(); + } + + void next() { + _current_stream.next(); + next_stream_if_done(); + } + + bool done() const { return _next_klass == nullptr && _current_stream.done(); } + + // bridge functions from FieldStreamBase + + AccessFlags access_flags() const { + return _current_stream.access_flags(); + } + + FieldInfo::FieldFlags field_flags() const { + return _current_stream.field_flags(); + } + + Symbol* name() const { + return _current_stream.name(); + } + + Symbol* signature() const { + return _current_stream.signature(); + } + + Symbol* generic_signature() const { + return _current_stream.generic_signature(); + } + + int offset() const { + return _current_stream.offset(); + } + + bool is_contended() const { + return _current_stream.is_contended(); + } + + int contended_group() const { + return _current_stream.contended_group(); + } + + FieldInfo to_FieldInfo() { + return _current_stream.to_FieldInfo(); + } + + fieldDescriptor& field_descriptor() const { + return _current_stream.field_descriptor(); + } + +}; + #endif // SHARE_OOPS_FIELDSTREAMS_HPP diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 565c136435424..6f0d521b9d4c3 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -768,20 +768,43 @@ void InstanceKlass::link_class(TRAPS) { void InstanceKlass::check_link_state_and_wait(JavaThread* current) { MonitorLocker ml(current, _init_monitor); + bool debug_logging_enabled = log_is_enabled(Debug, class, init); + // Another thread is linking this class, wait. while (is_being_linked() && !is_init_thread(current)) { + if (debug_logging_enabled) { + ResourceMark rm(current); + log_debug(class, init)("Thread \"%s\" waiting for linking of %s by thread \"%s\"", + current->name(), external_name(), init_thread_name()); + } ml.wait(); } // This thread is recursively linking this class, continue if (is_being_linked() && is_init_thread(current)) { + if (debug_logging_enabled) { + ResourceMark rm(current); + log_debug(class, init)("Thread \"%s\" recursively linking %s", + current->name(), external_name()); + } return; } // If this class wasn't linked already, set state to being_linked if (!is_linked()) { + if (debug_logging_enabled) { + ResourceMark rm(current); + log_debug(class, init)("Thread \"%s\" linking %s", + current->name(), external_name()); + } set_init_state(being_linked); set_init_thread(current); + } else { + if (debug_logging_enabled) { + ResourceMark rm(current); + log_debug(class, init)("Thread \"%s\" found %s already linked", + current->name(), external_name()); + } } } @@ -1047,13 +1070,21 @@ void InstanceKlass::initialize_impl(TRAPS) { JavaThread* jt = THREAD; + bool debug_logging_enabled = log_is_enabled(Debug, class, init); + // refer to the JVM book page 47 for description of steps // Step 1 { - MonitorLocker ml(THREAD, _init_monitor); + MonitorLocker ml(jt, _init_monitor); // Step 2 while (is_being_initialized() && !is_init_thread(jt)) { + if (debug_logging_enabled) { + ResourceMark rm(jt); + log_debug(class, init)("Thread \"%s\" waiting for initialization of %s by thread \"%s\"", + jt->name(), external_name(), init_thread_name()); + } + wait = true; jt->set_class_to_be_initialized(this); ml.wait(); @@ -1062,24 +1093,44 @@ void InstanceKlass::initialize_impl(TRAPS) { // Step 3 if (is_being_initialized() && is_init_thread(jt)) { + if (debug_logging_enabled) { + ResourceMark rm(jt); + log_debug(class, init)("Thread \"%s\" recursively initializing %s", + jt->name(), external_name()); + } DTRACE_CLASSINIT_PROBE_WAIT(recursive, -1, wait); return; } // Step 4 if (is_initialized()) { + if (debug_logging_enabled) { + ResourceMark rm(jt); + log_debug(class, init)("Thread \"%s\" found %s already initialized", + jt->name(), external_name()); + } DTRACE_CLASSINIT_PROBE_WAIT(concurrent, -1, wait); return; } // Step 5 if (is_in_error_state()) { + if (debug_logging_enabled) { + ResourceMark rm(jt); + log_debug(class, init)("Thread \"%s\" found %s is in error state", + jt->name(), external_name()); + } throw_error = true; } else { // Step 6 set_init_state(being_initialized); set_init_thread(jt); + if (debug_logging_enabled) { + ResourceMark rm(jt); + log_debug(class, init)("Thread \"%s\" is initializing %s", + jt->name(), external_name()); + } } } @@ -1553,7 +1604,9 @@ void InstanceKlass::call_class_initializer(TRAPS) { LogStream ls(lt); ls.print("%d Initializing ", call_class_initializer_counter++); name()->print_value_on(&ls); - ls.print_cr("%s (" PTR_FORMAT ")", h_method() == nullptr ? "(no method)" : "", p2i(this)); + ls.print_cr("%s (" PTR_FORMAT ") by thread \"%s\"", + h_method() == nullptr ? "(no method)" : "", p2i(this), + THREAD->name()); } if (h_method() != nullptr) { JavaCallArguments args; // No arguments @@ -4059,6 +4112,23 @@ bool InstanceKlass::should_clean_previous_versions_and_reset() { return ret; } +// This nulls out jmethodIDs for all methods in 'klass' +// It needs to be called explicitly for all previous versions of a class because these may not be cleaned up +// during class unloading. +// We can not use the jmethodID cache associated with klass directly because the 'previous' versions +// do not have the jmethodID cache filled in. Instead, we need to lookup jmethodID for each method and this +// is expensive - O(n) for one jmethodID lookup. For all contained methods it is O(n^2). +// The reason for expensive jmethodID lookup for each method is that there is no direct link between method and jmethodID. +void InstanceKlass::clear_jmethod_ids(InstanceKlass* klass) { + Array* method_refs = klass->methods(); + for (int k = 0; k < method_refs->length(); k++) { + Method* method = method_refs->at(k); + if (method != nullptr && method->is_obsolete()) { + method->clear_jmethod_id(); + } + } +} + // Purge previous versions before adding new previous versions of the class and // during class unloading. void InstanceKlass::purge_previous_version_list() { @@ -4102,6 +4172,7 @@ void InstanceKlass::purge_previous_version_list() { // Unlink from previous version list. assert(pv_node->class_loader_data() == loader_data, "wrong loader_data"); InstanceKlass* next = pv_node->previous_versions(); + clear_jmethod_ids(pv_node); // jmethodID maintenance for the unloaded class pv_node->link_previous_versions(nullptr); // point next to null last->link_previous_versions(next); // Delete this node directly. Nothing is referring to it and we don't @@ -4321,4 +4392,3 @@ void ClassHierarchyIterator::next() { _current = _current->next_sibling(); return; // visit next sibling subclass } - diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index ae08a56686f44..3026960221150 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -491,6 +491,14 @@ class InstanceKlass: public Klass { static void check_prohibited_package(Symbol* class_name, ClassLoaderData* loader_data, TRAPS); + + JavaThread* init_thread() { return Atomic::load(&_init_thread); } + // We can safely access the name as long as we hold the _init_monitor. + const char* init_thread_name() { + assert(_init_monitor->owned_by_self(), "Must hold _init_monitor here"); + return init_thread()->name_raw(); + } + public: // initialization state bool is_loaded() const { return init_state() >= loaded; } @@ -500,7 +508,7 @@ class InstanceKlass: public Klass { bool is_not_initialized() const { return init_state() < being_initialized; } bool is_being_initialized() const { return init_state() == being_initialized; } bool is_in_error_state() const { return init_state() == initialization_error; } - bool is_init_thread(JavaThread *thread) { return thread == Atomic::load(&_init_thread); } + bool is_init_thread(JavaThread *thread) { return thread == init_thread(); } ClassState init_state() const { return Atomic::load(&_init_state); } const char* init_state_name() const; bool is_rewritten() const { return _misc_flags.rewritten(); } @@ -1077,6 +1085,8 @@ class InstanceKlass: public Klass { bool idnum_can_increment() const { return has_been_redefined(); } inline jmethodID* methods_jmethod_ids_acquire() const; inline void release_set_methods_jmethod_ids(jmethodID* jmeths); + // This nulls out jmethodIDs for all methods in 'klass' + static void clear_jmethod_ids(InstanceKlass* klass); // Lock during initialization public: diff --git a/src/hotspot/share/oops/instanceKlassFlags.cpp b/src/hotspot/share/oops/instanceKlassFlags.cpp index 7ed77eb13fc6b..864fe60af2ea3 100644 --- a/src/hotspot/share/oops/instanceKlassFlags.cpp +++ b/src/hotspot/share/oops/instanceKlassFlags.cpp @@ -32,11 +32,10 @@ void InstanceKlassFlags::print_on(outputStream* st) const { #define IK_FLAGS_PRINT(name, ignore) \ - if (name()) st->print(" ##name "); + if (name()) st->print(#name " "); IK_FLAGS_DO(IK_FLAGS_PRINT) IK_STATUS_DO(IK_FLAGS_PRINT) #undef IK_FLAGS_PRINT - st->cr(); } #if INCLUDE_CDS diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 8625d2537cc9e..c5693b02b0578 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -2262,6 +2262,20 @@ void Method::clear_jmethod_ids(ClassLoaderData* loader_data) { loader_data->jmethod_ids()->clear_all_methods(); } +void Method::clear_jmethod_id() { + // Being at a safepoint prevents racing against other class redefinitions + assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); + // The jmethodID is not stored in the Method instance, we need to look it up first + jmethodID methodid = find_jmethod_id_or_null(); + // We need to make sure that jmethodID actually resolves to this method + // - multiple redefined versions may share jmethodID slots and if a method + // has already been rewired to a newer version we could be removing reference + // to a still existing method instance + if (methodid != nullptr && *((Method**)methodid) == this) { + *((Method**)methodid) = nullptr; + } +} + bool Method::has_method_vptr(const void* ptr) { Method m; // This assumes that the vtbl pointer is the first word of a C++ object. diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 06f0b8cf7d769..a4f8f3075efd3 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -773,6 +773,7 @@ class Method : public Metadata { // Clear methods static void clear_jmethod_ids(ClassLoaderData* loader_data); + void clear_jmethod_id(); static void print_jmethod_ids_count(const ClassLoaderData* loader_data, outputStream* out) PRODUCT_RETURN; // Get this method's jmethodID -- allocate if it doesn't exist diff --git a/src/hotspot/share/oops/methodFlags.cpp b/src/hotspot/share/oops/methodFlags.cpp index 3c805a4a8129f..4945dcc4b8396 100644 --- a/src/hotspot/share/oops/methodFlags.cpp +++ b/src/hotspot/share/oops/methodFlags.cpp @@ -28,7 +28,7 @@ void MethodFlags::print_on(outputStream* st) const { #define M_PRINT(name, ignore) \ - if (name()) st->print(" " #name " "); + if (name()) st->print(#name " "); M_STATUS_DO(M_PRINT) #undef M_PRINT } diff --git a/src/hotspot/share/oops/symbol.cpp b/src/hotspot/share/oops/symbol.cpp index f77d69fe3d41a..cbb51e1bb90e5 100644 --- a/src/hotspot/share/oops/symbol.cpp +++ b/src/hotspot/share/oops/symbol.cpp @@ -22,7 +22,6 @@ * */ - #include "precompiled.hpp" #include "cds/metaspaceShared.hpp" #include "classfile/altHashing.hpp" @@ -390,11 +389,9 @@ void Symbol::print() const { print_on(tty); } // The print_value functions are present in all builds, to support the // disassembler and error reporting. void Symbol::print_value_on(outputStream* st) const { - st->print("'"); - for (int i = 0; i < utf8_length(); i++) { - st->print("%c", char_at(i)); - } - st->print("'"); + st->print_raw("'", 1); + st->print_raw((const char*)base(), utf8_length()); + st->print_raw("'", 1); } void Symbol::print_value() const { print_value_on(tty); } diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index cf8f58d8e2307..73629a11bcdba 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -283,8 +283,26 @@ Node* AddNode::IdealIL(PhaseGVN* phase, bool can_reshape, BasicType bt) { assert( in1->in(2) != this && in2->in(2) != this, "dead loop in AddINode::Ideal" ); Node* sub = SubNode::make(nullptr, nullptr, bt); - sub->init_req(1, phase->transform(AddNode::make(in1->in(1), in2->in(1), bt))); - sub->init_req(2, phase->transform(AddNode::make(in1->in(2), in2->in(2), bt))); + Node* sub_in1; + PhaseIterGVN* igvn = phase->is_IterGVN(); + // During IGVN, if both inputs of the new AddNode are a tree of SubNodes, this same transformation will be applied + // to every node of the tree. Calling transform() causes the transformation to be applied recursively, once per + // tree node whether some subtrees are identical or not. Pushing to the IGVN worklist instead, causes the transform + // to be applied once per unique subtrees (because all uses of a subtree are updated with the result of the + // transformation). In case of a large tree, this can make a difference in compilation time. + if (igvn != nullptr) { + sub_in1 = igvn->register_new_node_with_optimizer(AddNode::make(in1->in(1), in2->in(1), bt)); + } else { + sub_in1 = phase->transform(AddNode::make(in1->in(1), in2->in(1), bt)); + } + Node* sub_in2; + if (igvn != nullptr) { + sub_in2 = igvn->register_new_node_with_optimizer(AddNode::make(in1->in(2), in2->in(2), bt)); + } else { + sub_in2 = phase->transform(AddNode::make(in1->in(2), in2->in(2), bt)); + } + sub->init_req(1, sub_in1); + sub->init_req(2, sub_in2); return sub; } // Convert "(a-b)+(b+c)" into "(a+c)" diff --git a/src/hotspot/share/opto/arraycopynode.cpp b/src/hotspot/share/opto/arraycopynode.cpp index cfb959021edca..71b7a7e5024d9 100644 --- a/src/hotspot/share/opto/arraycopynode.cpp +++ b/src/hotspot/share/opto/arraycopynode.cpp @@ -134,12 +134,13 @@ int ArrayCopyNode::get_count(PhaseGVN *phase) const { assert (ary_src != nullptr, "not an array or instance?"); // clone passes a length as a rounded number of longs. If we're // cloning an array we'll do it element by element. If the - // length input to ArrayCopyNode is constant, length of input - // array must be too. - - assert((get_length_if_constant(phase) == -1) != ary_src->size()->is_con() || + // length of the input array is constant, ArrayCopyNode::Length + // must be too. Note that the opposite does not need to hold, + // because different input array lengths (e.g. int arrays with + // 3 or 4 elements) might lead to the same length input + // (e.g. 2 double-words). + assert(!ary_src->size()->is_con() || (get_length_if_constant(phase) >= 0) || phase->is_IterGVN() || phase->C->inlining_incrementally() || StressReflectiveCode, "inconsistent"); - if (ary_src->size()->is_con()) { return ary_src->size()->get_con(); } diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 10b8ac2028aef..29dd95322a035 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -53,6 +53,9 @@ product(bool, StressCCP, false, DIAGNOSTIC, \ "Randomize worklist traversal in CCP") \ \ + product(bool, StressIncrementalInlining, false, DIAGNOSTIC, \ + "Randomize the incremental inlining decision") \ + \ product(uint, StressSeed, 0, DIAGNOSTIC, \ "Seed for randomized stress testing (if unset, a random one is " \ "generated). The seed is recorded in the compilation log, if " \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 4b911620cf9f9..9e27ff17d9e1d 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -113,6 +113,7 @@ void C2Compiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci, boo bool do_locks_coarsening = EliminateLocks; while (!env->failing()) { + ResourceMark rm; // Attempt to compile while subsuming loads into machine instructions. Options options(subsume_loads, do_escape_analysis, do_iterative_escape_analysis, eliminate_boxing, do_locks_coarsening, install_code); Compile C(env, target, entry_bci, options, directive); diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index 50f9f4b85f34d..c88d5db5488ac 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -97,6 +97,8 @@ JVMState* ParseGenerator::generate(JVMState* jvms) { } Parse parser(jvms, method(), _expected_uses); + if (C->failing()) return nullptr; + // Grab signature for matching/allocation GraphKit& exits = parser.exits(); @@ -430,7 +432,7 @@ bool LateInlineMHCallGenerator::do_late_inline_check(Compile* C, JVMState* jvms) assert(!input_not_const, "sanity"); // shouldn't have been scheduled for inlining in the first place if (cg != nullptr) { - assert(!cg->is_late_inline() || cg->is_mh_late_inline() || AlwaysIncrementalInline, "we're doing late inlining"); + assert(!cg->is_late_inline() || cg->is_mh_late_inline() || AlwaysIncrementalInline || StressIncrementalInlining, "we're doing late inlining"); _inline_cg = cg; C->dec_number_of_mh_late_inlines(); return true; @@ -552,7 +554,7 @@ bool LateInlineVirtualCallGenerator::do_late_inline_check(Compile* C, JVMState* true /*allow_intrinsics*/); if (cg != nullptr) { - assert(!cg->is_late_inline() || cg->is_mh_late_inline() || AlwaysIncrementalInline, "we're doing late inlining"); + assert(!cg->is_late_inline() || cg->is_mh_late_inline() || AlwaysIncrementalInline || StressIncrementalInlining, "we're doing late inlining"); _inline_cg = cg; return true; } else { @@ -987,8 +989,9 @@ CallGenerator* CallGenerator::for_method_handle_call(JVMState* jvms, ciMethod* c bool input_not_const; CallGenerator* cg = CallGenerator::for_method_handle_inline(jvms, caller, callee, allow_inline, input_not_const); Compile* C = Compile::current(); + bool should_delay = C->should_delay_inlining(); if (cg != nullptr) { - if (AlwaysIncrementalInline) { + if (should_delay) { return CallGenerator::for_late_inline(callee, cg); } else { return cg; @@ -999,7 +1002,7 @@ CallGenerator* CallGenerator::for_method_handle_call(JVMState* jvms, ciMethod* c int call_site_count = caller->scale_count(profile.count()); if (IncrementalInlineMH && call_site_count > 0 && - (input_not_const || !C->inlining_incrementally() || C->over_inlining_cutoff())) { + (should_delay || input_not_const || !C->inlining_incrementally() || C->over_inlining_cutoff())) { return CallGenerator::for_mh_late_inline(caller, callee, input_not_const); } else { // Out-of-line call. diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index d0d05b5bb98f0..8a26d514b688b 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -36,14 +36,14 @@ //============================================================================= // If input is already higher or equal to cast type, then this is an identity. Node* ConstraintCastNode::Identity(PhaseGVN* phase) { + if (_dependency == UnconditionalDependency) { + return this; + } Node* dom = dominating_cast(phase, phase); if (dom != nullptr) { return dom; } - if (_dependency != RegularDependency) { - return this; - } - return phase->type(in(1))->higher_equal_speculative(_type) ? in(1) : this; + return higher_equal_types(phase, in(1)) ? in(1) : this; } //------------------------------Value------------------------------------------ @@ -100,47 +100,62 @@ Node *ConstraintCastNode::Ideal(PhaseGVN *phase, bool can_reshape) { return (in(0) && remove_dead_region(phase, can_reshape)) ? this : nullptr; } +uint ConstraintCastNode::hash() const { + return TypeNode::hash() + (int)_dependency + (_extra_types != nullptr ? _extra_types->hash() : 0); +} + bool ConstraintCastNode::cmp(const Node &n) const { - return TypeNode::cmp(n) && ((ConstraintCastNode&)n)._dependency == _dependency; + if (!TypeNode::cmp(n)) { + return false; + } + ConstraintCastNode& cast = (ConstraintCastNode&) n; + if (cast._dependency != _dependency) { + return false; + } + if (_extra_types == nullptr || cast._extra_types == nullptr) { + return _extra_types == cast._extra_types; + } + return _extra_types->eq(cast._extra_types); } uint ConstraintCastNode::size_of() const { return sizeof(*this); } -Node* ConstraintCastNode::make_cast(int opcode, Node* c, Node *n, const Type *t, DependencyType dependency) { +Node* ConstraintCastNode::make_cast(int opcode, Node* c, Node* n, const Type* t, DependencyType dependency, + const TypeTuple* extra_types) { switch(opcode) { case Op_CastII: { - Node* cast = new CastIINode(n, t, dependency); + Node* cast = new CastIINode(n, t, dependency, false, extra_types); cast->set_req(0, c); return cast; } case Op_CastLL: { - Node* cast = new CastLLNode(n, t, dependency); + Node* cast = new CastLLNode(n, t, dependency, extra_types); cast->set_req(0, c); return cast; } case Op_CastPP: { - Node* cast = new CastPPNode(n, t, dependency); + Node* cast = new CastPPNode(n, t, dependency, extra_types); cast->set_req(0, c); return cast; } case Op_CastFF: { - Node* cast = new CastFFNode(n, t, dependency); + Node* cast = new CastFFNode(n, t, dependency, extra_types); cast->set_req(0, c); return cast; } case Op_CastDD: { - Node* cast = new CastDDNode(n, t, dependency); + Node* cast = new CastDDNode(n, t, dependency, extra_types); cast->set_req(0, c); return cast; } case Op_CastVV: { - Node* cast = new CastVVNode(n, t, dependency); + Node* cast = new CastVVNode(n, t, dependency, extra_types); cast->set_req(0, c); return cast; } - case Op_CheckCastPP: return new CheckCastPPNode(c, n, t, dependency); + case Op_CheckCastPP: return new CheckCastPPNode(c, n, t, dependency, extra_types); default: fatal("Bad opcode %d", opcode); } @@ -150,10 +165,10 @@ Node* ConstraintCastNode::make_cast(int opcode, Node* c, Node *n, const Type *t, Node* ConstraintCastNode::make(Node* c, Node *n, const Type *t, DependencyType dependency, BasicType bt) { switch(bt) { case T_INT: { - return make_cast(Op_CastII, c, n, t, dependency); + return make_cast(Op_CastII, c, n, t, dependency, nullptr); } case T_LONG: { - return make_cast(Op_CastLL, c, n, t, dependency); + return make_cast(Op_CastLL, c, n, t, dependency, nullptr); } default: fatal("Bad basic type %s", type2name(bt)); @@ -186,7 +201,7 @@ TypeNode* ConstraintCastNode::dominating_cast(PhaseGVN* gvn, PhaseTransform* pt) u->outcnt() > 0 && u->Opcode() == opc && u->in(0) != nullptr && - u->bottom_type()->higher_equal(type())) { + higher_equal_types(gvn, u)) { if (pt->is_dominator(u->in(0), ctl)) { return u->as_Type(); } @@ -202,9 +217,28 @@ TypeNode* ConstraintCastNode::dominating_cast(PhaseGVN* gvn, PhaseTransform* pt) return nullptr; } +bool ConstraintCastNode::higher_equal_types(PhaseGVN* phase, const Node* other) const { + const Type* t = phase->type(other); + if (!t->higher_equal_speculative(type())) { + return false; + } + if (_extra_types != nullptr) { + for (uint i = 0; i < _extra_types->cnt(); ++i) { + if (!t->higher_equal_speculative(_extra_types->field_at(i))) { + return false; + } + } + } + return true; +} + #ifndef PRODUCT void ConstraintCastNode::dump_spec(outputStream *st) const { TypeNode::dump_spec(st); + if (_extra_types != nullptr) { + st->print(" extra types: "); + _extra_types->dump_on(st); + } if (_dependency != RegularDependency) { st->print(" %s dependency", _dependency == StrongDependency ? "strong" : "unconditional"); } @@ -228,79 +262,6 @@ const Type* CastIINode::Value(PhaseGVN* phase) const { res = widen_type(phase, res, T_INT); } - // Try to improve the type of the CastII if we recognize a CmpI/If pattern. - // - // in1 in2 - // | | - // +--- | --+ - // | | | - // CmpINode | - // | | - // BoolNode | - // | | - // IfNode | - // | | - // IfProj | - // | | - // CastIINode - // - if (carry_dependency()) { - if (in(0) != nullptr && in(0)->in(0) != nullptr && in(0)->in(0)->is_If()) { - assert(in(0)->is_IfFalse() || in(0)->is_IfTrue(), "should be If proj"); - Node* proj = in(0); - if (proj->in(0)->in(1)->is_Bool()) { - Node* b = proj->in(0)->in(1); - if (b->in(1)->Opcode() == Op_CmpI) { - Node* cmp = b->in(1); - if (cmp->in(1) == in(1) && phase->type(cmp->in(2))->isa_int()) { - const TypeInt* in2_t = phase->type(cmp->in(2))->is_int(); - const Type* t = TypeInt::INT; - BoolTest test = b->as_Bool()->_test; - if (proj->is_IfFalse()) { - test = test.negate(); - } - BoolTest::mask m = test._test; - jlong lo_long = min_jint; - jlong hi_long = max_jint; - if (m == BoolTest::le || m == BoolTest::lt) { - hi_long = in2_t->_hi; - if (m == BoolTest::lt) { - hi_long -= 1; - } - } else if (m == BoolTest::ge || m == BoolTest::gt) { - lo_long = in2_t->_lo; - if (m == BoolTest::gt) { - lo_long += 1; - } - } else if (m == BoolTest::eq) { - lo_long = in2_t->_lo; - hi_long = in2_t->_hi; - } else if (m == BoolTest::ne) { - // can't do any better - } else { - stringStream ss; - test.dump_on(&ss); - fatal("unexpected comparison %s", ss.freeze()); - } - int lo_int = (int)lo_long; - int hi_int = (int)hi_long; - - if (lo_long != (jlong)lo_int) { - lo_int = min_jint; - } - if (hi_long != (jlong)hi_int) { - hi_int = max_jint; - } - - t = TypeInt::make(lo_int, hi_int, Type::WidenMax); - - res = res->filter_speculative(t); - return res; - } - } - } - } - } return res; } @@ -523,20 +484,21 @@ Node* CastP2XNode::Identity(PhaseGVN* phase) { return this; } -Node* ConstraintCastNode::make_cast_for_type(Node* c, Node* in, const Type* type, DependencyType dependency) { +Node* ConstraintCastNode::make_cast_for_type(Node* c, Node* in, const Type* type, DependencyType dependency, + const TypeTuple* types) { Node* cast= nullptr; if (type->isa_int()) { - cast = make_cast(Op_CastII, c, in, type, dependency); + cast = make_cast(Op_CastII, c, in, type, dependency, types); } else if (type->isa_long()) { - cast = make_cast(Op_CastLL, c, in, type, dependency); + cast = make_cast(Op_CastLL, c, in, type, dependency, types); } else if (type->isa_float()) { - cast = make_cast(Op_CastFF, c, in, type, dependency); + cast = make_cast(Op_CastFF, c, in, type, dependency, types); } else if (type->isa_double()) { - cast = make_cast(Op_CastDD, c, in, type, dependency); + cast = make_cast(Op_CastDD, c, in, type, dependency, types); } else if (type->isa_vect()) { - cast = make_cast(Op_CastVV, c, in, type, dependency); + cast = make_cast(Op_CastVV, c, in, type, dependency, types); } else if (type->isa_ptr()) { - cast = make_cast(Op_CastPP, c, in, type, dependency); + cast = make_cast(Op_CastPP, c, in, type, dependency, types); } return cast; } diff --git a/src/hotspot/share/opto/castnode.hpp b/src/hotspot/share/opto/castnode.hpp index d4b2d61621696..cbb1c5fe521ee 100644 --- a/src/hotspot/share/opto/castnode.hpp +++ b/src/hotspot/share/opto/castnode.hpp @@ -43,11 +43,20 @@ class ConstraintCastNode: public TypeNode { const DependencyType _dependency; virtual bool cmp( const Node &n ) const; virtual uint size_of() const; + virtual uint hash() const; // Check the type const Type* widen_type(const PhaseGVN* phase, const Type* res, BasicType bt) const; + private: + // PhiNode::Ideal() transforms a Phi that merges a single uncasted value into a single cast pinned at the region. + // The types of cast nodes eliminated as a consequence of this transformation are collected and stored here so the + // type dependencies carried by the cast are known. The cast can then be eliminated if the type of its input is + // narrower (or equal) than all the types it carries. + const TypeTuple* _extra_types; + public: - ConstraintCastNode(Node *n, const Type *t, DependencyType dependency) - : TypeNode(t,2), _dependency(dependency) { + ConstraintCastNode(Node* n, const Type* t, ConstraintCastNode::DependencyType dependency, + const TypeTuple* extra_types) + : TypeNode(t,2), _dependency(dependency), _extra_types(extra_types) { init_class_id(Class_ConstraintCast); init_req(1, n); } @@ -59,14 +68,15 @@ class ConstraintCastNode: public TypeNode { virtual bool depends_only_on_test() const { return _dependency == RegularDependency; } bool carry_dependency() const { return _dependency != RegularDependency; } TypeNode* dominating_cast(PhaseGVN* gvn, PhaseTransform* pt) const; - static Node* make_cast(int opcode, Node* c, Node *n, const Type *t, DependencyType dependency); + static Node* make_cast(int opcode, Node* c, Node* n, const Type* t, DependencyType dependency, const TypeTuple* extra_types); static Node* make(Node* c, Node *n, const Type *t, DependencyType dependency, BasicType bt); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif - static Node* make_cast_for_type(Node* c, Node* in, const Type* type, DependencyType dependency); + static Node* make_cast_for_type(Node* c, Node* in, const Type* type, DependencyType dependency, + const TypeTuple* types); Node* optimize_integer_cast(PhaseGVN* phase, BasicType bt); @@ -91,6 +101,16 @@ class ConstraintCastNode: public TypeNode { } } } + + bool higher_equal_types(PhaseGVN* phase, const Node* other) const; + + int extra_types_count() const { + return _extra_types == nullptr ? 0 : _extra_types->cnt(); + } + + const Type* extra_type_at(int i) const { + return _extra_types->field_at(i); + } }; //------------------------------CastIINode------------------------------------- @@ -103,12 +123,12 @@ class CastIINode: public ConstraintCastNode { virtual uint size_of() const; public: - CastIINode(Node* n, const Type* t, DependencyType dependency = RegularDependency, bool range_check_dependency = false) - : ConstraintCastNode(n, t, dependency), _range_check_dependency(range_check_dependency) { + CastIINode(Node* n, const Type* t, DependencyType dependency = RegularDependency, bool range_check_dependency = false, const TypeTuple* types = nullptr) + : ConstraintCastNode(n, t, dependency, types), _range_check_dependency(range_check_dependency) { init_class_id(Class_CastII); } CastIINode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, bool range_check_dependency = false) - : ConstraintCastNode(n, t, dependency), _range_check_dependency(range_check_dependency) { + : ConstraintCastNode(n, t, dependency, nullptr), _range_check_dependency(range_check_dependency) { init_class_id(Class_CastII); init_req(0, ctrl); } @@ -134,12 +154,12 @@ class CastIINode: public ConstraintCastNode { class CastLLNode: public ConstraintCastNode { public: CastLLNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency) - : ConstraintCastNode(n, t, dependency) { + : ConstraintCastNode(n, t, dependency, nullptr) { init_class_id(Class_CastLL); init_req(0, ctrl); } - CastLLNode(Node* n, const Type* t, DependencyType dependency = RegularDependency) - : ConstraintCastNode(n, t, dependency){ + CastLLNode(Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + : ConstraintCastNode(n, t, dependency, types) { init_class_id(Class_CastLL); } @@ -151,8 +171,8 @@ class CastLLNode: public ConstraintCastNode { class CastFFNode: public ConstraintCastNode { public: - CastFFNode(Node* n, const Type* t, DependencyType dependency = RegularDependency) - : ConstraintCastNode(n, t, dependency){ + CastFFNode(Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + : ConstraintCastNode(n, t, dependency, types) { init_class_id(Class_CastFF); } virtual int Opcode() const; @@ -161,8 +181,8 @@ class CastFFNode: public ConstraintCastNode { class CastDDNode: public ConstraintCastNode { public: - CastDDNode(Node* n, const Type* t, DependencyType dependency = RegularDependency) - : ConstraintCastNode(n, t, dependency){ + CastDDNode(Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + : ConstraintCastNode(n, t, dependency, types) { init_class_id(Class_CastDD); } virtual int Opcode() const; @@ -171,8 +191,8 @@ class CastDDNode: public ConstraintCastNode { class CastVVNode: public ConstraintCastNode { public: - CastVVNode(Node* n, const Type* t, DependencyType dependency = RegularDependency) - : ConstraintCastNode(n, t, dependency){ + CastVVNode(Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + : ConstraintCastNode(n, t, dependency, types) { init_class_id(Class_CastVV); } virtual int Opcode() const; @@ -184,8 +204,8 @@ class CastVVNode: public ConstraintCastNode { // cast pointer to pointer (different type) class CastPPNode: public ConstraintCastNode { public: - CastPPNode (Node *n, const Type *t, DependencyType dependency = RegularDependency) - : ConstraintCastNode(n, t, dependency) { + CastPPNode (Node *n, const Type *t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + : ConstraintCastNode(n, t, dependency, types) { } virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegP; } @@ -195,8 +215,8 @@ class CastPPNode: public ConstraintCastNode { // for _checkcast, cast pointer to pointer (different type), without JOIN, class CheckCastPPNode: public ConstraintCastNode { public: - CheckCastPPNode(Node *c, Node *n, const Type *t, DependencyType dependency = RegularDependency) - : ConstraintCastNode(n, t, dependency) { + CheckCastPPNode(Node *c, Node *n, const Type *t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + : ConstraintCastNode(n, t, dependency, types) { init_class_id(Class_CheckCastPP); init_req(0, c); } diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index fb52b49a0e112..25bc1b011e550 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -2085,10 +2085,12 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { // Add casts to carry the control dependency of the Phi that is // going away Node* cast = nullptr; + const TypeTuple* extra_types = collect_types(phase); if (phi_type->isa_ptr()) { const Type* uin_type = phase->type(uin); if (!phi_type->isa_oopptr() && !uin_type->isa_oopptr()) { - cast = ConstraintCastNode::make_cast(Op_CastPP, r, uin, phi_type, ConstraintCastNode::StrongDependency); + cast = ConstraintCastNode::make_cast(Op_CastPP, r, uin, phi_type, ConstraintCastNode::StrongDependency, + extra_types); } else { // Use a CastPP for a cast to not null and a CheckCastPP for // a cast to a new klass (and both if both null-ness and @@ -2098,7 +2100,8 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { // null, uin's type must be casted to not null if (phi_type->join(TypePtr::NOTNULL) == phi_type->remove_speculative() && uin_type->join(TypePtr::NOTNULL) != uin_type->remove_speculative()) { - cast = ConstraintCastNode::make_cast(Op_CastPP, r, uin, TypePtr::NOTNULL, ConstraintCastNode::StrongDependency); + cast = ConstraintCastNode::make_cast(Op_CastPP, r, uin, TypePtr::NOTNULL, + ConstraintCastNode::StrongDependency, extra_types); } // If the type of phi and uin, both casted to not null, @@ -2110,14 +2113,16 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { cast = phase->transform(cast); n = cast; } - cast = ConstraintCastNode::make_cast(Op_CheckCastPP, r, n, phi_type, ConstraintCastNode::StrongDependency); + cast = ConstraintCastNode::make_cast(Op_CheckCastPP, r, n, phi_type, ConstraintCastNode::StrongDependency, + extra_types); } if (cast == nullptr) { - cast = ConstraintCastNode::make_cast(Op_CastPP, r, uin, phi_type, ConstraintCastNode::StrongDependency); + cast = ConstraintCastNode::make_cast(Op_CastPP, r, uin, phi_type, ConstraintCastNode::StrongDependency, + extra_types); } } } else { - cast = ConstraintCastNode::make_cast_for_type(r, uin, phi_type, ConstraintCastNode::StrongDependency); + cast = ConstraintCastNode::make_cast_for_type(r, uin, phi_type, ConstraintCastNode::StrongDependency, extra_types); } assert(cast != nullptr, "cast should be set"); cast = phase->transform(cast); @@ -2512,6 +2517,52 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { return progress; // Return any progress } +static int compare_types(const Type* const& e1, const Type* const& e2) { + return (intptr_t)e1 - (intptr_t)e2; +} + +// Collect types at casts that are going to be eliminated at that Phi and store them in a TypeTuple. +// Sort the types using an arbitrary order so a list of some types always hashes to the same TypeTuple (and TypeTuple +// pointer comparison is enough to tell if 2 list of types are the same or not) +const TypeTuple* PhiNode::collect_types(PhaseGVN* phase) const { + const Node* region = in(0); + const Type* phi_type = bottom_type(); + ResourceMark rm; + GrowableArray types; + for (uint i = 1; i < req(); i++) { + if (region->in(i) == nullptr || phase->type(region->in(i)) == Type::TOP) { + continue; + } + Node* in = Node::in(i); + const Type* t = phase->type(in); + if (in == nullptr || in == this || t == Type::TOP) { + continue; + } + if (t != phi_type && t->higher_equal_speculative(phi_type)) { + types.insert_sorted(t); + } + while (in != nullptr && in->is_ConstraintCast()) { + Node* next = in->in(1); + if (phase->type(next)->isa_rawptr() && phase->type(in)->isa_oopptr()) { + break; + } + ConstraintCastNode* cast = in->as_ConstraintCast(); + for (int j = 0; j < cast->extra_types_count(); ++j) { + const Type* extra_t = cast->extra_type_at(j); + if (extra_t != phi_type && extra_t->higher_equal_speculative(phi_type)) { + types.insert_sorted(extra_t); + } + } + in = next; + } + } + const Type **flds = (const Type **)(phase->C->type_arena()->AmallocWords(types.length()*sizeof(Type*))); + for (int i = 0; i < types.length(); ++i) { + flds[i] = types.at(i); + } + return TypeTuple::make(types.length(), flds); +} + Node* PhiNode::clone_through_phi(Node* root_phi, const Type* t, uint c, PhaseIterGVN* igvn) { Node_Stack stack(1); VectorSet visited; diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 48f484a346898..d71e7ff758a8e 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -266,6 +266,8 @@ class PhiNode : public TypeNode { #else //ASSERT void verify_adr_type(bool recursive = false) const {} #endif //ASSERT + + const TypeTuple* collect_types(PhaseGVN* phase) const; }; //------------------------------GotoNode--------------------------------------- diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 47e2ebc5b6df1..c9b82face2d25 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -551,28 +551,37 @@ void Compile::print_compile_messages() { #ifndef PRODUCT void Compile::print_ideal_ir(const char* phase_name) { - ttyLocker ttyl; // keep the following output all in one block // This output goes directly to the tty, not the compiler log. // To enable tools to match it up with the compilation activity, // be sure to tag this tty output with the compile ID. - if (xtty != nullptr) { - xtty->head("ideal compile_id='%d'%s compile_phase='%s'", - compile_id(), - is_osr_compilation() ? " compile_kind='osr'" : "", - phase_name); - } + + // Node dumping can cause a safepoint, which can break the tty lock. + // Buffer all node dumps, so that all safepoints happen before we lock. + ResourceMark rm; + stringStream ss; + if (_output == nullptr) { - tty->print_cr("AFTER: %s", phase_name); + ss.print_cr("AFTER: %s", phase_name); // Print out all nodes in ascending order of index. - root()->dump_bfs(MaxNodeLimit, nullptr, "+S$"); + root()->dump_bfs(MaxNodeLimit, nullptr, "+S$", &ss); } else { // Dump the node blockwise if we have a scheduling - _output->print_scheduling(); + _output->print_scheduling(&ss); } + // Check that the lock is not broken by a safepoint. + NoSafepointVerifier nsv; + ttyLocker ttyl; if (xtty != nullptr) { + xtty->head("ideal compile_id='%d'%s compile_phase='%s'", + compile_id(), + is_osr_compilation() ? " compile_kind='osr'" : "", + phase_name); + xtty->print("%s", ss.as_string()); // print to tty would use xml escape encoding xtty->tail("ideal"); + } else { + tty->print("%s", ss.as_string()); } } #endif @@ -826,8 +835,8 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci, // If any phase is randomized for stress testing, seed random number // generation and log the seed for repeatability. - if (StressLCM || StressGCM || StressIGVN || StressCCP) { - if (FLAG_IS_DEFAULT(StressSeed) || (FLAG_IS_ERGO(StressSeed) && RepeatCompilation)) { + if (StressLCM || StressGCM || StressIGVN || StressCCP || StressIncrementalInlining) { + if (FLAG_IS_DEFAULT(StressSeed) || (FLAG_IS_ERGO(StressSeed) && directive->RepeatCompilationOption)) { _stress_seed = static_cast(Ticks::now().nanoseconds()); FLAG_SET_ERGO(StressSeed, _stress_seed); } else { @@ -2230,6 +2239,8 @@ void Compile::Optimize() { process_for_unstable_if_traps(igvn); + if (failing()) return; + inline_incrementally(igvn); print_method(PHASE_INCREMENTAL_INLINE, 2); @@ -2240,7 +2251,9 @@ void Compile::Optimize() { // Inline valueOf() methods now. inline_boxing_calls(igvn); - if (AlwaysIncrementalInline) { + if (failing()) return; + + if (AlwaysIncrementalInline || StressIncrementalInlining) { inline_incrementally(igvn); } @@ -2255,16 +2268,20 @@ void Compile::Optimize() { // CastPP nodes. remove_speculative_types(igvn); + if (failing()) return; + // No more new expensive nodes will be added to the list from here // so keep only the actual candidates for optimizations. cleanup_expensive_nodes(igvn); + if (failing()) return; + assert(EnableVectorSupport || !has_vbox_nodes(), "sanity"); if (EnableVectorSupport && has_vbox_nodes()) { TracePhase tp("", &timers[_t_vector]); PhaseVector pv(igvn); pv.optimize_vector_boxes(); - + if (failing()) return; print_method(PHASE_ITER_GVN_AFTER_VECTOR, 2); } assert(!has_vbox_nodes(), "sanity"); @@ -2284,6 +2301,8 @@ void Compile::Optimize() { // safepoints remove_root_to_sfpts_edges(igvn); + if (failing()) return; + // Perform escape analysis if (do_escape_analysis() && ConnectionGraph::has_candidates(this)) { if (has_loops()) { @@ -2393,6 +2412,8 @@ void Compile::Optimize() { process_for_post_loop_opts_igvn(igvn); + if (failing()) return; + #ifdef ASSERT bs->verify_gc_barriers(this, BarrierSetC2::BeforeMacroExpand); #endif @@ -2431,6 +2452,7 @@ void Compile::Optimize() { // More opportunities to optimize virtual and MH calls. // Though it's maybe too late to perform inlining, strength-reducing them to direct calls is still an option. process_late_inline_calls_no_inline(igvn); + if (failing()) return; } } // (End scope of igvn; run destructor if necessary for asserts.) @@ -4907,6 +4929,7 @@ void Compile::remove_speculative_types(PhaseIterGVN &igvn) { igvn.remove_speculative_types(); if (modified > 0) { igvn.optimize(); + if (failing()) return; } #ifdef ASSERT // Verify that after the IGVN is over no speculative type has resurfaced @@ -4977,8 +5000,8 @@ bool Compile::randomized_select(int count) { CloneMap& Compile::clone_map() { return _clone_map; } void Compile::set_clone_map(Dict* d) { _clone_map._dict = d; } -void NodeCloneInfo::dump() const { - tty->print(" {%d:%d} ", idx(), gen()); +void NodeCloneInfo::dump_on(outputStream* st) const { + st->print(" {%d:%d} ", idx(), gen()); } void CloneMap::clone(Node* old, Node* nnn, int gen) { @@ -5025,11 +5048,11 @@ int CloneMap::max_gen() const { return g; } -void CloneMap::dump(node_idx_t key) const { +void CloneMap::dump(node_idx_t key, outputStream* st) const { uint64_t val = value(key); if (val != 0) { NodeCloneInfo ni(val); - ni.dump(); + ni.dump_on(st); } } diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 52d1ba7e08b16..e5b881065ac7c 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -135,7 +135,7 @@ class NodeCloneInfo { NodeCloneInfo(uint64_t idx_clone_orig) : _idx_clone_orig(idx_clone_orig) {} NodeCloneInfo(node_idx_t x, int g) : _idx_clone_orig(0) { set(x, g); } - void dump() const; + void dump_on(outputStream* st) const; }; class CloneMap { @@ -158,7 +158,7 @@ class CloneMap { int max_gen() const; void clone(Node* old, Node* nnn, int gen); void verify_insert_and_clone(Node* old, Node* nnn, int gen); - void dump(node_idx_t key) const; + void dump(node_idx_t key, outputStream* st) const; int clone_idx() const { return _clone_idx; } void set_clone_idx(int x) { _clone_idx = x; } @@ -1032,6 +1032,7 @@ class Compile : public Phase { bool inline_incrementally_one(); void inline_incrementally_cleanup(PhaseIterGVN& igvn); void inline_incrementally(PhaseIterGVN& igvn); + bool should_delay_inlining() { return AlwaysIncrementalInline || (StressIncrementalInlining && (random() % 2) == 0); } void inline_string_calls(bool parse_time); void inline_boxing_calls(PhaseIterGVN& igvn); bool optimize_loops(PhaseIterGVN& igvn, LoopOptsMode mode); diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp index 2b78d7b3b244c..f7fa5e9d8cc95 100644 --- a/src/hotspot/share/opto/doCall.cpp +++ b/src/hotspot/share/opto/doCall.cpp @@ -172,7 +172,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool // Try inlining a bytecoded method: if (!call_does_dispatch) { InlineTree* ilt = InlineTree::find_subtree_from_root(this->ilt(), jvms->caller(), jvms->method()); - bool should_delay = AlwaysIncrementalInline; + bool should_delay = C->should_delay_inlining(); if (ilt->ok_to_inline(callee, jvms, profile, should_delay)) { CallGenerator* cg = CallGenerator::for_inline(callee, expected_uses); // For optimized virtual calls assert at runtime that receiver object @@ -191,14 +191,14 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool // Delay the inlining of this method to give us the // opportunity to perform some high level optimizations // first. - if (should_delay_string_inlining(callee, jvms)) { + if (should_delay) { + return CallGenerator::for_late_inline(callee, cg); + } else if (should_delay_string_inlining(callee, jvms)) { return CallGenerator::for_string_late_inline(callee, cg); } else if (should_delay_boxing_inlining(callee, jvms)) { return CallGenerator::for_boxing_late_inline(callee, cg); } else if (should_delay_vector_reboxing_inlining(callee, jvms)) { return CallGenerator::for_vector_reboxing_late_inline(callee, cg); - } else if (should_delay) { - return CallGenerator::for_late_inline(callee, cg); } else { return cg; } @@ -983,6 +983,8 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) { if (PrintOpto && WizardMode) { tty->print_cr(" Catching every inline exception bci:%d -> handler_bci:%d", bci(), handler_bci); } + // If this is a backwards branch in the bytecodes, add safepoint + maybe_add_safepoint(handler_bci); merge_exception(handler_bci); // jump to handler return; // No more handling to be done here! } @@ -1014,6 +1016,8 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) { klass->print_name(); tty->cr(); } + // If this is a backwards branch in the bytecodes, add safepoint + maybe_add_safepoint(handler_bci); merge_exception(handler_bci); } set_control(not_subtype_ctrl); diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 30dcf22105989..1c60de9b9d870 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -3728,7 +3728,10 @@ Node* GraphKit::new_instance(Node* klass_node, //-------------------------------new_array------------------------------------- // helper for both newarray and anewarray // The 'length' parameter is (obviously) the length of the array. -// See comments on new_instance for the meaning of the other arguments. +// The optional arguments are for specialized use by intrinsics: +// - If 'return_size_val', report the non-padded array size (sum of header size +// and array body) to the caller. +// - deoptimize_on_exception controls how Java exceptions are handled (rethrow vs deoptimize) Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable) Node* length, // number of array elements int nargs, // number of arguments to push back for uncommon trap @@ -3779,25 +3782,21 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable) // The rounding mask is strength-reduced, if possible. int round_mask = MinObjAlignmentInBytes - 1; Node* header_size = nullptr; - int header_size_min = arrayOopDesc::base_offset_in_bytes(T_BYTE); // (T_BYTE has the weakest alignment and size restrictions...) if (layout_is_con) { int hsize = Klass::layout_helper_header_size(layout_con); int eshift = Klass::layout_helper_log2_element_size(layout_con); - BasicType etype = Klass::layout_helper_element_type(layout_con); if ((round_mask & ~right_n_bits(eshift)) == 0) round_mask = 0; // strength-reduce it if it goes away completely assert((hsize & right_n_bits(eshift)) == 0, "hsize is pre-rounded"); + int header_size_min = arrayOopDesc::base_offset_in_bytes(T_BYTE); assert(header_size_min <= hsize, "generic minimum is smallest"); - header_size_min = hsize; - header_size = intcon(hsize + round_mask); + header_size = intcon(hsize); } else { Node* hss = intcon(Klass::_lh_header_size_shift); Node* hsm = intcon(Klass::_lh_header_size_mask); - Node* hsize = _gvn.transform( new URShiftINode(layout_val, hss) ); - hsize = _gvn.transform( new AndINode(hsize, hsm) ); - Node* mask = intcon(round_mask); - header_size = _gvn.transform( new AddINode(hsize, mask) ); + header_size = _gvn.transform(new URShiftINode(layout_val, hss)); + header_size = _gvn.transform(new AndINode(header_size, hsm)); } Node* elem_shift = nullptr; @@ -3849,25 +3848,30 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable) } #endif - // Combine header size (plus rounding) and body size. Then round down. - // This computation cannot overflow, because it is used only in two - // places, one where the length is sharply limited, and the other - // after a successful allocation. + // Combine header size and body size for the array copy part, then align (if + // necessary) for the allocation part. This computation cannot overflow, + // because it is used only in two places, one where the length is sharply + // limited, and the other after a successful allocation. Node* abody = lengthx; - if (elem_shift != nullptr) - abody = _gvn.transform( new LShiftXNode(lengthx, elem_shift) ); - Node* size = _gvn.transform( new AddXNode(headerx, abody) ); - if (round_mask != 0) { - Node* mask = MakeConX(~round_mask); - size = _gvn.transform( new AndXNode(size, mask) ); + if (elem_shift != nullptr) { + abody = _gvn.transform(new LShiftXNode(lengthx, elem_shift)); } - // else if round_mask == 0, the size computation is self-rounding + Node* non_rounded_size = _gvn.transform(new AddXNode(headerx, abody)); if (return_size_val != nullptr) { // This is the size - (*return_size_val) = size; + (*return_size_val) = non_rounded_size; } + Node* size = non_rounded_size; + if (round_mask != 0) { + Node* mask1 = MakeConX(round_mask); + size = _gvn.transform(new AddXNode(size, mask1)); + Node* mask2 = MakeConX(~round_mask); + size = _gvn.transform(new AndXNode(size, mask2)); + } + // else if round_mask == 0, the size computation is self-rounding + // Now generate allocation code // The entire memory state is needed for slow path of the allocation diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp index b711a5780cf92..92180371c067b 100644 --- a/src/hotspot/share/opto/graphKit.hpp +++ b/src/hotspot/share/opto/graphKit.hpp @@ -82,7 +82,8 @@ class GraphKit : public Phase { #ifdef ASSERT ~GraphKit() { - assert(!has_exceptions(), "user must call transfer_exceptions_into_jvms"); + assert(failing() || !has_exceptions(), + "unless compilation failed, user must call transfer_exceptions_into_jvms"); } #endif diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index ef0c720835631..21b82a7b2c3ca 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -1833,6 +1833,46 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { // then we are guaranteed to fail, so just start interpreting there. // We 'expand' the top 3 range checks to include all post-dominating // checks. + // + // Example: + // a[i+x] // (1) 1 < x < 6 + // a[i+3] // (2) + // a[i+4] // (3) + // a[i+6] // max = max of all constants + // a[i+2] + // a[i+1] // min = min of all constants + // + // If x < 3: + // (1) a[i+x]: Leave unchanged + // (2) a[i+3]: Replace with a[i+max] = a[i+6]: i+x < i+3 <= i+6 -> (2) is covered + // (3) a[i+4]: Replace with a[i+min] = a[i+1]: i+1 < i+4 <= i+6 -> (3) and all following checks are covered + // Remove all other a[i+c] checks + // + // If x >= 3: + // (1) a[i+x]: Leave unchanged + // (2) a[i+3]: Replace with a[i+min] = a[i+1]: i+1 < i+3 <= i+x -> (2) is covered + // (3) a[i+4]: Replace with a[i+max] = a[i+6]: i+1 < i+4 <= i+6 -> (3) and all following checks are covered + // Remove all other a[i+c] checks + // + // We only need the top 2 range checks if x is the min or max of all constants. + // + // This, however, only works if the interval [i+min,i+max] is not larger than max_int (i.e. abs(max - min) < max_int): + // The theoretical max size of an array is max_int with: + // - Valid index space: [0,max_int-1] + // - Invalid index space: [max_int,-1] // max_int, min_int, min_int - 1 ..., -1 + // + // The size of the consecutive valid index space is smaller than the size of the consecutive invalid index space. + // If we choose min and max in such a way that: + // - abs(max - min) < max_int + // - i+max and i+min are inside the valid index space + // then all indices [i+min,i+max] must be in the valid index space. Otherwise, the invalid index space must be + // smaller than the valid index space which is never the case for any array size. + // + // Choosing a smaller array size only makes the valid index space smaller and the invalid index space larger and + // the argument above still holds. + // + // Note that the same optimization with the same maximal accepted interval size can also be found in C1. + const jlong maximum_number_of_min_max_interval_indices = (jlong)max_jint; // The top 3 range checks seen const int NRC = 3; @@ -1867,13 +1907,18 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { found_immediate_dominator = true; break; } - // Gather expanded bounds - off_lo = MIN2(off_lo,offset2); - off_hi = MAX2(off_hi,offset2); - // Record top NRC range checks - prev_checks[nb_checks%NRC].ctl = prev_dom; - prev_checks[nb_checks%NRC].off = offset2; - nb_checks++; + + // "x - y" -> must add one to the difference for number of elements in [x,y] + const jlong diff = (jlong)MIN2(offset2, off_lo) - (jlong)MAX2(offset2, off_hi); + if (ABS(diff) < maximum_number_of_min_max_interval_indices) { + // Gather expanded bounds + off_lo = MIN2(off_lo, offset2); + off_hi = MAX2(off_hi, offset2); + // Record top NRC range checks + prev_checks[nb_checks % NRC].ctl = prev_dom; + prev_checks[nb_checks % NRC].off = offset2; + nb_checks++; + } } } prev_dom = dom; diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index c995a1c6502da..af2ea60959578 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -1108,6 +1108,7 @@ bool LibraryCallKit::inline_countPositives() { Node* ba_start = array_element_address(ba, offset, T_BYTE); Node* result = new CountPositivesNode(control(), memory(TypeAryPtr::BYTES), ba_start, len); set_result(_gvn.transform(result)); + clear_upper_avx(); return true; } @@ -1362,6 +1363,7 @@ bool LibraryCallKit::inline_string_indexOfChar(StrIntrinsicNode::ArgEnc ae) { set_control(_gvn.transform(region)); record_for_igvn(region); set_result(_gvn.transform(phi)); + clear_upper_avx(); return true; } @@ -2864,6 +2866,7 @@ bool LibraryCallKit::inline_native_notify_jvmti_funcs(address funcAddr, const ch if (!DoJVMTIVirtualThreadTransitions) { return true; } + Node* vt_oop = _gvn.transform(must_be_not_null(argument(0), true)); // VirtualThread this argument IdealKit ideal(this); Node* ONE = ideal.ConI(1); @@ -2872,16 +2875,13 @@ bool LibraryCallKit::inline_native_notify_jvmti_funcs(address funcAddr, const ch Node* notify_jvmti_enabled = ideal.load(ideal.ctrl(), addr, TypeInt::BOOL, T_BOOLEAN, Compile::AliasIdxRaw); ideal.if_then(notify_jvmti_enabled, BoolTest::eq, ONE); { + sync_kit(ideal); // if notifyJvmti enabled then make a call to the given SharedRuntime function const TypeFunc* tf = OptoRuntime::notify_jvmti_vthread_Type(); - Node* vt_oop = _gvn.transform(must_be_not_null(argument(0), true)); // VirtualThread this argument - - sync_kit(ideal); make_runtime_call(RC_NO_LEAF, tf, funcAddr, funcName, TypePtr::BOTTOM, vt_oop, hide); ideal.sync_kit(this); } ideal.else_(); { // set hide value to the VTMS transition bit in current JavaThread and VirtualThread object - Node* vt_oop = _gvn.transform(argument(0)); // this argument - VirtualThread oop Node* thread = ideal.thread(); Node* jt_addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_VTMS_transition_offset())); Node* vt_addr = basic_plus_adr(vt_oop, java_lang_Thread::is_in_VTMS_transition_offset()); @@ -3586,12 +3586,19 @@ bool LibraryCallKit::inline_native_setCurrentThread() { return true; } -Node* LibraryCallKit::scopedValueCache_helper() { - ciKlass *objects_klass = ciObjArrayKlass::make(env()->Object_klass()); - const TypeOopPtr *etype = TypeOopPtr::make_from_klass(env()->Object_klass()); +const Type* LibraryCallKit::scopedValueCache_type() { + ciKlass* objects_klass = ciObjArrayKlass::make(env()->Object_klass()); + const TypeOopPtr* etype = TypeOopPtr::make_from_klass(env()->Object_klass()); + const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS); + // Because we create the scopedValue cache lazily we have to make the + // type of the result BotPTR. bool xk = etype->klass_is_exact(); + const Type* objects_type = TypeAryPtr::make(TypePtr::BotPTR, arr0, objects_klass, xk, 0); + return objects_type; +} +Node* LibraryCallKit::scopedValueCache_helper() { Node* thread = _gvn.transform(new ThreadLocalNode()); Node* p = basic_plus_adr(top()/*!oop*/, thread, in_bytes(JavaThread::scopedValueCache_offset())); // We cannot use immutable_memory() because we might flip onto a @@ -3604,15 +3611,8 @@ Node* LibraryCallKit::scopedValueCache_helper() { //------------------------inline_native_scopedValueCache------------------ bool LibraryCallKit::inline_native_scopedValueCache() { - ciKlass *objects_klass = ciObjArrayKlass::make(env()->Object_klass()); - const TypeOopPtr *etype = TypeOopPtr::make_from_klass(env()->Object_klass()); - const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS); - - // Because we create the scopedValue cache lazily we have to make the - // type of the result BotPTR. - bool xk = etype->klass_is_exact(); - const Type* objects_type = TypeAryPtr::make(TypePtr::BotPTR, arr0, objects_klass, xk, 0); Node* cache_obj_handle = scopedValueCache_helper(); + const Type* objects_type = scopedValueCache_type(); set_result(access_load(cache_obj_handle, objects_type, T_OBJECT, IN_NATIVE)); return true; @@ -3622,9 +3622,10 @@ bool LibraryCallKit::inline_native_scopedValueCache() { bool LibraryCallKit::inline_native_setScopedValueCache() { Node* arr = argument(0); Node* cache_obj_handle = scopedValueCache_helper(); + const Type* objects_type = scopedValueCache_type(); const TypePtr *adr_type = _gvn.type(cache_obj_handle)->isa_ptr(); - access_store_at(nullptr, cache_obj_handle, adr_type, arr, _gvn.type(arr), T_OBJECT, IN_NATIVE | MO_UNORDERED); + access_store_at(nullptr, cache_obj_handle, adr_type, arr, objects_type, T_OBJECT, IN_NATIVE | MO_UNORDERED); return true; } @@ -4993,8 +4994,8 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) { PreserveJVMState pjvms(this); set_control(array_ctl); Node* obj_length = load_array_length(obj); - Node* obj_size = nullptr; - Node* alloc_obj = new_array(obj_klass, obj_length, 0, &obj_size, /*deoptimize_on_exception=*/true); + Node* array_size = nullptr; // Size of the array without object alignment padding. + Node* alloc_obj = new_array(obj_klass, obj_length, 0, &array_size, /*deoptimize_on_exception=*/true); BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); if (bs->array_copy_requires_gc_barriers(true, T_OBJECT, true, false, BarrierSetC2::Parsing)) { @@ -5027,7 +5028,7 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) { // the object.) if (!stopped()) { - copy_to_clone(obj, alloc_obj, obj_size, true); + copy_to_clone(obj, alloc_obj, array_size, true); // Present the results of the copy. result_reg->init_req(_array_path, control()); @@ -5067,7 +5068,7 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) { if (!stopped()) { // It's an instance, and it passed the slow-path tests. PreserveJVMState pjvms(this); - Node* obj_size = nullptr; + Node* obj_size = nullptr; // Total object size, including object alignment padding. // Need to deoptimize on exception from allocation since Object.clone intrinsic // is reexecuted if deoptimization occurs and there could be problems when merging // exception state between multiple Object.clone versions (reexecute=true vs reexecute=false). diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index d4d6e50b2a576..f714625a4df47 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -237,6 +237,7 @@ class LibraryCallKit : public GraphKit { bool inline_native_setCurrentThread(); bool inline_native_scopedValueCache(); + const Type* scopedValueCache_type(); Node* scopedValueCache_helper(); bool inline_native_setScopedValueCache(); diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index ab0a7eb1089e3..9ae24cb205556 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -1035,9 +1035,10 @@ BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree* loop, Node* ctrl, int scal // Check if (scale * max_idx_expr) may overflow const TypeInt* scale_type = TypeInt::make(scale); MulINode* mul = new MulINode(max_idx_expr, con_scale); - idx_type = (TypeInt*)mul->mul_ring(idx_type, scale_type); - if (overflow || TypeInt::INT->higher_equal(idx_type)) { + + if (overflow || MulINode::does_overflow(idx_type, scale_type)) { // May overflow + idx_type = TypeInt::INT; mul->destruct(&_igvn); if (!overflow) { max_idx_expr = new ConvI2LNode(max_idx_expr); @@ -1050,6 +1051,7 @@ BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree* loop, Node* ctrl, int scal } else { // No overflow possible max_idx_expr = mul; + idx_type = (TypeInt*)mul->mul_ring(idx_type, scale_type); } register_new_node(max_idx_expr, ctrl); } diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 7c3f5841f3f51..bc1140d4673e6 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -1965,6 +1965,9 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, post_head->set_normal_loop(); post_head->set_post_loop(main_head); + // clone_loop() above changes the exit projection + main_exit = outer_main_end->proj_out(false); + // Reduce the post-loop trip count. CountedLoopEndNode* post_end = old_new[main_end->_idx]->as_CountedLoopEnd(); post_end->_prob = PROB_FAIR; @@ -3003,6 +3006,8 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { continue; // Don't rce this check but continue looking for other candidates. } + assert(is_dominator(compute_early_ctrl(limit, limit_c), pre_end), "node pinned on loop exit test?"); + // Check for scaled induction variable plus an offset Node *offset = nullptr; @@ -3021,6 +3026,8 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { if (is_dominator(ctrl, offset_c)) { continue; // Don't rce this check but continue looking for other candidates. } + + assert(is_dominator(compute_early_ctrl(offset, offset_c), pre_end), "node pinned on loop exit test?"); #ifdef ASSERT if (TraceRangeLimitCheck) { tty->print_cr("RC bool node%s", flip ? " flipped:" : ":"); @@ -3703,7 +3710,7 @@ void IdealLoopTree::enqueue_data_nodes(PhaseIdealLoop* phase, Unique_Node_List& void IdealLoopTree::collect_loop_core_nodes(PhaseIdealLoop* phase, Unique_Node_List& wq) const { uint before = wq.size(); wq.push(_head->in(LoopNode::LoopBackControl)); - for (uint i = 0; i < wq.size(); ++i) { + for (uint i = before; i < wq.size(); ++i) { Node* n = wq.at(i); for (uint j = 0; j < n->req(); ++j) { Node* in = n->in(j); diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index f84c4100d8eb3..e102d9ac9e9b7 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -493,19 +493,19 @@ PhiNode* PhaseIdealLoop::loop_iv_phi(Node* xphi, Node* phi_incr, Node* x, IdealL return phi; } -static int check_stride_overflow(jlong stride_con, const TypeInteger* limit_t, BasicType bt) { - if (stride_con > 0) { - if (limit_t->lo_as_long() > (max_signed_integer(bt) - stride_con)) { +static int check_stride_overflow(jlong final_correction, const TypeInteger* limit_t, BasicType bt) { + if (final_correction > 0) { + if (limit_t->lo_as_long() > (max_signed_integer(bt) - final_correction)) { return -1; } - if (limit_t->hi_as_long() > (max_signed_integer(bt) - stride_con)) { + if (limit_t->hi_as_long() > (max_signed_integer(bt) - final_correction)) { return 1; } } else { - if (limit_t->hi_as_long() < (min_signed_integer(bt) - stride_con)) { + if (limit_t->hi_as_long() < (min_signed_integer(bt) - final_correction)) { return -1; } - if (limit_t->lo_as_long() < (min_signed_integer(bt) - stride_con)) { + if (limit_t->lo_as_long() < (min_signed_integer(bt) - final_correction)) { return 1; } } @@ -767,7 +767,7 @@ SafePointNode* PhaseIdealLoop::find_safepoint(Node* back_control, Node* x, Ideal // // inner_incr := AddI(inner_phi, intcon(stride)) // inner_incr = inner_phi + stride; // if (inner_incr < inner_iters_actual) { -// ... use phi=>(outer_phi+inner_phi) and incr=>(outer_phi+inner_incr) ... +// ... use phi=>(outer_phi+inner_phi) ... // continue; // } // else break; @@ -977,10 +977,6 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { // loop iv phi Node* iv_add = loop_nest_replace_iv(phi, inner_phi, outer_phi, head, bt); - // Replace inner loop long iv incr with inner loop int incr + outer - // loop iv phi - loop_nest_replace_iv(incr, inner_incr, outer_phi, head, bt); - set_subtree_ctrl(inner_iters_actual_int, body_populated); LoopNode* inner_head = create_inner_head(loop, head, exit_test); @@ -1029,7 +1025,7 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { // back_control: fallthrough; // else // inner_exit_branch: break; //exit_branch->clone() - // ... use phi=>(outer_phi+inner_phi) and incr=>(outer_phi+inner_incr) ... + // ... use phi=>(outer_phi+inner_phi) ... // inner_phi = inner_phi + stride; // inner_incr // } // outer_exit_test: //exit_test->clone(), in(0):=inner_exit_branch @@ -1749,50 +1745,205 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ C->print_method(PHASE_BEFORE_CLOOPS, 3); // =================================================== - // Generate loop limit check to avoid integer overflow - // in cases like next (cyclic loops): + // We can only convert this loop to a counted loop if we can guarantee that the iv phi will never overflow at runtime. + // This is an implicit assumption taken by some loop optimizations. We therefore must ensure this property at all cost. + // At this point, we've already excluded some trivial cases where an overflow could have been proven statically. + // But even though we cannot prove that an overflow will *not* happen, we still want to speculatively convert this loop + // to a counted loop. This can be achieved by adding additional iv phi overflow checks before the loop. If they fail, + // we trap and resume execution before the loop without having executed any iteration of the loop, yet. + // + // These additional iv phi overflow checks can be inserted as Loop Limit Check Predicates above the Loop Limit Check + // Parse Predicate which captures a JVM state just before the entry of the loop. If there is no such Parse Predicate, + // we cannot generate a Loop Limit Check Predicate and thus cannot speculatively convert the loop to a counted loop. + // + // In the following, we only focus on int loops with stride > 0 to keep things simple. The argumentation and proof + // for stride < 0 is analogously. For long loops, we would replace max_int with max_long. + // + // + // The loop to be converted does not always need to have the often used shape: + // + // i = init + // i = init loop: + // do { ... + // // ... equivalent i+=stride + // i+=stride <==> if (i < limit) + // } while (i < limit); goto loop + // exit: + // ... + // + // where the loop exit check uses the post-incremented iv phi and a '<'-operator. + // + // We could also have '<='-operator (or '>='-operator for negative strides) or use the pre-incremented iv phi value + // in the loop exit check: + // + // i = init + // loop: + // ... + // if (i <= limit) + // i+=stride + // goto loop + // exit: + // ... + // + // Let's define the following terms: + // - iv_pre_i: The pre-incremented iv phi before the i-th iteration. + // - iv_post_i: The post-incremented iv phi after the i-th iteration. + // + // The iv_pre_i and iv_post_i have the following relation: + // iv_pre_i + stride = iv_post_i + // + // When converting a loop to a counted loop, we want to have a canonicalized loop exit check of the form: + // iv_post_i < adjusted_limit + // + // If that is not the case, we need to canonicalize the loop exit check by using different values for adjusted_limit: + // (LE1) iv_post_i < limit: Already canonicalized. We can directly use limit as adjusted_limit. + // -> adjusted_limit = limit. + // (LE2) iv_post_i <= limit: + // iv_post_i < limit + 1 + // -> adjusted limit = limit + 1 + // (LE3) iv_pre_i < limit: + // iv_pre_i + stride < limit + stride + // iv_post_i < limit + stride + // -> adjusted_limit = limit + stride + // (LE4) iv_pre_i <= limit: + // iv_pre_i < limit + 1 + // iv_pre_i + stride < limit + stride + 1 + // iv_post_i < limit + stride + 1 + // -> adjusted_limit = limit + stride + 1 + // + // Note that: + // (AL) limit <= adjusted_limit. + // + // The following loop invariant has to hold for counted loops with n iterations (i.e. loop exit check true after n-th + // loop iteration) and a canonicalized loop exit check to guarantee that no iv_post_i over- or underflows: + // (INV) For i = 1..n, min_int <= iv_post_i <= max_int + // + // To prove (INV), we require the following two conditions/assumptions: + // (i): adjusted_limit - 1 + stride <= max_int + // (ii): init < limit + // + // If we can prove (INV), we know that there can be no over- or underflow of any iv phi value. We prove (INV) by + // induction by assuming (i) and (ii). + // + // Proof by Induction + // ------------------ + // > Base case (i = 1): We show that (INV) holds after the first iteration: + // min_int <= iv_post_1 = init + stride <= max_int + // Proof: + // First, we note that (ii) implies + // (iii) init <= limit - 1 + // max_int >= adjusted_limit - 1 + stride [using (i)] + // >= limit - 1 + stride [using (AL)] + // >= init + stride [using (iii)] + // >= min_int [using stride > 0, no underflow] + // Thus, no overflow happens after the first iteration and (INV) holds for i = 1. + // + // Note that to prove the base case we need (i) and (ii). + // + // > Induction Hypothesis (i = j, j > 1): Assume that (INV) holds after the j-th iteration: + // min_int <= iv_post_j <= max_int + // > Step case (i = j + 1): We show that (INV) also holds after the j+1-th iteration: + // min_int <= iv_post_{j+1} = iv_post_j + stride <= max_int + // Proof: + // If iv_post_j >= adjusted_limit: + // We exit the loop after the j-th iteration, and we don't execute the j+1-th iteration anymore. Thus, there is + // also no iv_{j+1}. Since (INV) holds for iv_j, there is nothing left to prove. + // If iv_post_j < adjusted_limit: + // First, we note that: + // (iv) iv_post_j <= adjusted_limit - 1 + // max_int >= adjusted_limit - 1 + stride [using (i)] + // >= iv_post_j + stride [using (iv)] + // >= min_int [using stride > 0, no underflow] // - // for (i=0; i <= max_jint; i++) {} - // for (i=0; i < max_jint; i+=2) {} + // Note that to prove the step case we only need (i). // + // Thus, by assuming (i) and (ii), we proved (INV). // - // Limit check predicate depends on the loop test: // - // for(;i != limit; i++) --> limit <= (max_jint) - // for(;i < limit; i+=stride) --> limit <= (max_jint - stride + 1) - // for(;i <= limit; i+=stride) --> limit <= (max_jint - stride ) + // It is therefore enough to add the following two Loop Limit Check Predicates to check assumptions (i) and (ii): // + // (1) Loop Limit Check Predicate for (i): + // Using (i): adjusted_limit - 1 + stride <= max_int + // + // This condition is now restated to use limit instead of adjusted_limit: + // + // To prevent an overflow of adjusted_limit -1 + stride itself, we rewrite this check to + // max_int - stride + 1 >= adjusted_limit + // We can merge the two constants into + // canonicalized_correction = stride - 1 + // which gives us + // max_int - canonicalized_correction >= adjusted_limit + // + // To directly use limit instead of adjusted_limit in the predicate condition, we split adjusted_limit into: + // adjusted_limit = limit + limit_correction + // Since stride > 0 and limit_correction <= stride + 1, we can restate this with no over- or underflow into: + // max_int - canonicalized_correction - limit_correction >= limit + // Since canonicalized_correction and limit_correction are both constants, we can replace them with a new constant: + // final_correction = canonicalized_correction + limit_correction + // which gives us: + // + // Final predicate condition: + // max_int - final_correction >= limit + // + // (2) Loop Limit Check Predicate for (ii): + // Using (ii): init < limit + // + // This Loop Limit Check Predicate is not required if we can prove at compile time that either: + // (2.1) type(init) < type(limit) + // In this case, we know: + // all possible values of init < all possible values of limit + // and we can skip the predicate. + // + // (2.2) init < limit is already checked before (i.e. found as a dominating check) + // In this case, we do not need to re-check the condition and can skip the predicate. + // This is often found for while- and for-loops which have the following shape: + // + // if (init < limit) { // Dominating test. Do not need the Loop Limit Check Predicate below. + // i = init; + // if (init >= limit) { trap(); } // Here we would insert the Loop Limit Check Predicate + // do { + // i += stride; + // } while (i < limit); + // } + // + // (2.3) init + stride <= max_int + // In this case, there is no overflow of the iv phi after the first loop iteration. + // In the proof of the base case above we showed that init + stride <= max_int by using assumption (ii): + // init < limit + // In the proof of the step case above, we did not need (ii) anymore. Therefore, if we already know at + // compile time that init + stride <= max_int then we have trivially proven the base case and that + // there is no overflow of the iv phi after the first iteration. In this case, we don't need to check (ii) + // again and can skip the predicate. - // Check if limit is excluded to do more precise int overflow check. - bool incl_limit = (bt == BoolTest::le || bt == BoolTest::ge); - jlong stride_m = stride_con - (incl_limit ? 0 : (stride_con > 0 ? 1 : -1)); - // If compare points directly to the phi we need to adjust - // the compare so that it points to the incr. Limit have - // to be adjusted to keep trip count the same and the - // adjusted limit should be checked for int overflow. - Node* adjusted_limit = limit; - if (phi_incr != nullptr) { - stride_m += stride_con; - } + // Accounting for (LE3) and (LE4) where we use pre-incremented phis in the loop exit check. + const jlong limit_correction_for_pre_iv_exit_check = (phi_incr != nullptr) ? stride_con : 0; - Node *init_control = x->in(LoopNode::EntryControl); + // Accounting for (LE2) and (LE4) where we use <= or >= in the loop exit check. + const bool includes_limit = (bt == BoolTest::le || bt == BoolTest::ge); + const jlong limit_correction_for_le_ge_exit_check = (includes_limit ? (stride_con > 0 ? 1 : -1) : 0); + + const jlong limit_correction = limit_correction_for_pre_iv_exit_check + limit_correction_for_le_ge_exit_check; + const jlong canonicalized_correction = stride_con + (stride_con > 0 ? -1 : 1); + const jlong final_correction = canonicalized_correction + limit_correction; + + int sov = check_stride_overflow(final_correction, limit_t, iv_bt); + Node* init_control = x->in(LoopNode::EntryControl); - int sov = check_stride_overflow(stride_m, limit_t, iv_bt); // If sov==0, limit's type always satisfies the condition, for // example, when it is an array length. if (sov != 0) { if (sov < 0) { return false; // Bailout: integer overflow is certain. } + // (1) Loop Limit Check Predicate is required because we could not statically prove that + // limit + final_correction = adjusted_limit - 1 + stride <= max_int assert(!x->as_Loop()->is_loop_nest_inner_loop(), "loop was transformed"); - // Generate loop's limit check. - // Loop limit check predicate should be near the loop. if (!ParsePredicates::is_loop_limit_check_predicate_proj(init_control)) { - // The limit check predicate is not generated if this method trapped here before. + // The Loop Limit Check Parse Predicate is not generated if this method trapped here before. #ifdef ASSERT if (TraceLoopLimitCheck) { - tty->print("missing loop limit check:"); + tty->print("Missing Loop Limit Check Parse Predicate:"); loop->dump_head(); x->dump(1); } @@ -1811,65 +1962,79 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ Node* bol; if (stride_con > 0) { - cmp_limit = CmpNode::make(limit, _igvn.integercon(max_signed_integer(iv_bt) - stride_m, iv_bt), iv_bt); + cmp_limit = CmpNode::make(limit, _igvn.integercon(max_signed_integer(iv_bt) - final_correction, iv_bt), iv_bt); bol = new BoolNode(cmp_limit, BoolTest::le); } else { - cmp_limit = CmpNode::make(limit, _igvn.integercon(min_signed_integer(iv_bt) - stride_m, iv_bt), iv_bt); + cmp_limit = CmpNode::make(limit, _igvn.integercon(min_signed_integer(iv_bt) - final_correction, iv_bt), iv_bt); bol = new BoolNode(cmp_limit, BoolTest::ge); } insert_loop_limit_check_predicate(loop_limit_check_parse_predicate_proj, cmp_limit, bol); } - // Now we need to canonicalize loop condition. - if (bt == BoolTest::ne) { - assert(stride_con == 1 || stride_con == -1, "simple increment only"); - if (stride_con > 0 && init_t->hi_as_long() < limit_t->lo_as_long()) { - // 'ne' can be replaced with 'lt' only when init < limit. - bt = BoolTest::lt; - } else if (stride_con < 0 && init_t->lo_as_long() > limit_t->hi_as_long()) { - // 'ne' can be replaced with 'gt' only when init > limit. - bt = BoolTest::gt; - } else { - if (!ParsePredicates::is_loop_limit_check_predicate_proj(init_control)) { - // The limit check predicate is not generated if this method trapped here before. + // (2.3) + const bool init_plus_stride_could_overflow = + (stride_con > 0 && init_t->hi_as_long() > max_signed_integer(iv_bt) - stride_con) || + (stride_con < 0 && init_t->lo_as_long() < min_signed_integer(iv_bt) - stride_con); + // (2.1) + const bool init_gte_limit = (stride_con > 0 && init_t->hi_as_long() >= limit_t->lo_as_long()) || + (stride_con < 0 && init_t->lo_as_long() <= limit_t->hi_as_long()); + + if (init_gte_limit && // (2.1) + ((bt == BoolTest::ne || init_plus_stride_could_overflow) && // (2.3) + !has_dominating_loop_limit_check(init_trip, limit, stride_con, iv_bt, init_control))) { // (2.2) + // (2) Iteration Loop Limit Check Predicate is required because neither (2.1), (2.2), nor (2.3) holds. + // We use the following condition: + // - stride > 0: init < limit + // - stride < 0: init > limit + // + // This predicate is always required if we have a non-equal-operator in the loop exit check (where stride = 1 is + // a requirement). We transform the loop exit check by using a less-than-operator. By doing so, we must always + // check that init < limit. Otherwise, we could have a different number of iterations at runtime. + + if (!ParsePredicates::is_loop_limit_check_predicate_proj(init_control)) { + // The Loop Limit Check Parse Predicate is not generated if this method trapped here before. #ifdef ASSERT - if (TraceLoopLimitCheck) { - tty->print("missing loop limit check:"); - loop->dump_head(); - x->dump(1); - } -#endif - return false; + if (TraceLoopLimitCheck) { + tty->print("Missing Loop Limit Check Parse Predicate:"); + loop->dump_head(); + x->dump(1); } - ParsePredicateSuccessProj* loop_limit_check_parse_predicate_proj = init_control->as_IfTrue(); - ParsePredicateNode* parse_predicate = init_control->in(0)->as_ParsePredicate(); +#endif + return false; + } + ParsePredicateSuccessProj* loop_limit_check_parse_predicate_proj = init_control->as_IfTrue(); + ParsePredicateNode* parse_predicate = init_control->in(0)->as_ParsePredicate(); - if (!is_dominator(get_ctrl(limit), parse_predicate->in(0)) || - !is_dominator(get_ctrl(init_trip), parse_predicate->in(0))) { - return false; - } + if (!is_dominator(get_ctrl(limit), parse_predicate->in(0)) || + !is_dominator(get_ctrl(init_trip), parse_predicate->in(0))) { + return false; + } - Node* cmp_limit; - Node* bol; + Node* cmp_limit; + Node* bol; - if (stride_con > 0) { - cmp_limit = CmpNode::make(init_trip, limit, iv_bt); - bol = new BoolNode(cmp_limit, BoolTest::lt); - } else { - cmp_limit = CmpNode::make(init_trip, limit, iv_bt); - bol = new BoolNode(cmp_limit, BoolTest::gt); - } + if (stride_con > 0) { + cmp_limit = CmpNode::make(init_trip, limit, iv_bt); + bol = new BoolNode(cmp_limit, BoolTest::lt); + } else { + cmp_limit = CmpNode::make(init_trip, limit, iv_bt); + bol = new BoolNode(cmp_limit, BoolTest::gt); + } - insert_loop_limit_check_predicate(loop_limit_check_parse_predicate_proj, cmp_limit, bol); + insert_loop_limit_check_predicate(loop_limit_check_parse_predicate_proj, cmp_limit, bol); + } - if (stride_con > 0) { - // 'ne' can be replaced with 'lt' only when init < limit. - bt = BoolTest::lt; - } else if (stride_con < 0) { - // 'ne' can be replaced with 'gt' only when init > limit. - bt = BoolTest::gt; - } + if (bt == BoolTest::ne) { + // Now we need to canonicalize the loop condition if it is 'ne'. + assert(stride_con == 1 || stride_con == -1, "simple increment only - checked before"); + if (stride_con > 0) { + // 'ne' can be replaced with 'lt' only when init < limit. This is ensured by the inserted predicate above. + bt = BoolTest::lt; + } else { + assert(stride_con < 0, "must be"); + // 'ne' can be replaced with 'gt' only when init > limit. This is ensured by the inserted predicate above. + bt = BoolTest::gt; } } @@ -1914,6 +2079,7 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ } #endif + Node* adjusted_limit = limit; if (phi_incr != nullptr) { // If compare points directly to the phi we need to adjust // the compare so that it points to the incr. Limit have @@ -1927,7 +2093,7 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ adjusted_limit = gvn->transform(AddNode::make(limit, stride, iv_bt)); } - if (incl_limit) { + if (includes_limit) { // The limit check guaranties that 'limit <= (max_jint - stride)' so // we can convert 'i <= limit' to 'i < limit+1' since stride != 0. // @@ -2108,6 +2274,37 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ return true; } +// Check if there is a dominating loop limit check of the form 'init < limit' starting at the loop entry. +// If there is one, then we do not need to create an additional Loop Limit Check Predicate. +bool PhaseIdealLoop::has_dominating_loop_limit_check(Node* init_trip, Node* limit, const jlong stride_con, + const BasicType iv_bt, Node* loop_entry) { + // Eagerly call transform() on the Cmp and Bool node to common them up if possible. This is required in order to + // successfully find a dominated test with the If node below. + Node* cmp_limit; + Node* bol; + if (stride_con > 0) { + cmp_limit = _igvn.transform(CmpNode::make(init_trip, limit, iv_bt)); + bol = _igvn.transform(new BoolNode(cmp_limit, BoolTest::lt)); + } else { + cmp_limit = _igvn.transform(CmpNode::make(init_trip, limit, iv_bt)); + bol = _igvn.transform(new BoolNode(cmp_limit, BoolTest::gt)); + } + + // Check if there is already a dominating init < limit check. If so, we do not need a Loop Limit Check Predicate. + IfNode* iff = new IfNode(loop_entry, bol, PROB_MIN, COUNT_UNKNOWN); + // Also add fake IfProj nodes in order to call transform() on the newly created IfNode. + IfFalseNode* if_false = new IfFalseNode(iff); + IfTrueNode* if_true = new IfTrueNode(iff); + Node* dominated_iff = _igvn.transform(iff); + // ConI node? Found dominating test (IfNode::dominated_by() returns a ConI node). + const bool found_dominating_test = dominated_iff != nullptr && dominated_iff->is_ConI(); + + // Kill the If with its projections again in the next IGVN round by cutting it off from the graph. + _igvn.replace_input_of(iff, 0, C->top()); + _igvn.replace_input_of(iff, 1, C->top()); + return found_dominating_test; +} + //----------------------exact_limit------------------------------------------- Node* PhaseIdealLoop::exact_limit( IdealLoopTree *loop ) { assert(loop->_head->is_CountedLoop(), ""); @@ -4448,6 +4645,7 @@ void PhaseIdealLoop::build_and_optimize() { NOT_PRODUCT( C->verify_graph_edges(); ) worklist.push(C->top()); build_loop_late( visited, worklist, nstack ); + if (C->failing()) { return; } if (_verify_only) { C->restore_major_progress(old_progress); @@ -4702,6 +4900,7 @@ void PhaseIdealLoop::verify() const { bool success = true; PhaseIdealLoop phase_verify(_igvn, this); + if (C->failing()) return; // Verify ctrl and idom of every node. success &= verify_idom_and_nodes(C->root(), &phase_verify); @@ -5954,6 +6153,7 @@ void PhaseIdealLoop::build_loop_late( VectorSet &visited, Node_List &worklist, N } else { // All of n's children have been processed, complete post-processing. build_loop_late_post(n); + if (C->failing()) { return; } if (nstack.is_empty()) { // Finished all nodes on stack. // Process next node on the worklist. @@ -6100,13 +6300,15 @@ void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) { Node *legal = LCA; // Walk 'legal' up the IDOM chain Node *least = legal; // Best legal position so far while( early != legal ) { // While not at earliest legal -#ifdef ASSERT if (legal->is_Start() && !early->is_Root()) { +#ifdef ASSERT // Bad graph. Print idom path and fail. dump_bad_graph("Bad graph detected in build_loop_late", n, early, LCA); assert(false, "Bad graph detected in build_loop_late"); - } #endif + C->record_method_not_compilable("Bad graph detected in build_loop_late"); + return; + } // Find least loop nesting depth legal = idom(legal); // Bump up the IDOM tree // Check for lower nesting depth diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 70c403d30a5f8..6d44434d71ecc 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1115,6 +1115,7 @@ class PhaseIdealLoop : public PhaseTransform { // Compute the Ideal Node to Loop mapping PhaseIdealLoop(PhaseIterGVN& igvn, LoopOptsMode mode) : PhaseTransform(Ideal_Loop), + _loop_or_ctrl(igvn.C->comp_arena()), _igvn(igvn), _verify_me(nullptr), _verify_only(false), @@ -1129,6 +1130,7 @@ class PhaseIdealLoop : public PhaseTransform { // or only verify that the graph is valid if verify_me is null. PhaseIdealLoop(PhaseIterGVN& igvn, const PhaseIdealLoop* verify_me = nullptr) : PhaseTransform(Ideal_Loop), + _loop_or_ctrl(igvn.C->comp_arena()), _igvn(igvn), _verify_me(verify_me), _verify_only(verify_me == nullptr), @@ -1206,7 +1208,7 @@ class PhaseIdealLoop : public PhaseTransform { if (!C->failing()) { // Cleanup any modified bits igvn.optimize(); - + if (C->failing()) { return; } v.log_loop_tree(); } } @@ -1361,6 +1363,8 @@ class PhaseIdealLoop : public PhaseTransform { void rewire_cloned_nodes_to_ctrl(const ProjNode* old_ctrl, Node* new_ctrl, const Node_List& nodes_with_same_ctrl, const Dict& old_new_mapping); void rewire_inputs_of_clones_to_clones(Node* new_ctrl, Node* clone, const Dict& old_new_mapping, const Node* next); + bool has_dominating_loop_limit_check(Node* init_trip, Node* limit, jlong stride_con, BasicType iv_bt, + Node* loop_entry); public: void register_control(Node* n, IdealLoopTree *loop, Node* pred, bool update_body = true); @@ -1549,7 +1553,7 @@ class PhaseIdealLoop : public PhaseTransform { Node *find_use_block( Node *use, Node *def, Node *old_false, Node *new_false, Node *old_true, Node *new_true ); void handle_use( Node *use, Node *def, small_cache *cache, Node *region_dom, Node *new_false, Node *new_true, Node *old_false, Node *old_true ); bool split_up( Node *n, Node *blk1, Node *blk2 ); - void sink_use( Node *use, Node *post_loop ); + Node* place_outside_loop(Node* useblock, IdealLoopTree* loop) const; Node* try_move_store_before_loop(Node* n, Node *n_ctrl); void try_move_store_after_loop(Node* n); @@ -1737,6 +1741,8 @@ class PhaseIdealLoop : public PhaseTransform { bool clone_cmp_loadklass_down(Node* n, const Node* blk1, const Node* blk2); bool at_relevant_ctrl(Node* n, const Node* blk1, const Node* blk2); + + void update_addp_chain_base(Node* x, Node* old_base, Node* new_base); }; diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index e9cbdb224571a..be2ec7dbc0727 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -237,7 +237,11 @@ bool PhaseIdealLoop::cannot_split_division(const Node* n, const Node* region) co return false; } - assert(n->in(0) == nullptr, "divisions with zero check should already have bailed out earlier in split-if"); + if (n->in(0) != nullptr) { + // Cannot split through phi if Div or Mod node has a control dependency to a zero check. + return true; + } + Node* divisor = n->in(2); return is_divisor_counted_loop_phi(divisor, region) && loop_phi_backedge_type_contains_zero(divisor, zero); @@ -1642,7 +1646,7 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { // Find control for 'x' next to use but not inside inner loops. x_ctrl = place_outside_loop(x_ctrl, n_loop); // Replace all uses - if (u->is_ConstraintCast() && u->bottom_type()->higher_equal(_igvn.type(n)) && u->in(0) == x_ctrl) { + if (u->is_ConstraintCast() && _igvn.type(n)->higher_equal(u->bottom_type()) && u->in(0) == x_ctrl) { // If we're sinking a chain of data nodes, we might have inserted a cast to pin the use which is not necessary // anymore now that we're going to pin n as well _igvn.replace_node(u, x); @@ -1677,9 +1681,10 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { assert(!n_loop->is_member(get_loop(x_ctrl)), "should have moved out of loop"); register_new_node(x, x_ctrl); - // Chain of AddP: (AddP base (AddP base )) must keep the same base after sinking so: - // 1- We don't add a CastPP here when the first one is sunk so if the second one is not, their bases remain - // the same. + // Chain of AddP nodes: (AddP base (AddP base (AddP base ))) + // All AddP nodes must keep the same base after sinking so: + // 1- We don't add a CastPP here until the last one of the chain is sunk: if part of the chain is not sunk, + // their bases remain the same. // (see 2- below) assert(!x->is_AddP() || !x->in(AddPNode::Address)->is_AddP() || x->in(AddPNode::Address)->in(AddPNode::Base) == x->in(AddPNode::Base) || @@ -1693,21 +1698,22 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { Node* in = x->in(k); if (in != nullptr && n_loop->is_member(get_loop(get_ctrl(in)))) { const Type* in_t = _igvn.type(in); - cast = ConstraintCastNode::make_cast_for_type(x_ctrl, in, in_t, ConstraintCastNode::UnconditionalDependency); + cast = ConstraintCastNode::make_cast_for_type(x_ctrl, in, in_t, + ConstraintCastNode::UnconditionalDependency, nullptr); } if (cast != nullptr) { - register_new_node(cast, x_ctrl); + Node* prev = _igvn.hash_find_insert(cast); + if (prev != nullptr && get_ctrl(prev) == x_ctrl) { + cast->destruct(&_igvn); + cast = prev; + } else { + register_new_node(cast, x_ctrl); + } x->replace_edge(in, cast); - // Chain of AddP: - // 2- A CastPP of the base is only added now that both AddP nodes are sunk + // Chain of AddP nodes: + // 2- A CastPP of the base is only added now that all AddP nodes are sunk if (x->is_AddP() && k == AddPNode::Base) { - for (DUIterator_Fast imax, i = x->fast_outs(imax); i < imax; i++) { - Node* u = x->fast_out(i); - if (u->is_AddP() && u->in(AddPNode::Base) == n->in(AddPNode::Base)) { - _igvn.replace_input_of(u, AddPNode::Base, cast); - assert(u->find_out_with(Op_AddP) == nullptr, "more than 2 chained AddP nodes?"); - } - } + update_addp_chain_base(x, n->in(AddPNode::Base), cast); } break; } @@ -1722,6 +1728,22 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { } } +void PhaseIdealLoop::update_addp_chain_base(Node* x, Node* old_base, Node* new_base) { + ResourceMark rm; + Node_List wq; + wq.push(x); + while (wq.size() != 0) { + Node* n = wq.pop(); + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + Node* u = n->fast_out(i); + if (u->is_AddP() && u->in(AddPNode::Base) == old_base) { + _igvn.replace_input_of(u, AddPNode::Base, new_base); + wq.push(u); + } + } + } +} + // Compute the early control of a node by following its inputs until we reach // nodes that are pinned. Then compute the LCA of the control of all pinned nodes. Node* PhaseIdealLoop::compute_early_ctrl(Node* n, Node* n_ctrl) { @@ -1793,6 +1815,14 @@ bool PhaseIdealLoop::ctrl_of_use_out_of_loop(const Node* n, Node* n_ctrl, IdealL if (n_loop->is_member(u_loop)) { return false; // Found use in inner loop } + // Sinking a node from a pre loop to its main loop pins the node between the pre and main loops. If that node is input + // to a check that's eliminated by range check elimination, it becomes input to an expression that feeds into the exit + // test of the pre loop above the point in the graph where it's pinned. + if (n_loop->_head->is_CountedLoop() && n_loop->_head->as_CountedLoop()->is_pre_loop() && + u_loop->_head->is_CountedLoop() && u_loop->_head->as_CountedLoop()->is_main_loop() && + n_loop->_next == get_loop(u_loop->_head->as_CountedLoop()->skip_strip_mined())) { + return false; + } return true; } @@ -2005,17 +2035,6 @@ CmpNode*PhaseIdealLoop::clone_bool(PhiNode* phi) { return (CmpNode*)cmp; } -//------------------------------sink_use--------------------------------------- -// If 'use' was in the loop-exit block, it now needs to be sunk -// below the post-loop merge point. -void PhaseIdealLoop::sink_use( Node *use, Node *post_loop ) { - if (!use->is_CFG() && get_ctrl(use) == post_loop->in(2)) { - set_ctrl(use, post_loop); - for (DUIterator j = use->outs(); use->has_out(j); j++) - sink_use(use->out(j), post_loop); - } -} - void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new, IdealLoopTree* loop, IdealLoopTree* outer_loop, Node_List*& split_if_set, Node_List*& split_bool_set, @@ -2082,7 +2101,7 @@ void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new, while( use->in(idx) != old ) idx++; Node *prev = use->is_CFG() ? use : get_ctrl(use); assert(!loop->is_member(get_loop(prev)) && !outer_loop->is_member(get_loop(prev)), "" ); - Node *cfg = prev->_idx >= new_counter + Node* cfg = (prev->_idx >= new_counter && prev->is_Region()) ? prev->in(2) : idom(prev); if( use->is_Phi() ) // Phi use is in prior block @@ -2106,7 +2125,7 @@ void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new, while(!outer_loop->is_member(get_loop(cfg))) { prev = cfg; - cfg = cfg->_idx >= new_counter ? cfg->in(2) : idom(cfg); + cfg = (cfg->_idx >= new_counter && cfg->is_Region()) ? cfg->in(2) : idom(cfg); } // If the use occurs after merging several exits from the loop, then // old value must have dominated all those exits. Since the same old @@ -2164,10 +2183,6 @@ void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new, if( hit ) // Go ahead and re-hash for hits. _igvn.replace_node( use, hit ); } - - // If 'use' was in the loop-exit block, it now needs to be sunk - // below the post-loop merge point. - sink_use( use, prev ); } } } @@ -2534,8 +2549,6 @@ void PhaseIdealLoop::fix_ctrl_uses(const Node_List& body, const IdealLoopTree* l // We need a Region to merge the exit from the peeled body and the // exit from the old loop body. RegionNode *r = new RegionNode(3); - // Map the old use to the new merge point - old_new.map( use->_idx, r ); uint dd_r = MIN2(dom_depth(newuse), dom_depth(use)); assert(dd_r >= dom_depth(dom_lca(newuse, use)), "" ); @@ -2571,12 +2584,24 @@ void PhaseIdealLoop::fix_ctrl_uses(const Node_List& body, const IdealLoopTree* l l -= uses_found; // we deleted 1 or more copies of this edge } + assert(use->is_Proj(), "loop exit should be projection"); + // lazy_replace() below moves all nodes that are: + // - control dependent on the loop exit or + // - have control set to the loop exit + // below the post-loop merge point. lazy_replace() takes a dead control as first input. To make it + // possible to use it, the loop exit projection is cloned and becomes the new exit projection. The initial one + // becomes dead and is "replaced" by the region. + Node* use_clone = use->clone(); + register_control(use_clone, use_loop, idom(use), dom_depth(use)); // Now finish up 'r' r->set_req(1, newuse); - r->set_req(2, use); + r->set_req(2, use_clone); _igvn.register_new_node_with_optimizer(r); set_loop(r, use_loop); set_idom(r, (side_by_side_idom == nullptr) ? newuse->in(0) : side_by_side_idom, dd_r); + lazy_replace(use, r); + // Map the (cloned) old use to the new merge point + old_new.map(use_clone->_idx, r); } // End of if a loop-exit test } } @@ -4216,6 +4241,12 @@ void PhaseIdealLoop::move_unordered_reduction_out_of_loop(IdealLoopTree* loop) { break; // Chain traversal fails. } + assert(current->vect_type() != nullptr, "must have vector type"); + if (current->vect_type() != last_ur->vect_type()) { + // Reductions do not have the same vector type (length and element type). + break; // Chain traversal fails. + } + // Expect single use of UnorderedReduction, except for last_ur. if (current == last_ur) { // Expect all uses to be outside the loop, except phi. diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index ec0b465adf668..51fad220e53c8 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -356,7 +356,9 @@ void Matcher::match( ) { // Recursively match trees from old space into new space. // Correct leaves of new-space Nodes; they point to old-space. _visited.clear(); - C->set_cached_top_node(xform( C->top(), live_nodes )); + Node* const n = xform(C->top(), live_nodes); + if (C->failing()) return; + C->set_cached_top_node(n); if (!C->failing()) { Node* xroot = xform( C->root(), 1 ); if (xroot == nullptr) { diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 286f901bd5dab..76ed95c4a789b 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -593,8 +593,13 @@ Node* LoadNode::find_previous_arraycopy(PhaseValues* phase, Node* ld_alloc, Node Node* dest = ac->in(ArrayCopyNode::Dest); if (dest == ld_base) { - const TypeX *ld_offs_t = phase->type(ld_offs)->isa_intptr_t(); - if (ac->modifies(ld_offs_t->_lo, ld_offs_t->_hi, phase, can_see_stored_value)) { + const TypeX* ld_offs_t = phase->type(ld_offs)->isa_intptr_t(); + assert(!ld_offs_t->empty(), "dead reference should be checked already"); + // Take into account vector or unsafe access size + jlong ld_size_in_bytes = (jlong)memory_size(); + jlong offset_hi = ld_offs_t->_hi + ld_size_in_bytes - 1; + offset_hi = MIN2(offset_hi, (jlong)(TypeX::MAX->_hi)); // Take care for overflow in 32-bit VM + if (ac->modifies(ld_offs_t->_lo, (intptr_t)offset_hi, phase, can_see_stored_value)) { return ac; } if (!can_see_stored_value) { diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 0636bcd31dc1f..f42d06a365000 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -281,45 +281,86 @@ Node *MulINode::Ideal(PhaseGVN *phase, bool can_reshape) { return res; // Return final result } -// Classes to perform mul_ring() for MulI/MulLNode. +// This template class performs type multiplication for MulI/MulLNode. NativeType is either jint or jlong. +// In this class, the inputs of the MulNodes are named left and right with types [left_lo,left_hi] and [right_lo,right_hi]. // -// This class checks if all cross products of the left and right input of a multiplication have the same "overflow value". -// Without overflow/underflow: -// Product is positive? High signed multiplication result: 0 -// Product is negative? High signed multiplication result: -1 +// In general, the multiplication of two x-bit values could produce a result that consumes up to 2x bits if there is +// enough space to hold them all. We can therefore distinguish the following two cases for the product: +// - no overflow (i.e. product fits into x bits) +// - overflow (i.e. product does not fit into x bits) // -// We normalize these values (see normalize_overflow_value()) such that we get the same "overflow value" by adding 1 if -// the product is negative. This allows us to compare all the cross product "overflow values". If one is different, -// compared to the others, then we know that this multiplication has a different number of over- or underflows compared -// to the others. In this case, we need to use bottom type and cannot guarantee a better type. Otherwise, we can take -// the min und max of all computed cross products as type of this Mul node. -template -class IntegerMulRing { - using NativeType = std::conditional_t::value, jint, jlong>; +// When multiplying the two x-bit inputs 'left' and 'right' with their x-bit types [left_lo,left_hi] and [right_lo,right_hi] +// we need to find the minimum and maximum of all possible products to define a new type. To do that, we compute the +// cross product of [left_lo,left_hi] and [right_lo,right_hi] in 2x-bit space where no over- or underflow can happen. +// The cross product consists of the following four multiplications with 2x-bit results: +// (1) left_lo * right_lo +// (2) left_lo * right_hi +// (3) left_hi * right_lo +// (4) left_hi * right_hi +// +// Let's define the following two functions: +// - Lx(i): Returns the lower x bits of the 2x-bit number i. +// - Ux(i): Returns the upper x bits of the 2x-bit number i. +// +// Let's first assume all products are positive where only overflows are possible but no underflows. If there is no +// overflow for a product p, then the upper x bits of the 2x-bit result p are all zero: +// Ux(p) = 0 +// Lx(p) = p +// +// If none of the multiplications (1)-(4) overflow, we can truncate the upper x bits and use the following result type +// with x bits: +// [result_lo,result_hi] = [MIN(Lx(1),Lx(2),Lx(3),Lx(4)),MAX(Lx(1),Lx(2),Lx(3),Lx(4))] +// +// If any of these multiplications overflows, we could pessimistically take the bottom type for the x bit result +// (i.e. all values in the x-bit space could be possible): +// [result_lo,result_hi] = [NativeType_min,NativeType_max] +// +// However, in case of any overflow, we can do better by analyzing the upper x bits of all multiplications (1)-(4) with +// 2x-bit results. The upper x bits tell us something about how many times a multiplication has overflown the lower +// x bits. If the upper x bits of (1)-(4) are all equal, then we know that all of these multiplications overflowed +// the lower x bits the same number of times: +// Ux((1)) = Ux((2)) = Ux((3)) = Ux((4)) +// +// If all upper x bits are equal, we can conclude: +// Lx(MIN((1),(2),(3),(4))) = MIN(Lx(1),Lx(2),Lx(3),Lx(4))) +// Lx(MAX((1),(2),(3),(4))) = MAX(Lx(1),Lx(2),Lx(3),Lx(4))) +// +// Therefore, we can use the same precise x-bit result type as for the no-overflow case: +// [result_lo,result_hi] = [(MIN(Lx(1),Lx(2),Lx(3),Lx(4))),MAX(Lx(1),Lx(2),Lx(3),Lx(4)))] +// +// +// Now let's assume that (1)-(4) are signed multiplications where over- and underflow could occur: +// Negative numbers are all sign extend with ones. Therefore, if a negative product does not underflow, then the +// upper x bits of the 2x-bit result are all set to ones which is minus one in two's complement. If there is an underflow, +// the upper x bits are decremented by the number of times an underflow occurred. The smallest possible negative product +// is NativeType_min*NativeType_max, where the upper x bits are set to NativeType_min / 2 (b11...0). It is therefore +// impossible to underflow the upper x bits. Thus, when having all ones (i.e. minus one) in the upper x bits, we know +// that there is no underflow. +// +// To be able to compare the number of over-/underflows of positive and negative products, respectively, we normalize +// the upper x bits of negative 2x-bit products by adding one. This way a product has no over- or underflow if the +// normalized upper x bits are zero. Now we can use the same improved type as for strictly positive products because we +// can compare the upper x bits in a unified way with N() being the normalization function: +// N(Ux((1))) = N(Ux((2))) = N(Ux((3)) = N(Ux((4))) +template +class IntegerTypeMultiplication { NativeType _lo_left; NativeType _lo_right; NativeType _hi_left; NativeType _hi_right; - NativeType _lo_lo_product; - NativeType _lo_hi_product; - NativeType _hi_lo_product; - NativeType _hi_hi_product; short _widen_left; short _widen_right; static const Type* overflow_type(); - static NativeType multiply_high_signed_overflow_value(NativeType x, NativeType y); + static NativeType multiply_high(NativeType x, NativeType y); + const Type* create_type(NativeType lo, NativeType hi) const; - // Pre-compute cross products which are used at several places - void compute_cross_products() { - _lo_lo_product = java_multiply(_lo_left, _lo_right); - _lo_hi_product = java_multiply(_lo_left, _hi_right); - _hi_lo_product = java_multiply(_hi_left, _lo_right); - _hi_hi_product = java_multiply(_hi_left, _hi_right); + static NativeType multiply_high_signed_overflow_value(NativeType x, NativeType y) { + return normalize_overflow_value(x, y, multiply_high(x, y)); } - bool cross_products_not_same_overflow() const { + bool cross_product_not_same_overflow_value() const { const NativeType lo_lo_high_product = multiply_high_signed_overflow_value(_lo_left, _lo_right); const NativeType lo_hi_high_product = multiply_high_signed_overflow_value(_lo_left, _hi_right); const NativeType hi_lo_high_product = multiply_high_signed_overflow_value(_hi_left, _lo_right); @@ -329,66 +370,95 @@ class IntegerMulRing { hi_lo_high_product != hi_hi_high_product; } + bool does_product_overflow(NativeType x, NativeType y) const { + return multiply_high_signed_overflow_value(x, y) != 0; + } + static NativeType normalize_overflow_value(const NativeType x, const NativeType y, NativeType result) { return java_multiply(x, y) < 0 ? result + 1 : result; } public: - IntegerMulRing(const IntegerType* left, const IntegerType* right) : _lo_left(left->_lo), _lo_right(right->_lo), - _hi_left(left->_hi), _hi_right(right->_hi), _widen_left(left->_widen), _widen_right(right->_widen) { - compute_cross_products(); - } + template + IntegerTypeMultiplication(const IntegerType* left, const IntegerType* right) + : _lo_left(left->_lo), _lo_right(right->_lo), + _hi_left(left->_hi), _hi_right(right->_hi), + _widen_left(left->_widen), _widen_right(right->_widen) {} // Compute the product type by multiplying the two input type ranges. We take the minimum and maximum of all possible // values (requires 4 multiplications of all possible combinations of the two range boundary values). If any of these // multiplications overflows/underflows, we need to make sure that they all have the same number of overflows/underflows // If that is not the case, we return the bottom type to cover all values due to the inconsistent overflows/underflows). const Type* compute() const { - if (cross_products_not_same_overflow()) { + if (cross_product_not_same_overflow_value()) { return overflow_type(); } - const NativeType min = MIN4(_lo_lo_product, _lo_hi_product, _hi_lo_product, _hi_hi_product); - const NativeType max = MAX4(_lo_lo_product, _lo_hi_product, _hi_lo_product, _hi_hi_product); - return IntegerType::make(min, max, MAX2(_widen_left, _widen_right)); + + NativeType lo_lo_product = java_multiply(_lo_left, _lo_right); + NativeType lo_hi_product = java_multiply(_lo_left, _hi_right); + NativeType hi_lo_product = java_multiply(_hi_left, _lo_right); + NativeType hi_hi_product = java_multiply(_hi_left, _hi_right); + const NativeType min = MIN4(lo_lo_product, lo_hi_product, hi_lo_product, hi_hi_product); + const NativeType max = MAX4(lo_lo_product, lo_hi_product, hi_lo_product, hi_hi_product); + return create_type(min, max); } -}; + bool does_overflow() const { + return does_product_overflow(_lo_left, _lo_right) || + does_product_overflow(_lo_left, _hi_right) || + does_product_overflow(_hi_left, _lo_right) || + does_product_overflow(_hi_left, _hi_right); + } +}; template <> -const Type* IntegerMulRing::overflow_type() { +const Type* IntegerTypeMultiplication::overflow_type() { return TypeInt::INT; } template <> -jint IntegerMulRing::multiply_high_signed_overflow_value(const jint x, const jint y) { +jint IntegerTypeMultiplication::multiply_high(const jint x, const jint y) { const jlong x_64 = x; const jlong y_64 = y; const jlong product = x_64 * y_64; - const jint result = (jint)((uint64_t)product >> 32u); - return normalize_overflow_value(x, y, result); + return (jint)((uint64_t)product >> 32u); +} + +template <> +const Type* IntegerTypeMultiplication::create_type(jint lo, jint hi) const { + return TypeInt::make(lo, hi, MAX2(_widen_left, _widen_right)); } template <> -const Type* IntegerMulRing::overflow_type() { +const Type* IntegerTypeMultiplication::overflow_type() { return TypeLong::LONG; } template <> -jlong IntegerMulRing::multiply_high_signed_overflow_value(const jlong x, const jlong y) { - const jlong result = multiply_high_signed(x, y); - return normalize_overflow_value(x, y, result); +jlong IntegerTypeMultiplication::multiply_high(const jlong x, const jlong y) { + return multiply_high_signed(x, y); +} + +template <> +const Type* IntegerTypeMultiplication::create_type(jlong lo, jlong hi) const { + return TypeLong::make(lo, hi, MAX2(_widen_left, _widen_right)); } // Compute the product type of two integer ranges into this node. const Type* MulINode::mul_ring(const Type* type_left, const Type* type_right) const { - const IntegerMulRing integer_mul_ring(type_left->is_int(), type_right->is_int()); - return integer_mul_ring.compute(); + const IntegerTypeMultiplication integer_multiplication(type_left->is_int(), type_right->is_int()); + return integer_multiplication.compute(); +} + +bool MulINode::does_overflow(const TypeInt* type_left, const TypeInt* type_right) { + const IntegerTypeMultiplication integer_multiplication(type_left, type_right); + return integer_multiplication.does_overflow(); } // Compute the product type of two long ranges into this node. const Type* MulLNode::mul_ring(const Type* type_left, const Type* type_right) const { - const IntegerMulRing integer_mul_ring(type_left->is_long(), type_right->is_long()); - return integer_mul_ring.compute(); + const IntegerTypeMultiplication integer_multiplication(type_left->is_long(), type_right->is_long()); + return integer_multiplication.compute(); } //============================================================================= diff --git a/src/hotspot/share/opto/mulnode.hpp b/src/hotspot/share/opto/mulnode.hpp index 84307fb00fb6c..01d418a5b1041 100644 --- a/src/hotspot/share/opto/mulnode.hpp +++ b/src/hotspot/share/opto/mulnode.hpp @@ -95,6 +95,7 @@ class MulINode : public MulNode { virtual int Opcode() const; virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual const Type *mul_ring( const Type *, const Type * ) const; + static bool does_overflow(const TypeInt* type_left, const TypeInt* type_right); const Type *mul_id() const { return TypeInt::ONE; } const Type *add_id() const { return TypeInt::ZERO; } int add_opcode() const { return Op_AddI; } diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index 62d6c4f690f1f..e09aaf2acb7fb 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -1759,8 +1759,8 @@ Node* Node::find(const int idx, bool only_ctrl) { class PrintBFS { public: - PrintBFS(const Node* start, const int max_distance, const Node* target, const char* options) - : _start(start), _max_distance(max_distance), _target(target), _options(options), + PrintBFS(const Node* start, const int max_distance, const Node* target, const char* options, outputStream* st) + : _start(start), _max_distance(max_distance), _target(target), _options(options), _output(st), _dcc(this), _info_uid(cmpkey, hashkey) {} void run(); @@ -1780,6 +1780,7 @@ class PrintBFS { const int _max_distance; const Node* _target; const char* _options; + outputStream* _output; // options bool _traverse_inputs = false; @@ -1819,7 +1820,7 @@ class PrintBFS { bool _print_blocks = false; bool _print_old = false; bool _dump_only = false; - static void print_options_help(bool print_examples); + void print_options_help(bool print_examples); bool parse_options(); public: @@ -1836,9 +1837,9 @@ class PrintBFS { // node info static Node* old_node(const Node* n); // mach node -> prior IR node - static void print_node_idx(const Node* n); // to tty - static void print_block_id(const Block* b); // to tty - static void print_node_block(const Node* n); // to tty: _pre_order, head idx, _idom, _dom_depth + void print_node_idx(const Node* n); + void print_block_id(const Block* b); + void print_node_block(const Node* n); // _pre_order, head idx, _idom, _dom_depth // traversal data structures GrowableArray _worklist; // BFS queue @@ -1903,7 +1904,7 @@ void PrintBFS::run() { // set up configuration for BFS and print bool PrintBFS::configure() { if (_max_distance < 0) { - tty->print("dump_bfs: max_distance must be non-negative!\n"); + _output->print_cr("dump_bfs: max_distance must be non-negative!"); return false; } return parse_options(); @@ -1941,7 +1942,7 @@ void PrintBFS::select() { select_all(); } else { if (find_info(_target) == nullptr) { - tty->print("Could not find target in BFS.\n"); + _output->print_cr("Could not find target in BFS."); return; } if (_all_paths) { @@ -2037,96 +2038,96 @@ void PrintBFS::print() { print_node(n); } } else { - tty->print("No nodes to print.\n"); + _output->print_cr("No nodes to print."); } } void PrintBFS::print_options_help(bool print_examples) { - tty->print("Usage: node->dump_bfs(int max_distance, Node* target, char* options)\n"); - tty->print("\n"); - tty->print("Use cases:\n"); - tty->print(" BFS traversal: no target required\n"); - tty->print(" shortest path: set target\n"); - tty->print(" all paths: set target and put 'A' in options\n"); - tty->print(" detect loop: subcase of all paths, have start==target\n"); - tty->print("\n"); - tty->print("Arguments:\n"); - tty->print(" this/start: staring point of BFS\n"); - tty->print(" target:\n"); - tty->print(" if null: simple BFS\n"); - tty->print(" else: shortest path or all paths between this/start and target\n"); - tty->print(" options:\n"); - tty->print(" if null: same as \"cdmox@B\"\n"); - tty->print(" else: use combination of following characters\n"); - tty->print(" h: display this help info\n"); - tty->print(" H: display this help info, with examples\n"); - tty->print(" +: traverse in-edges (on if neither + nor -)\n"); - tty->print(" -: traverse out-edges\n"); - tty->print(" c: visit control nodes\n"); - tty->print(" d: visit data nodes\n"); - tty->print(" m: visit memory nodes\n"); - tty->print(" o: visit other nodes\n"); - tty->print(" x: visit mixed nodes\n"); - tty->print(" C: boundary control nodes\n"); - tty->print(" D: boundary data nodes\n"); - tty->print(" M: boundary memory nodes\n"); - tty->print(" O: boundary other nodes\n"); - tty->print(" X: boundary mixed nodes\n"); - tty->print(" #: display node category in color (not supported in all terminals)\n"); - tty->print(" S: sort displayed nodes by node idx\n"); - tty->print(" A: all paths (not just shortest path to target)\n"); - tty->print(" @: print old nodes - before matching (if available)\n"); - tty->print(" B: print scheduling blocks (if available)\n"); - tty->print(" $: dump only, no header, no other columns\n"); - tty->print("\n"); - tty->print("recursively follow edges to nodes with permitted visit types,\n"); - tty->print("on the boundary additionally display nodes allowed in boundary types\n"); - tty->print("Note: the categories can be overlapping. For example a mixed node\n"); - tty->print(" can contain control and memory output. Some from the other\n"); - tty->print(" category are also control (Halt, Return, etc).\n"); - tty->print("\n"); - tty->print("output columns:\n"); - tty->print(" dist: BFS distance to this/start\n"); - tty->print(" apd: all paths distance (d_start + d_target)\n"); - tty->print(" block: block identifier, based on _pre_order\n"); - tty->print(" head: first node in block\n"); - tty->print(" idom: head node of idom block\n"); - tty->print(" depth: depth of block (_dom_depth)\n"); - tty->print(" old: old IR node - before matching\n"); - tty->print(" dump: node->dump()\n"); - tty->print("\n"); - tty->print("Note: if none of the \"cmdxo\" characters are in the options string\n"); - tty->print(" then we set all of them.\n"); - tty->print(" This allows for short strings like \"#\" for colored input traversal\n"); - tty->print(" or \"-#\" for colored output traversal.\n"); + _output->print_cr("Usage: node->dump_bfs(int max_distance, Node* target, char* options)"); + _output->print_cr(""); + _output->print_cr("Use cases:"); + _output->print_cr(" BFS traversal: no target required"); + _output->print_cr(" shortest path: set target"); + _output->print_cr(" all paths: set target and put 'A' in options"); + _output->print_cr(" detect loop: subcase of all paths, have start==target"); + _output->print_cr(""); + _output->print_cr("Arguments:"); + _output->print_cr(" this/start: staring point of BFS"); + _output->print_cr(" target:"); + _output->print_cr(" if null: simple BFS"); + _output->print_cr(" else: shortest path or all paths between this/start and target"); + _output->print_cr(" options:"); + _output->print_cr(" if null: same as \"cdmox@B\""); + _output->print_cr(" else: use combination of following characters"); + _output->print_cr(" h: display this help info"); + _output->print_cr(" H: display this help info, with examples"); + _output->print_cr(" +: traverse in-edges (on if neither + nor -)"); + _output->print_cr(" -: traverse out-edges"); + _output->print_cr(" c: visit control nodes"); + _output->print_cr(" d: visit data nodes"); + _output->print_cr(" m: visit memory nodes"); + _output->print_cr(" o: visit other nodes"); + _output->print_cr(" x: visit mixed nodes"); + _output->print_cr(" C: boundary control nodes"); + _output->print_cr(" D: boundary data nodes"); + _output->print_cr(" M: boundary memory nodes"); + _output->print_cr(" O: boundary other nodes"); + _output->print_cr(" X: boundary mixed nodes"); + _output->print_cr(" #: display node category in color (not supported in all terminals)"); + _output->print_cr(" S: sort displayed nodes by node idx"); + _output->print_cr(" A: all paths (not just shortest path to target)"); + _output->print_cr(" @: print old nodes - before matching (if available)"); + _output->print_cr(" B: print scheduling blocks (if available)"); + _output->print_cr(" $: dump only, no header, no other columns"); + _output->print_cr(""); + _output->print_cr("recursively follow edges to nodes with permitted visit types,"); + _output->print_cr("on the boundary additionally display nodes allowed in boundary types"); + _output->print_cr("Note: the categories can be overlapping. For example a mixed node"); + _output->print_cr(" can contain control and memory output. Some from the other"); + _output->print_cr(" category are also control (Halt, Return, etc)."); + _output->print_cr(""); + _output->print_cr("output columns:"); + _output->print_cr(" dist: BFS distance to this/start"); + _output->print_cr(" apd: all paths distance (d_outputart + d_target)"); + _output->print_cr(" block: block identifier, based on _pre_order"); + _output->print_cr(" head: first node in block"); + _output->print_cr(" idom: head node of idom block"); + _output->print_cr(" depth: depth of block (_dom_depth)"); + _output->print_cr(" old: old IR node - before matching"); + _output->print_cr(" dump: node->dump()"); + _output->print_cr(""); + _output->print_cr("Note: if none of the \"cmdxo\" characters are in the options string"); + _output->print_cr(" then we set all of them."); + _output->print_cr(" This allows for short strings like \"#\" for colored input traversal"); + _output->print_cr(" or \"-#\" for colored output traversal."); if (print_examples) { - tty->print("\n"); - tty->print("Examples:\n"); - tty->print(" if->dump_bfs(10, 0, \"+cxo\")\n"); - tty->print(" starting at some if node, traverse inputs recursively\n"); - tty->print(" only along control (mixed and other can also be control)\n"); - tty->print(" phi->dump_bfs(5, 0, \"-dxo\")\n"); - tty->print(" starting at phi node, traverse outputs recursively\n"); - tty->print(" only along data (mixed and other can also have data flow)\n"); - tty->print(" find_node(385)->dump_bfs(3, 0, \"cdmox+#@B\")\n"); - tty->print(" find inputs of node 385, up to 3 nodes up (+)\n"); - tty->print(" traverse all nodes (cdmox), use colors (#)\n"); - tty->print(" display old nodes and blocks, if they exist\n"); - tty->print(" useful call to start with\n"); - tty->print(" find_node(102)->dump_bfs(10, 0, \"dCDMOX-\")\n"); - tty->print(" find non-data dependencies of a data node\n"); - tty->print(" follow data node outputs until we find another category\n"); - tty->print(" node as the boundary\n"); - tty->print(" x->dump_bfs(10, y, 0)\n"); - tty->print(" find shortest path from x to y, along any edge or node\n"); - tty->print(" will not find a path if it is longer than 10\n"); - tty->print(" useful to find how x and y are related\n"); - tty->print(" find_node(741)->dump_bfs(20, find_node(746), \"c+\")\n"); - tty->print(" find shortest control path between two nodes\n"); - tty->print(" find_node(741)->dump_bfs(8, find_node(746), \"cdmox+A\")\n"); - tty->print(" find all paths (A) between two nodes of length at most 8\n"); - tty->print(" find_node(741)->dump_bfs(7, find_node(741), \"c+A\")\n"); - tty->print(" find all control loops for this node\n"); + _output->print_cr(""); + _output->print_cr("Examples:"); + _output->print_cr(" if->dump_bfs(10, 0, \"+cxo\")"); + _output->print_cr(" starting at some if node, traverse inputs recursively"); + _output->print_cr(" only along control (mixed and other can also be control)"); + _output->print_cr(" phi->dump_bfs(5, 0, \"-dxo\")"); + _output->print_cr(" starting at phi node, traverse outputs recursively"); + _output->print_cr(" only along data (mixed and other can also have data flow)"); + _output->print_cr(" find_node(385)->dump_bfs(3, 0, \"cdmox+#@B\")"); + _output->print_cr(" find inputs of node 385, up to 3 nodes up (+)"); + _output->print_cr(" traverse all nodes (cdmox), use colors (#)"); + _output->print_cr(" display old nodes and blocks, if they exist"); + _output->print_cr(" useful call to start with"); + _output->print_cr(" find_node(102)->dump_bfs(10, 0, \"dCDMOX-\")"); + _output->print_cr(" find non-data dependencies of a data node"); + _output->print_cr(" follow data node outputs until we find another category"); + _output->print_cr(" node as the boundary"); + _output->print_cr(" x->dump_bfs(10, y, 0)"); + _output->print_cr(" find shortest path from x to y, along any edge or node"); + _output->print_cr(" will not find a path if it is longer than 10"); + _output->print_cr(" useful to find how x and y are related"); + _output->print_cr(" find_node(741)->dump_bfs(20, find_node(746), \"c+\")"); + _output->print_cr(" find shortest control path between two nodes"); + _output->print_cr(" find_node(741)->dump_bfs(8, find_node(746), \"cdmox+A\")"); + _output->print_cr(" find all paths (A) between two nodes of length at most 8"); + _output->print_cr(" find_node(741)->dump_bfs(7, find_node(741), \"c+A\")"); + _output->print_cr(" find all control loops for this node"); } } @@ -2198,8 +2199,8 @@ bool PrintBFS::parse_options() { print_options_help(true); return false; default: - tty->print_cr("dump_bfs: Unrecognized option \'%c\'", _options[i]); - tty->print_cr("for help, run: find_node(0)->dump_bfs(0,0,\"H\")"); + _output->print_cr("dump_bfs: Unrecognized option \'%c\'", _options[i]); + _output->print_cr("for help, run: find_node(0)->dump_bfs(0,0,\"H\")"); return false; } } @@ -2278,14 +2279,14 @@ void PrintBFS::print_node_idx(const Node* n) { } else { os::snprintf_checked(buf, sizeof(buf), "o%d", n->_idx); // old node } - tty->print("%6s", buf); + _output->print("%6s", buf); } void PrintBFS::print_block_id(const Block* b) { Compile* C = Compile::current(); char buf[30]; os::snprintf_checked(buf, sizeof(buf), "B%d", b->_pre_order); - tty->print("%7s", buf); + _output->print("%7s", buf); } void PrintBFS::print_node_block(const Node* n) { @@ -2294,19 +2295,19 @@ void PrintBFS::print_node_block(const Node* n) { ? C->cfg()->get_block_for_node(n) : nullptr; // guard against old nodes if (b == nullptr) { - tty->print(" _"); // Block - tty->print(" _"); // head - tty->print(" _"); // idom - tty->print(" _"); // depth + _output->print(" _"); // Block + _output->print(" _"); // head + _output->print(" _"); // idom + _output->print(" _"); // depth } else { print_block_id(b); print_node_idx(b->head()); if (b->_idom) { print_node_idx(b->_idom->head()); } else { - tty->print(" _"); // idom + _output->print(" _"); // idom } - tty->print("%6d ", b->_dom_depth); + _output->print("%6d ", b->_dom_depth); } } @@ -2336,39 +2337,39 @@ void PrintBFS::print_header() const { if (_dump_only) { return; // no header in dump only mode } - tty->print("dist"); // distance + _output->print("dist"); // distance if (_all_paths) { - tty->print(" apd"); // all paths distance + _output->print(" apd"); // all paths distance } if (_print_blocks) { - tty->print(" [block head idom depth]"); // block + _output->print(" [block head idom depth]"); // block } if (_print_old) { - tty->print(" old"); // old node + _output->print(" old"); // old node } - tty->print(" dump\n"); // node dump - tty->print("---------------------------------------------\n"); + _output->print(" dump\n"); // node dump + _output->print_cr("---------------------------------------------"); } void PrintBFS::print_node(const Node* n) { if (_dump_only) { - n->dump("\n", false, tty, &_dcc); + n->dump("\n", false, _output, &_dcc); return; } - tty->print("%4d", find_info(n)->distance());// distance + _output->print("%4d", find_info(n)->distance());// distance if (_all_paths) { Info* info = find_info(n); int apd = info->distance() + info->distance_from_target(); - tty->print("%4d", apd); // all paths distance + _output->print("%4d", apd); // all paths distance } if (_print_blocks) { - print_node_block(n); // block + print_node_block(n); // block } if (_print_old) { - print_node_idx(old_node(n)); // old node + print_node_idx(old_node(n)); // old node } - tty->print(" "); - n->dump("\n", false, tty, &_dcc); // node dump + _output->print(" "); + n->dump("\n", false, _output, &_dcc); // node dump } //------------------------------dump_bfs-------------------------------------- @@ -2378,7 +2379,12 @@ void PrintBFS::print_node(const Node* n) { // To find all options, run: // find_node(0)->dump_bfs(0,0,"H") void Node::dump_bfs(const int max_distance, Node* target, const char* options) const { - PrintBFS bfs(this, max_distance, target, options); + dump_bfs(max_distance, target, options, tty); +} + +// Used to dump to stream. +void Node::dump_bfs(const int max_distance, Node* target, const char* options, outputStream* st) const { + PrintBFS bfs(this, max_distance, target, options, st); bfs.run(); } @@ -2522,7 +2528,7 @@ void Node::dump(const char* suffix, bool mark, outputStream* st, DumpConfig* dc) } if (C->clone_map().value(_idx) != 0) { - C->clone_map().dump(_idx); + C->clone_map().dump(_idx, st); } // Dump node-specific info dump_spec(st); diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index dbe18b672239e..ca03ecd070a92 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -1215,7 +1215,8 @@ class Node { public: Node* find(int idx, bool only_ctrl = false); // Search the graph for the given idx. Node* find_ctrl(int idx); // Search control ancestors for the given idx. - void dump_bfs(const int max_distance, Node* target, const char* options) const; // Print BFS traversal + void dump_bfs(const int max_distance, Node* target, const char* options, outputStream* st) const; + void dump_bfs(const int max_distance, Node* target, const char* options) const; // directly to tty void dump_bfs(const int max_distance) const; // dump_bfs(max_distance, nullptr, nullptr) class DumpConfig { public: diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 524e38fcf72dd..998be5e122589 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -2068,8 +2068,12 @@ void PhaseOutput::ScheduleAndBundle() { #ifndef PRODUCT if (C->trace_opto_output()) { - tty->print("\n---- After ScheduleAndBundle ----\n"); - print_scheduling(); + // Buffer and print all at once + ResourceMark rm; + stringStream ss; + ss.print("\n---- After ScheduleAndBundle ----\n"); + print_scheduling(&ss); + tty->print("%s", ss.as_string()); } #endif } @@ -2077,14 +2081,18 @@ void PhaseOutput::ScheduleAndBundle() { #ifndef PRODUCT // Separated out so that it can be called directly from debugger void PhaseOutput::print_scheduling() { + print_scheduling(tty); +} + +void PhaseOutput::print_scheduling(outputStream* output_stream) { for (uint i = 0; i < C->cfg()->number_of_blocks(); i++) { - tty->print("\nBB#%03d:\n", i); + output_stream->print("\nBB#%03d:\n", i); Block* block = C->cfg()->get_block(i); for (uint j = 0; j < block->number_of_nodes(); j++) { Node* n = block->get_node(j); OptoReg::Name reg = C->regalloc()->get_reg_first(n); - tty->print(" %-6s ", reg >= 0 && reg < REG_COUNT ? Matcher::regName[reg] : ""); - n->dump(); + output_stream->print(" %-6s ", reg >= 0 && reg < REG_COUNT ? Matcher::regName[reg] : ""); + n->dump("\n", false, output_stream); } } } diff --git a/src/hotspot/share/opto/output.hpp b/src/hotspot/share/opto/output.hpp index 77c49b33bfeae..d74751ddbf601 100644 --- a/src/hotspot/share/opto/output.hpp +++ b/src/hotspot/share/opto/output.hpp @@ -222,7 +222,8 @@ class PhaseOutput : public Phase { void BuildOopMaps(); #ifndef PRODUCT - void print_scheduling(); + void print_scheduling(outputStream* output_stream); + void print_scheduling(); // to tty for debugging static void print_statistics(); #endif }; diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index f179d3ba88df2..e214268112e41 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -1575,6 +1575,7 @@ void Parse::do_one_block() { #endif //ASSERT do_one_bytecode(); + if (failing()) return; assert(!have_se || stopped() || failing() || (sp() - pre_bc_sp) == depth, "incorrect depth prediction: sp=%d, pre_bc_sp=%d, depth=%d", sp(), pre_bc_sp, depth); diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index 30f71ea4e9715..6f43a3769f76c 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -152,6 +152,16 @@ static bool ok_to_convert(Node* inc, Node* var) { return !(is_cloop_increment(inc) || var->is_cloop_ind_var()); } +static bool is_cloop_condition(BoolNode* bol) { + for (DUIterator_Fast imax, i = bol->fast_outs(imax); i < imax; i++) { + Node* out = bol->fast_out(i); + if (out->is_BaseCountedLoopEnd()) { + return true; + } + } + return false; +} + //------------------------------Ideal------------------------------------------ Node *SubINode::Ideal(PhaseGVN *phase, bool can_reshape){ Node *in1 = in(1); @@ -1556,13 +1566,15 @@ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) { // and "cmp (add X min_jint) c" into "cmpu X (c + min_jint)" if (cop == Op_CmpI && cmp1_op == Op_AddI && - phase->type(cmp1->in(2)) == TypeInt::MIN) { + phase->type(cmp1->in(2)) == TypeInt::MIN && + !is_cloop_condition(this)) { if (cmp2_op == Op_ConI) { Node* ncmp2 = phase->intcon(java_add(cmp2->get_int(), min_jint)); Node* ncmp = phase->transform(new CmpUNode(cmp1->in(1), ncmp2)); return new BoolNode(ncmp, _test._test); } else if (cmp2_op == Op_AddI && - phase->type(cmp2->in(2)) == TypeInt::MIN) { + phase->type(cmp2->in(2)) == TypeInt::MIN && + !is_cloop_condition(this)) { Node* ncmp = phase->transform(new CmpUNode(cmp1->in(1), cmp2->in(1))); return new BoolNode(ncmp, _test._test); } @@ -1572,13 +1584,15 @@ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) { // and "cmp (add X min_jlong) c" into "cmpu X (c + min_jlong)" if (cop == Op_CmpL && cmp1_op == Op_AddL && - phase->type(cmp1->in(2)) == TypeLong::MIN) { + phase->type(cmp1->in(2)) == TypeLong::MIN && + !is_cloop_condition(this)) { if (cmp2_op == Op_ConL) { Node* ncmp2 = phase->longcon(java_add(cmp2->get_long(), min_jlong)); Node* ncmp = phase->transform(new CmpULNode(cmp1->in(1), ncmp2)); return new BoolNode(ncmp, _test._test); } else if (cmp2_op == Op_AddL && - phase->type(cmp2->in(2)) == TypeLong::MIN) { + phase->type(cmp2->in(2)) == TypeLong::MIN && + !is_cloop_condition(this)) { Node* ncmp = phase->transform(new CmpULNode(cmp1->in(1), cmp2->in(1))); return new BoolNode(ncmp, _test._test); } diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 6dcea46b4be85..6a641a44b3296 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -1403,6 +1403,7 @@ bool SuperWord::isomorphic(Node* s1, Node* s2) { if (s1->Opcode() != s2->Opcode()) return false; if (s1->req() != s2->req()) return false; if (!same_velt_type(s1, s2)) return false; + if (s1->is_Bool() && s1->as_Bool()->_test._test != s2->as_Bool()->_test._test) return false; Node* s1_ctrl = s1->in(0); Node* s2_ctrl = s2->in(0); // If the control nodes are equivalent, no further checks are required to test for isomorphism. @@ -2701,18 +2702,15 @@ bool SuperWord::output() { if (n->is_Load()) { Node* ctl = n->in(MemNode::Control); Node* mem = first->in(MemNode::Memory); - SWPointer p1(n->as_Mem(), this, nullptr, false); - // Identify the memory dependency for the new loadVector node by - // walking up through memory chain. - // This is done to give flexibility to the new loadVector node so that - // it can move above independent storeVector nodes. + // Set the memory dependency of the LoadVector as early as possible. + // Walk up the memory chain, and ignore any StoreVector that provably + // does not have any memory dependency. while (mem->is_StoreVector()) { - SWPointer p2(mem->as_Mem(), this, nullptr, false); - int cmp = p1.cmp(p2); - if (SWPointer::not_equal(cmp) || !SWPointer::comparable(cmp)) { - mem = mem->in(MemNode::Memory); + SWPointer p_store(mem->as_Mem(), this, nullptr, false); + if (p_store.overlap_possible_with_any_in(p)) { + break; } else { - break; // dependent memory + mem = mem->in(MemNode::Memory); } } Node* adr = first->in(MemNode::Address); @@ -2799,6 +2797,14 @@ bool SuperWord::output() { Node_List* p_bol = my_pack(bol); assert(p_bol != nullptr, "CMove must have matching Bool pack"); +#ifdef ASSERT + for (uint j = 0; j < p_bol->size(); j++) { + Node* m = p_bol->at(j); + assert(m->as_Bool()->_test._test == bol_test, + "all bool nodes must have same test"); + } +#endif + CmpNode* cmp = bol->in(1)->as_Cmp(); assert(cmp != nullptr, "must have cmp above CMove"); Node_List* p_cmp = my_pack(cmp); diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp index 6e2689b19ad8e..eca3836845ad1 100644 --- a/src/hotspot/share/opto/superword.hpp +++ b/src/hotspot/share/opto/superword.hpp @@ -722,6 +722,20 @@ class SWPointer : public ArenaObj { } } + bool overlap_possible_with_any_in(Node_List* p) { + for (uint k = 0; k < p->size(); k++) { + MemNode* mem = p->at(k)->as_Mem(); + SWPointer p_mem(mem, _slp, nullptr, false); + // Only if we know that we have Less or Greater can we + // be sure that there can never be an overlap between + // the two memory regions. + if (!not_equal(p_mem)) { + return true; + } + } + return false; + } + bool not_equal(SWPointer& q) { return not_equal(cmp(q)); } bool equal(SWPointer& q) { return equal(cmp(q)); } bool comparable(SWPointer& q) { return comparable(cmp(q)); } diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index ba63134f01e5e..4e0bd43be5cb1 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -61,6 +61,7 @@ const Type::TypeInfo Type::_type_info[Type::lastype] = { { Bad, T_NARROWKLASS,"narrowklass:", false, Op_RegN, relocInfo::none }, // NarrowKlass { Bad, T_ILLEGAL, "tuple:", false, Node::NotAMachineReg, relocInfo::none }, // Tuple { Bad, T_ARRAY, "array:", false, Node::NotAMachineReg, relocInfo::none }, // Array + { Bad, T_ARRAY, "interfaces:", false, Node::NotAMachineReg, relocInfo::none }, // Interfaces #if defined(PPC64) { Bad, T_ILLEGAL, "vectormask:", false, Op_RegVectMask, relocInfo::none }, // VectorMask. @@ -120,8 +121,8 @@ const Type* Type:: _zero_type[T_CONFLICT+1]; // Map basic types to array-body alias types. const TypeAryPtr* TypeAryPtr::_array_body_type[T_CONFLICT+1]; -const TypePtr::InterfaceSet* TypeAryPtr::_array_interfaces = nullptr; -const TypePtr::InterfaceSet* TypeAryKlassPtr::_array_interfaces = nullptr; +const TypeInterfaces* TypeAryPtr::_array_interfaces = nullptr; +const TypeInterfaces* TypeAryKlassPtr::_array_interfaces = nullptr; //============================================================================= // Convenience common pre-built types. @@ -571,7 +572,7 @@ void Type::Initialize_shared(Compile* current) { GrowableArray array_interfaces; array_interfaces.push(current->env()->Cloneable_klass()); array_interfaces.push(current->env()->Serializable_klass()); - TypeAryPtr::_array_interfaces = new TypePtr::InterfaceSet(&array_interfaces); + TypeAryPtr::_array_interfaces = TypeInterfaces::make(&array_interfaces); TypeAryKlassPtr::_array_interfaces = TypeAryPtr::_array_interfaces; TypeAryPtr::RANGE = TypeAryPtr::make( TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS), nullptr /* current->env()->Object_klass() */, false, arrayOopDesc::length_offset_in_bytes()); @@ -3252,14 +3253,14 @@ void TypeRawPtr::dump2( Dict &d, uint depth, outputStream *st ) const { // Convenience common pre-built type. const TypeOopPtr *TypeOopPtr::BOTTOM; -TypePtr::InterfaceSet::InterfaceSet() - : _list(Compile::current()->type_arena(), 0, 0, nullptr), +TypeInterfaces::TypeInterfaces() + : Type(Interfaces), _list(Compile::current()->type_arena(), 0, 0, nullptr), _hash(0), _exact_klass(nullptr) { DEBUG_ONLY(_initialized = true); } -TypePtr::InterfaceSet::InterfaceSet(GrowableArray* interfaces) - : _list(Compile::current()->type_arena(), interfaces->length(), 0, nullptr), +TypeInterfaces::TypeInterfaces(GrowableArray* interfaces) + : Type(Interfaces), _list(Compile::current()->type_arena(), interfaces->length(), 0, nullptr), _hash(0), _exact_klass(nullptr) { for (int i = 0; i < interfaces->length(); i++) { add(interfaces->at(i)); @@ -3267,13 +3268,18 @@ TypePtr::InterfaceSet::InterfaceSet(GrowableArray* interfaces) initialize(); } -void TypePtr::InterfaceSet::initialize() { +const TypeInterfaces* TypeInterfaces::make(GrowableArray* interfaces) { + TypeInterfaces* result = (interfaces == nullptr) ? new TypeInterfaces() : new TypeInterfaces(interfaces); + return (const TypeInterfaces*)result->hashcons(); +} + +void TypeInterfaces::initialize() { compute_hash(); compute_exact_klass(); DEBUG_ONLY(_initialized = true;) } -int TypePtr::InterfaceSet::compare(ciKlass* const& k1, ciKlass* const& k2) { +int TypeInterfaces::compare(ciInstanceKlass* const& k1, ciInstanceKlass* const& k2) { if ((intptr_t)k1 < (intptr_t)k2) { return -1; } else if ((intptr_t)k1 > (intptr_t)k2) { @@ -3282,24 +3288,20 @@ int TypePtr::InterfaceSet::compare(ciKlass* const& k1, ciKlass* const& k2) { return 0; } -void TypePtr::InterfaceSet::add(ciKlass* interface) { +void TypeInterfaces::add(ciInstanceKlass* interface) { assert(interface->is_interface(), "for interfaces only"); _list.insert_sorted(interface); verify(); } -void TypePtr::InterfaceSet::raw_add(ciKlass* interface) { - assert(interface->is_interface(), "for interfaces only"); - _list.push(interface); -} - -bool TypePtr::InterfaceSet::eq(const InterfaceSet& other) const { - if (_list.length() != other._list.length()) { +bool TypeInterfaces::eq(const Type* t) const { + const TypeInterfaces* other = (const TypeInterfaces*)t; + if (_list.length() != other->_list.length()) { return false; } for (int i = 0; i < _list.length(); i++) { ciKlass* k1 = _list.at(i); - ciKlass* k2 = other._list.at(i); + ciKlass* k2 = other->_list.at(i); if (!k1->equals(k2)) { return false; } @@ -3307,15 +3309,15 @@ bool TypePtr::InterfaceSet::eq(const InterfaceSet& other) const { return true; } -bool TypePtr::InterfaceSet::eq(ciInstanceKlass* k) const { +bool TypeInterfaces::eq(ciInstanceKlass* k) const { assert(k->is_loaded(), "should be loaded"); - GrowableArray* interfaces = k->as_instance_klass()->transitive_interfaces(); + GrowableArray* interfaces = k->transitive_interfaces(); if (_list.length() != interfaces->length()) { return false; } for (int i = 0; i < interfaces->length(); i++) { bool found = false; - _list.find_sorted(interfaces->at(i), found); + _list.find_sorted(interfaces->at(i), found); if (!found) { return false; } @@ -3324,12 +3326,16 @@ bool TypePtr::InterfaceSet::eq(ciInstanceKlass* k) const { } -uint TypePtr::InterfaceSet::hash() const { +uint TypeInterfaces::hash() const { assert(_initialized, "must be"); return _hash; } -void TypePtr::InterfaceSet::compute_hash() { +const Type* TypeInterfaces::xdual() const { + return this; +} + +void TypeInterfaces::compute_hash() { uint hash = 0; for (int i = 0; i < _list.length(); i++) { ciKlass* k = _list.at(i); @@ -3338,17 +3344,17 @@ void TypePtr::InterfaceSet::compute_hash() { _hash = hash; } -static int compare_interfaces(ciKlass** k1, ciKlass** k2) { +static int compare_interfaces(ciInstanceKlass** k1, ciInstanceKlass** k2) { return (int)((*k1)->ident() - (*k2)->ident()); } -void TypePtr::InterfaceSet::dump(outputStream* st) const { +void TypeInterfaces::dump(outputStream* st) const { if (_list.length() == 0) { return; } ResourceMark rm; st->print(" ("); - GrowableArray interfaces; + GrowableArray interfaces; interfaces.appendAll(&_list); // Sort the interfaces so they are listed in the same order from one run to the other of the same compilation interfaces.sort(compare_interfaces); @@ -3363,110 +3369,110 @@ void TypePtr::InterfaceSet::dump(outputStream* st) const { } #ifdef ASSERT -void TypePtr::InterfaceSet::verify() const { +void TypeInterfaces::verify() const { for (int i = 1; i < _list.length(); i++) { - ciKlass* k1 = _list.at(i-1); - ciKlass* k2 = _list.at(i); + ciInstanceKlass* k1 = _list.at(i-1); + ciInstanceKlass* k2 = _list.at(i); assert(compare(k2, k1) > 0, "should be ordered"); assert(k1 != k2, "no duplicate"); } } #endif -TypePtr::InterfaceSet TypeOopPtr::InterfaceSet::union_with(const InterfaceSet& other) const { - InterfaceSet result; +const TypeInterfaces* TypeInterfaces::union_with(const TypeInterfaces* other) const { + GrowableArray result_list; int i = 0; int j = 0; - while (i < _list.length() || j < other._list.length()) { + while (i < _list.length() || j < other->_list.length()) { while (i < _list.length() && - (j >= other._list.length() || - compare(_list.at(i), other._list.at(j)) < 0)) { - result.raw_add(_list.at(i)); + (j >= other->_list.length() || + compare(_list.at(i), other->_list.at(j)) < 0)) { + result_list.push(_list.at(i)); i++; } - while (j < other._list.length() && + while (j < other->_list.length() && (i >= _list.length() || - compare(other._list.at(j), _list.at(i)) < 0)) { - result.raw_add(other._list.at(j)); + compare(other->_list.at(j), _list.at(i)) < 0)) { + result_list.push(other->_list.at(j)); j++; } if (i < _list.length() && - j < other._list.length() && - _list.at(i) == other._list.at(j)) { - result.raw_add(_list.at(i)); + j < other->_list.length() && + _list.at(i) == other->_list.at(j)) { + result_list.push(_list.at(i)); i++; j++; } } - result.initialize(); + const TypeInterfaces* result = TypeInterfaces::make(&result_list); #ifdef ASSERT - result.verify(); + result->verify(); for (int i = 0; i < _list.length(); i++) { - assert(result._list.contains(_list.at(i)), "missing"); + assert(result->_list.contains(_list.at(i)), "missing"); } - for (int i = 0; i < other._list.length(); i++) { - assert(result._list.contains(other._list.at(i)), "missing"); + for (int i = 0; i < other->_list.length(); i++) { + assert(result->_list.contains(other->_list.at(i)), "missing"); } - for (int i = 0; i < result._list.length(); i++) { - assert(_list.contains(result._list.at(i)) || other._list.contains(result._list.at(i)), "missing"); + for (int i = 0; i < result->_list.length(); i++) { + assert(_list.contains(result->_list.at(i)) || other->_list.contains(result->_list.at(i)), "missing"); } #endif return result; } -TypePtr::InterfaceSet TypeOopPtr::InterfaceSet::intersection_with(const InterfaceSet& other) const { - InterfaceSet result; +const TypeInterfaces* TypeInterfaces::intersection_with(const TypeInterfaces* other) const { + GrowableArray result_list; int i = 0; int j = 0; - while (i < _list.length() || j < other._list.length()) { + while (i < _list.length() || j < other->_list.length()) { while (i < _list.length() && - (j >= other._list.length() || - compare(_list.at(i), other._list.at(j)) < 0)) { + (j >= other->_list.length() || + compare(_list.at(i), other->_list.at(j)) < 0)) { i++; } - while (j < other._list.length() && + while (j < other->_list.length() && (i >= _list.length() || - compare(other._list.at(j), _list.at(i)) < 0)) { + compare(other->_list.at(j), _list.at(i)) < 0)) { j++; } if (i < _list.length() && - j < other._list.length() && - _list.at(i) == other._list.at(j)) { - result.raw_add(_list.at(i)); + j < other->_list.length() && + _list.at(i) == other->_list.at(j)) { + result_list.push(_list.at(i)); i++; j++; } } - result.initialize(); + const TypeInterfaces* result = TypeInterfaces::make(&result_list); #ifdef ASSERT - result.verify(); + result->verify(); for (int i = 0; i < _list.length(); i++) { - assert(!other._list.contains(_list.at(i)) || result._list.contains(_list.at(i)), "missing"); + assert(!other->_list.contains(_list.at(i)) || result->_list.contains(_list.at(i)), "missing"); } - for (int i = 0; i < other._list.length(); i++) { - assert(!_list.contains(other._list.at(i)) || result._list.contains(other._list.at(i)), "missing"); + for (int i = 0; i < other->_list.length(); i++) { + assert(!_list.contains(other->_list.at(i)) || result->_list.contains(other->_list.at(i)), "missing"); } - for (int i = 0; i < result._list.length(); i++) { - assert(_list.contains(result._list.at(i)) && other._list.contains(result._list.at(i)), "missing"); + for (int i = 0; i < result->_list.length(); i++) { + assert(_list.contains(result->_list.at(i)) && other->_list.contains(result->_list.at(i)), "missing"); } #endif return result; } // Is there a single ciKlass* that can represent the interface set? -ciKlass* TypePtr::InterfaceSet::exact_klass() const { +ciInstanceKlass* TypeInterfaces::exact_klass() const { assert(_initialized, "must be"); return _exact_klass; } -void TypePtr::InterfaceSet::compute_exact_klass() { +void TypeInterfaces::compute_exact_klass() { if (_list.length() == 0) { _exact_klass = nullptr; return; } - ciKlass* res = nullptr; + ciInstanceKlass* res = nullptr; for (int i = 0; i < _list.length(); i++) { - ciInstanceKlass* interface = _list.at(i)->as_instance_klass(); + ciInstanceKlass* interface = _list.at(i); if (eq(interface)) { assert(res == nullptr, ""); res = interface; @@ -3476,7 +3482,7 @@ void TypePtr::InterfaceSet::compute_exact_klass() { } #ifdef ASSERT -void TypePtr::InterfaceSet::verify_is_loaded() const { +void TypeInterfaces::verify_is_loaded() const { for (int i = 0; i < _list.length(); i++) { ciKlass* interface = _list.at(i); assert(interface->is_loaded(), "Interface not loaded"); @@ -3484,8 +3490,19 @@ void TypePtr::InterfaceSet::verify_is_loaded() const { } #endif +// Can't be implemented because there's no way to know if the type is above or below the center line. +const Type* TypeInterfaces::xmeet(const Type* t) const { + ShouldNotReachHere(); + return Type::xmeet(t); +} + +bool TypeInterfaces::singleton(void) const { + ShouldNotReachHere(); + return Type::singleton(); +} + //------------------------------TypeOopPtr------------------------------------- -TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const InterfaceSet& interfaces, bool xk, ciObject* o, int offset, +TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, int offset, int instance_id, const TypePtr* speculative, int inline_depth) : TypePtr(t, ptr, offset, speculative, inline_depth), _const_oop(o), _klass(k), @@ -3497,7 +3514,7 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const InterfaceSet& interfa _instance_id(instance_id) { #ifdef ASSERT if (klass() != nullptr && klass()->is_loaded()) { - interfaces.verify_is_loaded(); + interfaces->verify_is_loaded(); } #endif if (Compile::current()->eliminate_boxing() && (t == InstPtr) && @@ -3574,7 +3591,8 @@ const TypeOopPtr *TypeOopPtr::make(PTR ptr, int offset, int instance_id, ciKlass* k = Compile::current()->env()->Object_klass(); bool xk = false; ciObject* o = nullptr; - return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, InterfaceSet(), xk, o, offset, instance_id, speculative, inline_depth))->hashcons(); + const TypeInterfaces* interfaces = TypeInterfaces::make(); + return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, interfaces, xk, o, offset, instance_id, speculative, inline_depth))->hashcons(); } @@ -3719,7 +3737,7 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass* klass, bool klass_ klass_is_exact = true; } } - const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling); + const TypeInterfaces* interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling); return TypeInstPtr::make(TypePtr::BotPTR, klass, interfaces, klass_is_exact, nullptr, 0); } else if (klass->is_obj_array_klass()) { // Element is an object array. Recursively call ourself. @@ -3952,15 +3970,15 @@ int TypeOopPtr::dual_instance_id( ) const { } -TypePtr::InterfaceSet TypeOopPtr::meet_interfaces(const TypeOopPtr* other) const { +const TypeInterfaces* TypeOopPtr::meet_interfaces(const TypeOopPtr* other) const { if (above_centerline(_ptr) && above_centerline(other->_ptr)) { - return _interfaces.union_with(other->_interfaces); + return _interfaces->union_with(other->_interfaces); } else if (above_centerline(_ptr) && !above_centerline(other->_ptr)) { return other->_interfaces; } else if (above_centerline(other->_ptr) && !above_centerline(_ptr)) { return _interfaces; } - return _interfaces.intersection_with(other->_interfaces); + return _interfaces->intersection_with(other->_interfaces); } /** @@ -3989,20 +4007,20 @@ const TypeInstPtr *TypeInstPtr::KLASS; // Is there a single ciKlass* that can represent that type? ciKlass* TypeInstPtr::exact_klass_helper() const { - if (_interfaces.empty()) { + if (_interfaces->empty()) { return _klass; } if (_klass != ciEnv::current()->Object_klass()) { - if (_interfaces.eq(_klass->as_instance_klass())) { + if (_interfaces->eq(_klass->as_instance_klass())) { return _klass; } return nullptr; } - return _interfaces.exact_klass(); + return _interfaces->exact_klass(); } //------------------------------TypeInstPtr------------------------------------- -TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, const InterfaceSet& interfaces, bool xk, ciObject* o, int off, +TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, int off, int instance_id, const TypePtr* speculative, int inline_depth) : TypeOopPtr(InstPtr, ptr, k, interfaces, xk, o, off, instance_id, speculative, inline_depth) { assert(k == nullptr || !k->is_loaded() || !k->is_interface(), "no interface here"); @@ -4014,7 +4032,7 @@ TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, const InterfaceSet& interfaces, bo //------------------------------make------------------------------------------- const TypeInstPtr *TypeInstPtr::make(PTR ptr, ciKlass* k, - const InterfaceSet& interfaces, + const TypeInterfaces* interfaces, bool xk, ciObject* o, int offset, @@ -4046,17 +4064,17 @@ const TypeInstPtr *TypeInstPtr::make(PTR ptr, return result; } -TypePtr::InterfaceSet TypePtr::interfaces(ciKlass*& k, bool klass, bool interface, bool array, InterfaceHandling interface_handling) { +const TypeInterfaces* TypePtr::interfaces(ciKlass*& k, bool klass, bool interface, bool array, InterfaceHandling interface_handling) { if (k->is_instance_klass()) { if (k->is_loaded()) { if (k->is_interface() && interface_handling == ignore_interfaces) { assert(interface, "no interface expected"); k = ciEnv::current()->Object_klass(); - InterfaceSet interfaces; + const TypeInterfaces* interfaces = TypeInterfaces::make(); return interfaces; } GrowableArray* k_interfaces = k->as_instance_klass()->transitive_interfaces(); - InterfaceSet interfaces(k_interfaces); + const TypeInterfaces* interfaces = TypeInterfaces::make(k_interfaces); if (k->is_interface()) { assert(interface, "no interface expected"); k = ciEnv::current()->Object_klass(); @@ -4065,7 +4083,7 @@ TypePtr::InterfaceSet TypePtr::interfaces(ciKlass*& k, bool klass, bool interfac } return interfaces; } - InterfaceSet interfaces; + const TypeInterfaces* interfaces = TypeInterfaces::make(); return interfaces; } assert(array, "no array expected"); @@ -4076,7 +4094,7 @@ TypePtr::InterfaceSet TypePtr::interfaces(ciKlass*& k, bool klass, bool interfac k = ciObjArrayKlass::make(ciEnv::current()->Object_klass(), k->as_array_klass()->dimension()); } } - return *TypeAryPtr::_array_interfaces; + return TypeAryPtr::_array_interfaces; } /** @@ -4130,7 +4148,7 @@ const TypeInstPtr* TypeInstPtr::cast_to_instance_id(int instance_id) const { //------------------------------xmeet_unloaded--------------------------------- // Compute the MEET of two InstPtrs when at least one is unloaded. // Assume classes are different since called after check for same name/class-loader -const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst, const InterfaceSet& interfaces) const { +const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst, const TypeInterfaces* interfaces) const { int off = meet_offset(tinst->offset()); PTR ptr = meet_ptr(tinst->ptr()); int instance_id = meet_instance_id(tinst->instance_id()); @@ -4287,7 +4305,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { int instance_id = meet_instance_id(tinst->instance_id()); const TypePtr* speculative = xmeet_speculative(tinst); int depth = meet_inline_depth(tinst->inline_depth()); - InterfaceSet interfaces = meet_interfaces(tinst); + const TypeInterfaces* interfaces = meet_interfaces(tinst); ciKlass* tinst_klass = tinst->klass(); ciKlass* this_klass = klass(); @@ -4347,16 +4365,16 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { return this; // Return the double constant } -template TypePtr::MeetResult TypePtr::meet_instptr(PTR& ptr, InterfaceSet& interfaces, const T* this_type, const T* other_type, - ciKlass*& res_klass, bool& res_xk) { +template TypePtr::MeetResult TypePtr::meet_instptr(PTR& ptr, const TypeInterfaces*& interfaces, const T* this_type, const T* other_type, + ciKlass*& res_klass, bool& res_xk) { ciKlass* this_klass = this_type->klass(); ciKlass* other_klass = other_type->klass(); bool this_xk = this_type->klass_is_exact(); bool other_xk = other_type->klass_is_exact(); PTR this_ptr = this_type->ptr(); PTR other_ptr = other_type->ptr(); - InterfaceSet this_interfaces = this_type->interfaces(); - InterfaceSet other_interfaces = other_type->interfaces(); + const TypeInterfaces* this_interfaces = this_type->interfaces(); + const TypeInterfaces* other_interfaces = other_type->interfaces(); // Check for easy case; klasses are equal (and perhaps not loaded!) // If we have constants, then we created oops so classes are loaded // and we can handle the constants further down. This case handles @@ -4441,7 +4459,7 @@ template TypePtr::MeetResult TypePtr::meet_instptr(PTR& ptr, InterfaceS ptr = NotNull; } - interfaces = this_interfaces.intersection_with(other_interfaces); + interfaces = this_interfaces->intersection_with(other_interfaces); // Now we find the LCA of Java classes ciKlass* k = this_klass->least_common_ancestor(other_klass); @@ -4477,14 +4495,14 @@ bool TypeInstPtr::eq( const Type *t ) const { const TypeInstPtr *p = t->is_instptr(); return klass()->equals(p->klass()) && - _interfaces.eq(p->_interfaces) && + _interfaces->eq(p->_interfaces) && TypeOopPtr::eq(p); // Check sub-type stuff } //------------------------------hash------------------------------------------- // Type-specific hashing function. uint TypeInstPtr::hash(void) const { - return klass()->hash() + TypeOopPtr::hash() + _interfaces.hash(); + return klass()->hash() + TypeOopPtr::hash() + _interfaces->hash(); } bool TypeInstPtr::is_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const { @@ -4507,7 +4525,7 @@ bool TypeInstPtr::maybe_java_subtype_of_helper(const TypeOopPtr* other, bool thi void TypeInstPtr::dump2(Dict &d, uint depth, outputStream* st) const { // Print the name of the klass. klass()->print_name_on(st); - _interfaces.dump(st); + _interfaces->dump(st); switch( _ptr ) { case Constant: @@ -4591,7 +4609,7 @@ const TypeKlassPtr* TypeInstPtr::as_klass_type(bool try_for_exact) const { bool xk = klass_is_exact(); ciInstanceKlass* ik = klass()->as_instance_klass(); if (try_for_exact && !xk && !ik->has_subklass() && !ik->is_final()) { - if (_interfaces.eq(ik)) { + if (_interfaces->eq(ik)) { Compile* C = Compile::current(); Dependencies* deps = C->dependencies(); deps->assert_leaf_type(ik); @@ -4608,12 +4626,12 @@ template bool TypePtr::is_meet_subtype_of_helper_for_instan return false; } - if (other->klass() == ciEnv::current()->Object_klass() && other->_interfaces.empty()) { + if (other->klass() == ciEnv::current()->Object_klass() && other->_interfaces->empty()) { return true; } return this_one->klass()->is_subtype_of(other->klass()) && - (!this_xk || this_one->_interfaces.contains(other->_interfaces)); + (!this_xk || this_one->_interfaces->contains(other->_interfaces)); } @@ -4623,12 +4641,12 @@ bool TypeInstPtr::is_meet_subtype_of_helper(const TypeOopPtr *other, bool this_x template bool TypePtr::is_meet_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_xk, bool other_xk) { static_assert(std::is_base_of::value, ""); - if (other->klass() == ciEnv::current()->Object_klass() && other->_interfaces.empty()) { + if (other->klass() == ciEnv::current()->Object_klass() && other->_interfaces->empty()) { return true; } if (this_one->is_instance_type(other)) { - return other->klass() == ciEnv::current()->Object_klass() && this_one->_interfaces.contains(other->_interfaces); + return other->klass() == ciEnv::current()->Object_klass() && this_one->_interfaces->contains(other->_interfaces); } int dummy; @@ -4645,7 +4663,7 @@ template bool TypePtr::is_meet_subtype_of_helper_for_array } if (other_elem == nullptr && this_elem == nullptr) { - return this_one->_klass->is_subtype_of(other->_klass); + return this_one->klass()->is_subtype_of(other->klass()); } return false; @@ -4749,7 +4767,7 @@ const TypeInt* TypeAryPtr::narrow_size_type(const TypeInt* size) const { jint hi = size->_hi; jint lo = size->_lo; jint min_lo = 0; - jint max_hi = max_array_length(elem()->basic_type()); + jint max_hi = max_array_length(elem()->array_element_basic_type()); //if (index_not_size) --max_hi; // type of a valid array index, FTR bool chg = false; if (lo < min_lo) { @@ -4971,9 +4989,9 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { int instance_id = meet_instance_id(tp->instance_id()); const TypePtr* speculative = xmeet_speculative(tp); int depth = meet_inline_depth(tp->inline_depth()); - InterfaceSet interfaces = meet_interfaces(tp); - InterfaceSet tp_interfaces = tp->_interfaces; - InterfaceSet this_interfaces = _interfaces; + const TypeInterfaces* interfaces = meet_interfaces(tp); + const TypeInterfaces* tp_interfaces = tp->_interfaces; + const TypeInterfaces* this_interfaces = _interfaces; switch (ptr) { case TopPTR: @@ -4981,13 +4999,13 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { // For instances when a subclass meets a superclass we fall // below the centerline when the superclass is exact. We need to // do the same here. - if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces.contains(tp_interfaces) && !tp->klass_is_exact()) { + if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) && !tp->klass_is_exact()) { return TypeAryPtr::make(ptr, _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth); } else { // cannot subclass, so the meet has to fall badly below the centerline ptr = NotNull; instance_id = InstanceBot; - interfaces = this_interfaces.intersection_with(tp_interfaces); + interfaces = this_interfaces->intersection_with(tp_interfaces); return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, false, nullptr,offset, instance_id, speculative, depth); } case Constant: @@ -5000,7 +5018,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { // For instances when a subclass meets a superclass we fall // below the centerline when the superclass is exact. We need // to do the same here. - if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces.contains(tp_interfaces) && !tp->klass_is_exact()) { + if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) && !tp->klass_is_exact()) { // that is, my array type is a subtype of 'tp' klass return make(ptr, (ptr == Constant ? const_oop() : nullptr), _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth); @@ -5014,7 +5032,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { if (instance_id > 0) { instance_id = InstanceBot; } - interfaces = this_interfaces.intersection_with(tp_interfaces); + interfaces = this_interfaces->intersection_with(tp_interfaces); return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, false, nullptr, offset, instance_id, speculative, depth); default: typerr(t); } @@ -5128,7 +5146,7 @@ const Type *TypeAryPtr::xdual() const { #ifndef PRODUCT void TypeAryPtr::dump2( Dict &d, uint depth, outputStream *st ) const { _ary->dump2(d,depth,st); - _interfaces.dump(st); + _interfaces->dump(st); switch( _ptr ) { case Constant: @@ -5578,7 +5596,7 @@ const TypeKlassPtr* TypeKlassPtr::make(ciKlass *klass, InterfaceHandling interfa const TypeKlassPtr* TypeKlassPtr::make(PTR ptr, ciKlass* klass, int offset, InterfaceHandling interface_handling) { if (klass->is_instance_klass()) { - const InterfaceSet interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling); + const TypeInterfaces* interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling); return TypeInstKlassPtr::make(ptr, klass, interfaces, offset); } return TypeAryKlassPtr::make(ptr, klass, offset, interface_handling); @@ -5586,7 +5604,7 @@ const TypeKlassPtr* TypeKlassPtr::make(PTR ptr, ciKlass* klass, int offset, Inte //------------------------------TypeKlassPtr----------------------------------- -TypeKlassPtr::TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, const InterfaceSet& interfaces, int offset) +TypeKlassPtr::TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, const TypeInterfaces* interfaces, int offset) : TypePtr(t, ptr, offset), _klass(klass), _interfaces(interfaces) { assert(klass == nullptr || !klass->is_loaded() || (klass->is_instance_klass() && !klass->is_interface()) || klass->is_type_array_klass() || !klass->as_obj_array_klass()->base_element_klass()->is_interface(), "no interface here"); @@ -5595,16 +5613,16 @@ TypeKlassPtr::TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, const InterfaceSet& // Is there a single ciKlass* that can represent that type? ciKlass* TypeKlassPtr::exact_klass_helper() const { assert(_klass->is_instance_klass() && !_klass->is_interface(), "No interface"); - if (_interfaces.empty()) { + if (_interfaces->empty()) { return _klass; } if (_klass != ciEnv::current()->Object_klass()) { - if (_interfaces.eq(_klass->as_instance_klass())) { + if (_interfaces->eq(_klass->as_instance_klass())) { return _klass; } return nullptr; } - return _interfaces.exact_klass(); + return _interfaces->exact_klass(); } //------------------------------eq--------------------------------------------- @@ -5612,14 +5630,14 @@ ciKlass* TypeKlassPtr::exact_klass_helper() const { bool TypeKlassPtr::eq(const Type *t) const { const TypeKlassPtr *p = t->is_klassptr(); return - _interfaces.eq(p->_interfaces) && + _interfaces->eq(p->_interfaces) && TypePtr::eq(p); } //------------------------------hash------------------------------------------- // Type-specific hashing function. uint TypeKlassPtr::hash(void) const { - return TypePtr::hash() + _interfaces.hash(); + return TypePtr::hash() + _interfaces->hash(); } //------------------------------singleton-------------------------------------- @@ -5646,15 +5664,15 @@ const Type *TypeKlassPtr::filter_helper(const Type *kills, bool include_speculat return ft; } -TypePtr::InterfaceSet TypeKlassPtr::meet_interfaces(const TypeKlassPtr* other) const { +const TypeInterfaces* TypeKlassPtr::meet_interfaces(const TypeKlassPtr* other) const { if (above_centerline(_ptr) && above_centerline(other->_ptr)) { - return _interfaces.union_with(other->_interfaces); + return _interfaces->union_with(other->_interfaces); } else if (above_centerline(_ptr) && !above_centerline(other->_ptr)) { return other->_interfaces; } else if (above_centerline(other->_ptr) && !above_centerline(_ptr)) { return _interfaces; } - return _interfaces.intersection_with(other->_interfaces); + return _interfaces->intersection_with(other->_interfaces); } //------------------------------get_con---------------------------------------- @@ -5694,7 +5712,7 @@ void TypeKlassPtr::dump2(Dict & d, uint depth, outputStream *st) const { } else { ShouldNotReachHere(); } - _interfaces.dump(st); + _interfaces->dump(st); } case BotPTR: if (!WizardMode && !Verbose && _ptr != Constant) break; @@ -5735,7 +5753,7 @@ uint TypeInstKlassPtr::hash(void) const { return klass()->hash() + TypeKlassPtr::hash(); } -const TypeInstKlassPtr *TypeInstKlassPtr::make(PTR ptr, ciKlass* k, const InterfaceSet& interfaces, int offset) { +const TypeInstKlassPtr *TypeInstKlassPtr::make(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, int offset) { TypeInstKlassPtr *r = (TypeInstKlassPtr*)(new TypeInstKlassPtr(ptr, k, interfaces, offset))->hashcons(); @@ -5787,7 +5805,7 @@ const TypeOopPtr* TypeInstKlassPtr::as_instance_type(bool klass_change) const { assert((deps != nullptr) == (C->method() != nullptr && C->method()->code_size() > 0), "sanity"); // Element is an instance bool klass_is_exact = false; - TypePtr::InterfaceSet interfaces = _interfaces; + const TypeInterfaces* interfaces = _interfaces; if (k->is_loaded()) { // Try to set klass_is_exact. ciInstanceKlass* ik = k->as_instance_klass(); @@ -5796,7 +5814,7 @@ const TypeOopPtr* TypeInstKlassPtr::as_instance_type(bool klass_change) const { && deps != nullptr && UseUniqueSubclasses) { ciInstanceKlass* sub = ik->unique_concrete_subklass(); if (sub != nullptr) { - if (_interfaces.eq(sub)) { + if (_interfaces->eq(sub)) { deps->assert_abstract_with_unique_concrete_subtype(ik, sub); k = ik = sub; xk = sub->is_final(); @@ -5880,7 +5898,7 @@ const Type *TypeInstKlassPtr::xmeet( const Type *t ) const { const TypeInstKlassPtr *tkls = t->is_instklassptr(); int off = meet_offset(tkls->offset()); PTR ptr = meet_ptr(tkls->ptr()); - InterfaceSet interfaces = meet_interfaces(tkls); + const TypeInterfaces* interfaces = meet_interfaces(tkls); ciKlass* res_klass = nullptr; bool res_xk = false; @@ -5903,9 +5921,9 @@ const Type *TypeInstKlassPtr::xmeet( const Type *t ) const { const TypeAryKlassPtr *tp = t->is_aryklassptr(); int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); - InterfaceSet interfaces = meet_interfaces(tp); - InterfaceSet tp_interfaces = tp->_interfaces; - InterfaceSet this_interfaces = _interfaces; + const TypeInterfaces* interfaces = meet_interfaces(tp); + const TypeInterfaces* tp_interfaces = tp->_interfaces; + const TypeInterfaces* this_interfaces = _interfaces; switch (ptr) { case TopPTR: @@ -5913,12 +5931,12 @@ const Type *TypeInstKlassPtr::xmeet( const Type *t ) const { // For instances when a subclass meets a superclass we fall // below the centerline when the superclass is exact. We need to // do the same here. - if (klass()->equals(ciEnv::current()->Object_klass()) && tp_interfaces.contains(this_interfaces) && !klass_is_exact()) { + if (klass()->equals(ciEnv::current()->Object_klass()) && tp_interfaces->contains(this_interfaces) && !klass_is_exact()) { return TypeAryKlassPtr::make(ptr, tp->elem(), tp->klass(), offset); } else { // cannot subclass, so the meet has to fall badly below the centerline ptr = NotNull; - interfaces = _interfaces.intersection_with(tp->_interfaces); + interfaces = _interfaces->intersection_with(tp->_interfaces); return make(ptr, ciEnv::current()->Object_klass(), interfaces, offset); } case Constant: @@ -5931,7 +5949,7 @@ const Type *TypeInstKlassPtr::xmeet( const Type *t ) const { // For instances when a subclass meets a superclass we fall // below the centerline when the superclass is exact. We need // to do the same here. - if (klass()->equals(ciEnv::current()->Object_klass()) && tp_interfaces.contains(this_interfaces) && !klass_is_exact()) { + if (klass()->equals(ciEnv::current()->Object_klass()) && tp_interfaces->contains(this_interfaces) && !klass_is_exact()) { // that is, tp's array type is a subtype of my klass return TypeAryKlassPtr::make(ptr, tp->elem(), tp->klass(), offset); @@ -5941,7 +5959,7 @@ const Type *TypeInstKlassPtr::xmeet( const Type *t ) const { // The meet falls down to Object class below centerline. if( ptr == Constant ) ptr = NotNull; - interfaces = this_interfaces.intersection_with(tp_interfaces); + interfaces = this_interfaces->intersection_with(tp_interfaces); return make(ptr, ciEnv::current()->Object_klass(), interfaces, offset); default: typerr(t); } @@ -5970,11 +5988,11 @@ template bool TypePtr::is_java_subtype_of_helper_for_instan return false; } - if (other->klass()->equals(ciEnv::current()->Object_klass()) && other->_interfaces.empty()) { + if (other->klass()->equals(ciEnv::current()->Object_klass()) && other->_interfaces->empty()) { return true; } - return this_one->_klass->is_subtype_of(other->_klass) && this_one->_interfaces.contains(other->_interfaces); + return this_one->klass()->is_subtype_of(other->klass()) && this_one->_interfaces->contains(other->_interfaces); } bool TypeInstKlassPtr::is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const { @@ -5989,7 +6007,7 @@ template bool TypePtr::is_same_java_type_as_helper_for_inst if (!this_one->is_instance_type(other)) { return false; } - return this_one->_klass->equals(other->_klass) && this_one->_interfaces.eq(other->_interfaces); + return this_one->klass()->equals(other->klass()) && this_one->_interfaces->eq(other->_interfaces); } bool TypeInstKlassPtr::is_same_java_type_as_helper(const TypeKlassPtr* other) const { @@ -6003,7 +6021,7 @@ template bool TypePtr::maybe_java_subtype_of_helper_for_ins } if (this_one->is_array_type(other)) { - return !this_exact && this_one->_klass->equals(ciEnv::current()->Object_klass()) && other->_interfaces.contains(this_one->_interfaces); + return !this_exact && this_one->klass()->equals(ciEnv::current()->Object_klass()) && other->_interfaces->contains(this_one->_interfaces); } assert(this_one->is_instance_type(other), "unsupported"); @@ -6012,12 +6030,12 @@ template bool TypePtr::maybe_java_subtype_of_helper_for_ins return this_one->is_java_subtype_of(other); } - if (!this_one->_klass->is_subtype_of(other->_klass) && !other->_klass->is_subtype_of(this_one->_klass)) { + if (!this_one->klass()->is_subtype_of(other->klass()) && !other->klass()->is_subtype_of(this_one->klass())) { return false; } if (this_exact) { - return this_one->_klass->is_subtype_of(other->_klass) && this_one->_interfaces.contains(other->_interfaces); + return this_one->klass()->is_subtype_of(other->klass()) && this_one->_interfaces->contains(other->_interfaces); } return true; @@ -6035,7 +6053,7 @@ const TypeKlassPtr* TypeInstKlassPtr::try_improve() const { Compile* C = Compile::current(); Dependencies* deps = C->dependencies(); assert((deps != nullptr) == (C->method() != nullptr && C->method()->code_size() > 0), "sanity"); - TypePtr::InterfaceSet interfaces = _interfaces; + const TypeInterfaces* interfaces = _interfaces; if (k->is_loaded()) { ciInstanceKlass* ik = k->as_instance_klass(); bool klass_is_exact = ik->is_final(); @@ -6043,7 +6061,7 @@ const TypeKlassPtr* TypeInstKlassPtr::try_improve() const { deps != nullptr) { ciInstanceKlass* sub = ik->unique_concrete_subklass(); if (sub != nullptr) { - if (_interfaces.eq(sub)) { + if (_interfaces->eq(sub)) { deps->assert_abstract_with_unique_concrete_subtype(ik, sub); k = ik = sub; klass_is_exact = sub->is_final(); @@ -6097,7 +6115,7 @@ uint TypeAryKlassPtr::hash(void) const { //----------------------compute_klass------------------------------------------ // Compute the defining klass for this class -ciKlass* TypeAryPtr::compute_klass(DEBUG_ONLY(bool verify)) const { +ciKlass* TypeAryPtr::compute_klass() const { // Compute _klass based on element type. ciKlass* k_ary = nullptr; const TypeInstPtr *tinst; @@ -6118,28 +6136,7 @@ ciKlass* TypeAryPtr::compute_klass(DEBUG_ONLY(bool verify)) const { // and object; Top occurs when doing join on Bottom. // Leave k_ary at null. } else { - // Cannot compute array klass directly from basic type, - // since subtypes of TypeInt all have basic type T_INT. -#ifdef ASSERT - if (verify && el->isa_int()) { - // Check simple cases when verifying klass. - BasicType bt = T_ILLEGAL; - if (el == TypeInt::BYTE) { - bt = T_BYTE; - } else if (el == TypeInt::SHORT) { - bt = T_SHORT; - } else if (el == TypeInt::CHAR) { - bt = T_CHAR; - } else if (el == TypeInt::INT) { - bt = T_INT; - } else { - return _klass; // just return specified klass - } - return ciTypeArrayKlass::make(bt); - } -#endif - assert(!el->isa_int(), - "integral arrays must be pre-equipped with a class"); + assert(!el->isa_int(), "integral arrays must be pre-equipped with a class"); // Compute array klass directly from basic type k_ary = ciTypeArrayKlass::make(el->basic_type()); } @@ -6337,9 +6334,9 @@ const Type *TypeAryKlassPtr::xmeet( const Type *t ) const { const TypeInstKlassPtr *tp = t->is_instklassptr(); int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); - InterfaceSet interfaces = meet_interfaces(tp); - InterfaceSet tp_interfaces = tp->_interfaces; - InterfaceSet this_interfaces = _interfaces; + const TypeInterfaces* interfaces = meet_interfaces(tp); + const TypeInterfaces* tp_interfaces = tp->_interfaces; + const TypeInterfaces* this_interfaces = _interfaces; switch (ptr) { case TopPTR: @@ -6347,12 +6344,12 @@ const Type *TypeAryKlassPtr::xmeet( const Type *t ) const { // For instances when a subclass meets a superclass we fall // below the centerline when the superclass is exact. We need to // do the same here. - if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces.intersection_with(tp_interfaces).eq(tp_interfaces) && !tp->klass_is_exact()) { + if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->intersection_with(tp_interfaces)->eq(tp_interfaces) && !tp->klass_is_exact()) { return TypeAryKlassPtr::make(ptr, _elem, _klass, offset); } else { // cannot subclass, so the meet has to fall badly below the centerline ptr = NotNull; - interfaces = this_interfaces.intersection_with(tp->_interfaces); + interfaces = this_interfaces->intersection_with(tp->_interfaces); return TypeInstKlassPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, offset); } case Constant: @@ -6365,7 +6362,7 @@ const Type *TypeAryKlassPtr::xmeet( const Type *t ) const { // For instances when a subclass meets a superclass we fall // below the centerline when the superclass is exact. We need // to do the same here. - if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces.intersection_with(tp_interfaces).eq(tp_interfaces) && !tp->klass_is_exact()) { + if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->intersection_with(tp_interfaces)->eq(tp_interfaces) && !tp->klass_is_exact()) { // that is, my array type is a subtype of 'tp' klass return make(ptr, _elem, _klass, offset); } @@ -6374,7 +6371,7 @@ const Type *TypeAryKlassPtr::xmeet( const Type *t ) const { // The meet falls down to Object class below centerline. if (ptr == Constant) ptr = NotNull; - interfaces = this_interfaces.intersection_with(tp_interfaces); + interfaces = this_interfaces->intersection_with(tp_interfaces); return TypeInstKlassPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, offset); default: typerr(t); } @@ -6387,7 +6384,7 @@ const Type *TypeAryKlassPtr::xmeet( const Type *t ) const { template bool TypePtr::is_java_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_exact, bool other_exact) { static_assert(std::is_base_of::value, ""); - if (other->klass() == ciEnv::current()->Object_klass() && other->_interfaces.empty() && other_exact) { + if (other->klass() == ciEnv::current()->Object_klass() && other->_interfaces->empty() && other_exact) { return true; } @@ -6399,7 +6396,7 @@ template bool TypePtr::is_java_subtype_of_helper_for_array( } if (this_one->is_instance_type(other)) { - return other->klass() == ciEnv::current()->Object_klass() && other->_interfaces.intersection_with(this_one->_interfaces).eq(other->_interfaces) && other_exact; + return other->klass() == ciEnv::current()->Object_klass() && other->_interfaces->intersection_with(this_one->_interfaces)->eq(other->_interfaces) && other_exact; } assert(this_one->is_array_type(other), ""); @@ -6415,7 +6412,7 @@ template bool TypePtr::is_java_subtype_of_helper_for_array( return this_one->is_reference_type(this_elem)->is_java_subtype_of_helper(this_one->is_reference_type(other_elem), this_exact, other_exact); } if (this_elem == nullptr && other_elem == nullptr) { - return this_one->_klass->is_subtype_of(other->_klass); + return this_one->klass()->is_subtype_of(other->klass()); } return false; } @@ -6447,8 +6444,7 @@ template bool TypePtr::is_same_java_type_as_helper_for_arra return this_one->is_reference_type(this_elem)->is_same_java_type_as(this_one->is_reference_type(other_elem)); } if (other_elem == nullptr && this_elem == nullptr) { - assert(this_one->_klass != nullptr && other->_klass != nullptr, ""); - return this_one->_klass->equals(other->_klass); + return this_one->klass()->equals(other->klass()); } return false; } @@ -6459,7 +6455,7 @@ bool TypeAryKlassPtr::is_same_java_type_as_helper(const TypeKlassPtr* other) con template bool TypePtr::maybe_java_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_exact, bool other_exact) { static_assert(std::is_base_of::value, ""); - if (other->klass() == ciEnv::current()->Object_klass() && other->_interfaces.empty() && other_exact) { + if (other->klass() == ciEnv::current()->Object_klass() && other->_interfaces->empty() && other_exact) { return true; } int dummy; @@ -6468,7 +6464,7 @@ template bool TypePtr::maybe_java_subtype_of_helper_for_arr return true; } if (this_one->is_instance_type(other)) { - return other->_klass->equals(ciEnv::current()->Object_klass()) && other->_interfaces.intersection_with(this_one->_interfaces).eq(other->_interfaces); + return other->klass()->equals(ciEnv::current()->Object_klass()) && other->_interfaces->intersection_with(this_one->_interfaces)->eq(other->_interfaces); } assert(this_one->is_array_type(other), ""); @@ -6487,7 +6483,7 @@ template bool TypePtr::maybe_java_subtype_of_helper_for_arr return this_one->is_reference_type(this_elem)->maybe_java_subtype_of_helper(this_one->is_reference_type(other_elem), this_exact, other_exact); } if (other_elem == nullptr && this_elem == nullptr) { - return this_one->_klass->is_subtype_of(other->_klass); + return this_one->klass()->is_subtype_of(other->klass()); } return false; } @@ -6543,7 +6539,7 @@ void TypeAryKlassPtr::dump2( Dict & d, uint depth, outputStream *st ) const { { st->print("["); _elem->dump2(d, depth, st); - _interfaces.dump(st); + _interfaces->dump(st); st->print(": "); } case BotPTR: diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 6cb74c6752193..62f9e27c8f88f 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -94,6 +94,8 @@ class Type { Tuple, // Method signature or object layout Array, // Array types + Interfaces, // Set of implemented interfaces for oop types + VectorMask, // Vector predicate/mask type VectorA, // (Scalable) Vector types for vector length agnostic VectorS, // 32bit Vector types @@ -872,6 +874,48 @@ class TypeVectMask : public TypeVect { static const TypeVectMask* make(const Type* elem, uint length); }; +// Set of implemented interfaces. Referenced from TypeOopPtr and TypeKlassPtr. +class TypeInterfaces : public Type { +private: + GrowableArray _list; + uint _hash; + ciInstanceKlass* _exact_klass; + DEBUG_ONLY(bool _initialized;) + + void initialize(); + + void add(ciInstanceKlass* interface); + void verify() const NOT_DEBUG_RETURN; + void compute_hash(); + void compute_exact_klass(); + TypeInterfaces(); + TypeInterfaces(GrowableArray* interfaces); + + NONCOPYABLE(TypeInterfaces); +public: + static const TypeInterfaces* make(GrowableArray* interfaces = nullptr); + bool eq(const Type* other) const; + bool eq(ciInstanceKlass* k) const; + uint hash() const; + const Type *xdual() const; + void dump(outputStream* st) const; + const TypeInterfaces* union_with(const TypeInterfaces* other) const; + const TypeInterfaces* intersection_with(const TypeInterfaces* other) const; + bool contains(const TypeInterfaces* other) const { + return intersection_with(other)->eq(other); + } + bool empty() const { return _list.length() == 0; } + + ciInstanceKlass* exact_klass() const; + void verify_is_loaded() const NOT_DEBUG_RETURN; + + static int compare(ciInstanceKlass* const& k1, ciInstanceKlass* const& k2); + + const Type* xmeet(const Type* t) const; + + bool singleton(void) const; +}; + //------------------------------TypePtr---------------------------------------- // Class of machine Pointer Types: raw data, instances or arrays. // If the _base enum is AnyPtr, then this refers to all of the above. @@ -881,47 +925,7 @@ class TypePtr : public Type { friend class TypeNarrowPtr; friend class Type; protected: - class InterfaceSet { - private: - GrowableArray _list; - uint _hash; - ciKlass* _exact_klass; - DEBUG_ONLY(bool _initialized;) - - void initialize(); - void raw_add(ciKlass* interface); - void add(ciKlass* interface); - void verify() const NOT_DEBUG_RETURN; - void compute_hash(); - void compute_exact_klass(); - public: - InterfaceSet(); - InterfaceSet(GrowableArray* interfaces); - bool eq(const InterfaceSet& other) const; - bool eq(ciInstanceKlass* k) const; - uint hash() const; - void dump(outputStream* st) const; - InterfaceSet union_with(const InterfaceSet& other) const; - InterfaceSet intersection_with(const InterfaceSet& other) const; - bool contains(const InterfaceSet& other) const { - return intersection_with(other).eq(other); - } - bool empty() const { return _list.length() == 0; } - - inline void* operator new(size_t x) throw() { - Compile* compile = Compile::current(); - return compile->type_arena()->AmallocWords(x); - } - inline void operator delete(void* ptr) { - ShouldNotReachHere(); - } - ciKlass* exact_klass() const; - void verify_is_loaded() const NOT_DEBUG_RETURN; - - static int compare(ciKlass* const& k1, ciKlass* const& k2); - }; - - static InterfaceSet interfaces(ciKlass*& k, bool klass, bool interface, bool array, InterfaceHandling interface_handling); + static const TypeInterfaces* interfaces(ciKlass*& k, bool klass, bool interface, bool array, InterfaceHandling interface_handling); public: enum PTR { TopPTR, AnyNull, Constant, Null, NotNull, BotPTR, lastPTR }; @@ -981,7 +985,7 @@ class TypePtr : public Type { NOT_SUBTYPE, LCA }; - template static TypePtr::MeetResult meet_instptr(PTR& ptr, InterfaceSet& interfaces, const T* this_type, + template static TypePtr::MeetResult meet_instptr(PTR& ptr, const TypeInterfaces*& interfaces, const T* this_type, const T* other_type, ciKlass*& res_klass, bool& res_xk); template static MeetResult meet_aryptr(PTR& ptr, const Type*& elem, const T* this_ary, const T* other_ary, @@ -1103,8 +1107,8 @@ class TypeOopPtr : public TypePtr { friend class TypeInstPtr; friend class TypeAryPtr; protected: - TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const InterfaceSet& interfaces, bool xk, ciObject* o, int offset, int instance_id, - const TypePtr* speculative, int inline_depth); + TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, int offset, int instance_id, + const TypePtr* speculative, int inline_depth); public: virtual bool eq( const Type *t ) const; virtual uint hash() const; // Type specific hashing @@ -1120,7 +1124,7 @@ class TypeOopPtr : public TypePtr { // If _klass is null, then so is _sig. This is an unloaded klass. ciKlass* _klass; // Klass object - const InterfaceSet _interfaces; + const TypeInterfaces* _interfaces; // Does the type exclude subclasses of the klass? (Inexact == polymorphic.) bool _klass_is_exact; @@ -1138,7 +1142,7 @@ class TypeOopPtr : public TypePtr { int dual_instance_id() const; int meet_instance_id(int uid) const; - InterfaceSet meet_interfaces(const TypeOopPtr* other) const; + const TypeInterfaces* meet_interfaces(const TypeOopPtr* other) const; // Do not allow interface-vs.-noninterface joins to collapse to top. virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; @@ -1252,7 +1256,7 @@ class TypeOopPtr : public TypePtr { ShouldNotReachHere(); return false; } - virtual const InterfaceSet interfaces() const { + virtual const TypeInterfaces* interfaces() const { return _interfaces; }; @@ -1273,7 +1277,7 @@ class TypeOopPtr : public TypePtr { // Class of Java object pointers, pointing either to non-array Java instances // or to a Klass* (including array klasses). class TypeInstPtr : public TypeOopPtr { - TypeInstPtr(PTR ptr, ciKlass* k, const InterfaceSet& interfaces, bool xk, ciObject* o, int offset, int instance_id, + TypeInstPtr(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, int off, int instance_id, const TypePtr* speculative, int inline_depth); virtual bool eq( const Type *t ) const; virtual uint hash() const; // Type specific hashing @@ -1295,41 +1299,41 @@ class TypeInstPtr : public TypeOopPtr { // Make a pointer to a constant oop. static const TypeInstPtr *make(ciObject* o) { ciKlass* k = o->klass(); - const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces); + const TypeInterfaces* interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces); return make(TypePtr::Constant, k, interfaces, true, o, 0, InstanceBot); } // Make a pointer to a constant oop with offset. static const TypeInstPtr *make(ciObject* o, int offset) { ciKlass* k = o->klass(); - const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces); + const TypeInterfaces* interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces); return make(TypePtr::Constant, k, interfaces, true, o, offset, InstanceBot); } // Make a pointer to some value of type klass. static const TypeInstPtr *make(PTR ptr, ciKlass* klass, InterfaceHandling interface_handling = ignore_interfaces) { - const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling); + const TypeInterfaces* interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling); return make(ptr, klass, interfaces, false, nullptr, 0, InstanceBot); } // Make a pointer to some non-polymorphic value of exactly type klass. static const TypeInstPtr *make_exact(PTR ptr, ciKlass* klass) { - const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(klass, true, false, false, ignore_interfaces); + const TypeInterfaces* interfaces = TypePtr::interfaces(klass, true, false, false, ignore_interfaces); return make(ptr, klass, interfaces, true, nullptr, 0, InstanceBot); } // Make a pointer to some value of type klass with offset. static const TypeInstPtr *make(PTR ptr, ciKlass* klass, int offset) { - const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(klass, true, false, false, ignore_interfaces); + const TypeInterfaces* interfaces = TypePtr::interfaces(klass, true, false, false, ignore_interfaces); return make(ptr, klass, interfaces, false, nullptr, offset, InstanceBot); } - static const TypeInstPtr *make(PTR ptr, ciKlass* k, const InterfaceSet& interfaces, bool xk, ciObject* o, int offset, + static const TypeInstPtr *make(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, int offset, int instance_id = InstanceBot, const TypePtr* speculative = nullptr, int inline_depth = InlineDepthBottom); static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id = InstanceBot) { - const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces); + const TypeInterfaces* interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces); return make(ptr, k, interfaces, xk, o, offset, instance_id); } @@ -1357,7 +1361,7 @@ class TypeInstPtr : public TypeOopPtr { // the core of the computation of the meet of 2 types virtual const Type *xmeet_helper(const Type *t) const; - virtual const TypeInstPtr *xmeet_unloaded(const TypeInstPtr *t, const InterfaceSet& interfaces) const; + virtual const TypeInstPtr *xmeet_unloaded(const TypeInstPtr *tinst, const TypeInterfaces* interfaces) const; virtual const Type *xdual() const; // Compute dual right now. const TypeKlassPtr* as_klass_type(bool try_for_exact = false) const; @@ -1376,7 +1380,7 @@ class TypeInstPtr : public TypeOopPtr { virtual bool is_meet_subtype_of_helper(const TypeOopPtr* other, bool this_xk, bool other_xk) const; virtual bool is_meet_same_type_as(const TypePtr* other) const { - return _klass->equals(other->is_instptr()->_klass) && _interfaces.eq(other->is_instptr()->_interfaces); + return _klass->equals(other->is_instptr()->_klass) && _interfaces->eq(other->is_instptr()->_interfaces); } }; @@ -1390,7 +1394,7 @@ class TypeAryPtr : public TypeOopPtr { TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, bool is_autobox_cache, const TypePtr* speculative, int inline_depth) - : TypeOopPtr(AryPtr,ptr,k,*_array_interfaces,xk,o,offset, instance_id, speculative, inline_depth), + : TypeOopPtr(AryPtr,ptr,k,_array_interfaces,xk,o,offset, instance_id, speculative, inline_depth), _ary(ary), _is_autobox_cache(is_autobox_cache) { @@ -1409,11 +1413,11 @@ class TypeAryPtr : public TypeOopPtr { const TypeAry *_ary; // Array we point into const bool _is_autobox_cache; - ciKlass* compute_klass(DEBUG_ONLY(bool verify = false)) const; + ciKlass* compute_klass() const; // A pointer to delay allocation to Type::Initialize_shared() - static const InterfaceSet* _array_interfaces; + static const TypeInterfaces* _array_interfaces; ciKlass* exact_klass_helper() const; // Only guaranteed non null for array of basic types ciKlass* klass() const; @@ -1551,7 +1555,7 @@ class TypeKlassPtr : public TypePtr { friend class TypeAryKlassPtr; friend class TypePtr; protected: - TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, const InterfaceSet& interfaces, int offset); + TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, const TypeInterfaces* interfaces, int offset); virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; @@ -1563,8 +1567,8 @@ class TypeKlassPtr : public TypePtr { protected: ciKlass* _klass; - const InterfaceSet _interfaces; - InterfaceSet meet_interfaces(const TypeKlassPtr* other) const; + const TypeInterfaces* _interfaces; + const TypeInterfaces* meet_interfaces(const TypeKlassPtr* other) const; virtual bool must_be_exact() const { ShouldNotReachHere(); return false; } virtual ciKlass* exact_klass_helper() const; virtual ciKlass* klass() const { return _klass; } @@ -1623,7 +1627,7 @@ class TypeKlassPtr : public TypePtr { ShouldNotReachHere(); return false; } - virtual const InterfaceSet interfaces() const { + virtual const TypeInterfaces* interfaces() const { return _interfaces; }; @@ -1643,7 +1647,7 @@ class TypeKlassPtr : public TypePtr { // Instance klass pointer, mirrors TypeInstPtr class TypeInstKlassPtr : public TypeKlassPtr { - TypeInstKlassPtr(PTR ptr, ciKlass* klass, const InterfaceSet& interfaces, int offset) + TypeInstKlassPtr(PTR ptr, ciKlass* klass, const TypeInterfaces* interfaces, int offset) : TypeKlassPtr(InstKlassPtr, ptr, klass, interfaces, offset) { assert(klass->is_instance_klass() && (!klass->is_loaded() || !klass->is_interface()), ""); } @@ -1662,13 +1666,13 @@ class TypeInstKlassPtr : public TypeKlassPtr { bool maybe_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const; static const TypeInstKlassPtr *make(ciKlass* k, InterfaceHandling interface_handling) { - InterfaceSet interfaces = TypePtr::interfaces(k, true, true, false, interface_handling); + const TypeInterfaces* interfaces = TypePtr::interfaces(k, true, true, false, interface_handling); return make(TypePtr::Constant, k, interfaces, 0); } - static const TypeInstKlassPtr* make(PTR ptr, ciKlass* k, const InterfaceSet& interfaces, int offset); + static const TypeInstKlassPtr* make(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, int offset); static const TypeInstKlassPtr* make(PTR ptr, ciKlass* k, int offset) { - const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces); + const TypeInterfaces* interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces); return make(ptr, k, interfaces, offset); } @@ -1703,9 +1707,9 @@ class TypeAryKlassPtr : public TypeKlassPtr { const Type *_elem; - static const InterfaceSet* _array_interfaces; + static const TypeInterfaces* _array_interfaces; TypeAryKlassPtr(PTR ptr, const Type *elem, ciKlass* klass, int offset) - : TypeKlassPtr(AryKlassPtr, ptr, klass, *_array_interfaces, offset), _elem(elem) { + : TypeKlassPtr(AryKlassPtr, ptr, klass, _array_interfaces, offset), _elem(elem) { assert(klass == nullptr || klass->is_type_array_klass() || !klass->as_obj_array_klass()->base_element_klass()->is_interface(), ""); } diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 9b8c97249b1e8..0d477d67eab88 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -930,6 +930,11 @@ static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receive } } + if (selected_method->is_abstract()) { + ResourceMark rm(THREAD); + THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), selected_method->name()->as_C_string()); + } + methodHandle method(THREAD, selected_method); // Create object to hold arguments for the JavaCall, and associate it with @@ -2876,7 +2881,7 @@ JNI_ENTRY(jweak, jni_NewWeakGlobalRef(JNIEnv *env, jobject ref)) HOTSPOT_JNI_NEWWEAKGLOBALREF_ENTRY(env, ref); Handle ref_handle(thread, JNIHandles::resolve(ref)); jweak ret = JNIHandles::make_weak_global(ref_handle, AllocFailStrategy::RETURN_NULL); - if (ret == nullptr) { + if (ret == nullptr && ref_handle.not_null()) { THROW_OOP_(Universe::out_of_memory_error_c_heap(), nullptr); } HOTSPOT_JNI_NEWWEAKGLOBALREF_RETURN(ret); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 9f5327eb31376..7852f37d4be25 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -1385,9 +1385,8 @@ JVM_ENTRY(jobject, JVM_FindScopedValueBindings(JNIEnv *env, jclass cls)) InstanceKlass* holder = method->method_holder(); if (name == vmSymbols::runWith_method_name()) { - if ((holder == resolver.Carrier_klass - || holder == vmClasses::VirtualThread_klass() - || holder == vmClasses::Thread_klass())) { + if (holder == vmClasses::Thread_klass() + || holder == resolver.Carrier_klass) { loc = 1; } } diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index e82e4de0f6678..15472787f645d 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -1009,7 +1009,7 @@ JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvm jvmtiError JvmtiEnv::SuspendAllVirtualThreads(jint except_count, const jthread* except_list) { - if (!JvmtiExport::can_support_virtual_threads()) { + if (get_capabilities()->can_support_virtual_threads == 0) { return JVMTI_ERROR_MUST_POSSESS_CAPABILITY; } JavaThread* current = JavaThread::current(); @@ -1127,7 +1127,7 @@ JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmt jvmtiError JvmtiEnv::ResumeAllVirtualThreads(jint except_count, const jthread* except_list) { - if (!JvmtiExport::can_support_virtual_threads()) { + if (get_capabilities()->can_support_virtual_threads == 0) { return JVMTI_ERROR_MUST_POSSESS_CAPABILITY; } jvmtiError err = JvmtiEnvBase::check_thread_list(except_count, except_list); diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 9e12e9d51e006..105902b964263 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -213,7 +213,8 @@ JvmtiEnvBase::JvmtiEnvBase(jint version) : _env_event_enable() { _is_retransformable = true; // all callbacks initially null - memset(&_event_callbacks,0,sizeof(jvmtiEventCallbacks)); + memset(&_event_callbacks, 0, sizeof(jvmtiEventCallbacks)); + memset(&_ext_event_callbacks, 0, sizeof(jvmtiExtEventCallbacks)); // all capabilities initially off memset(&_current_capabilities, 0, sizeof(_current_capabilities)); diff --git a/src/hotspot/share/prims/jvmtiEventController.cpp b/src/hotspot/share/prims/jvmtiEventController.cpp index 033365071229d..0a01c3263e136 100644 --- a/src/hotspot/share/prims/jvmtiEventController.cpp +++ b/src/hotspot/share/prims/jvmtiEventController.cpp @@ -309,6 +309,8 @@ class JvmtiEventControllerPrivate : public AllStatic { static void clear_to_frame_pop(JvmtiEnvThreadState *env_thread, JvmtiFramePop fpop); static void change_field_watch(jvmtiEvent event_type, bool added); + static bool is_any_thread_filtered_event_enabled_globally(); + static void recompute_thread_filtered(JvmtiThreadState *state); static void thread_started(JavaThread *thread); static void thread_ended(JavaThread *thread); @@ -729,6 +731,20 @@ JvmtiEventControllerPrivate::recompute_enabled() { EC_TRACE(("[-] # recompute enabled - after " JULONG_FORMAT_X, any_env_thread_enabled)); } +bool +JvmtiEventControllerPrivate::is_any_thread_filtered_event_enabled_globally() { + julong global_thread_events = JvmtiEventController::_universal_global_event_enabled.get_bits() & THREAD_FILTERED_EVENT_BITS; + return global_thread_events != 0L; +} + +void +JvmtiEventControllerPrivate::recompute_thread_filtered(JvmtiThreadState *state) { + assert(Threads::number_of_threads() == 0 || JvmtiThreadState_lock->is_locked(), "sanity check"); + + if (is_any_thread_filtered_event_enabled_globally()) { + JvmtiEventControllerPrivate::recompute_thread_enabled(state); + } +} void JvmtiEventControllerPrivate::thread_started(JavaThread *thread) { @@ -738,17 +754,11 @@ JvmtiEventControllerPrivate::thread_started(JavaThread *thread) { EC_TRACE(("[%s] # thread started", JvmtiTrace::safe_get_thread_name(thread))); // if we have any thread filtered events globally enabled, create/update the thread state - if ((JvmtiEventController::_universal_global_event_enabled.get_bits() & THREAD_FILTERED_EVENT_BITS) != 0) { - MutexLocker mu(JvmtiThreadState_lock); - // create the thread state if missing - JvmtiThreadState *state = JvmtiThreadState::state_for_while_locked(thread); - if (state != nullptr) { // skip threads with no JVMTI thread state - recompute_thread_enabled(state); - } + if (is_any_thread_filtered_event_enabled_globally()) { // intentionally racy + JvmtiThreadState::state_for(thread); } } - void JvmtiEventControllerPrivate::thread_ended(JavaThread *thread) { // Removes the JvmtiThreadState associated with the specified thread. @@ -1114,6 +1124,11 @@ JvmtiEventController::change_field_watch(jvmtiEvent event_type, bool added) { JvmtiEventControllerPrivate::change_field_watch(event_type, added); } +void +JvmtiEventController::recompute_thread_filtered(JvmtiThreadState *state) { + JvmtiEventControllerPrivate::recompute_thread_filtered(state); +} + void JvmtiEventController::thread_started(JavaThread *thread) { // operates only on the current thread diff --git a/src/hotspot/share/prims/jvmtiEventController.hpp b/src/hotspot/share/prims/jvmtiEventController.hpp index 9b236b29204fb..84070a3098c2c 100644 --- a/src/hotspot/share/prims/jvmtiEventController.hpp +++ b/src/hotspot/share/prims/jvmtiEventController.hpp @@ -234,6 +234,7 @@ class JvmtiEventController : AllStatic { static void change_field_watch(jvmtiEvent event_type, bool added); + static void recompute_thread_filtered(JvmtiThreadState *state); static void thread_started(JavaThread *thread); static void thread_ended(JavaThread *thread); diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 5585eb124054d..0466bf8096035 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -417,6 +417,15 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { } } +JvmtiThreadState* +JvmtiExport::get_jvmti_thread_state(JavaThread *thread) { + assert(thread == JavaThread::current(), "must be current thread"); + if (thread->is_vthread_mounted() && thread->jvmti_thread_state() == nullptr) { + JvmtiEventController::thread_started(thread); + } + return thread->jvmti_thread_state(); +} + void JvmtiExport::add_default_read_edges(Handle h_module, TRAPS) { if (!Universe::is_module_initialized()) { @@ -920,7 +929,7 @@ class JvmtiClassFileLoadHookPoster : public StackObj { _has_been_modified = false; assert(!_thread->is_in_any_VTMS_transition(), "CFLH events are not allowed in any VTMS transition"); - _state = _thread->jvmti_thread_state(); + _state = JvmtiExport::get_jvmti_thread_state(_thread); if (_state != nullptr) { _class_being_redefined = _state->get_class_being_redefined(); _load_kind = _state->get_class_load_kind(); @@ -1209,7 +1218,7 @@ void JvmtiExport::post_raw_breakpoint(JavaThread *thread, Method* method, addres HandleMark hm(thread); methodHandle mh(thread, method); - JvmtiThreadState *state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -1307,7 +1316,7 @@ void JvmtiExport::at_single_stepping_point(JavaThread *thread, Method* method, a methodHandle mh(thread, method); // update information about current location and post a step event - JvmtiThreadState *state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -1326,7 +1335,7 @@ void JvmtiExport::at_single_stepping_point(JavaThread *thread, Method* method, a void JvmtiExport::expose_single_stepping(JavaThread *thread) { - JvmtiThreadState *state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state != nullptr) { state->clear_hide_single_stepping(); } @@ -1334,7 +1343,7 @@ void JvmtiExport::expose_single_stepping(JavaThread *thread) { bool JvmtiExport::hide_single_stepping(JavaThread *thread) { - JvmtiThreadState *state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state != nullptr && state->is_enabled(JVMTI_EVENT_SINGLE_STEP)) { state->set_hide_single_stepping(); return true; @@ -1349,7 +1358,7 @@ void JvmtiExport::post_class_load(JavaThread *thread, Klass* klass) { } HandleMark hm(thread); - JvmtiThreadState* state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -1387,7 +1396,7 @@ void JvmtiExport::post_class_prepare(JavaThread *thread, Klass* klass) { } HandleMark hm(thread); - JvmtiThreadState* state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -1516,7 +1525,7 @@ void JvmtiExport::post_thread_end(JavaThread *thread) { EVT_TRIG_TRACE(JVMTI_EVENT_THREAD_END, ("[%s] Trg Thread End event triggered", JvmtiTrace::safe_get_thread_name(thread))); - JvmtiThreadState *state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -1564,7 +1573,7 @@ void JvmtiExport::post_vthread_start(jobject vthread) { EVT_TRIG_TRACE(JVMTI_EVENT_VIRTUAL_THREAD_START, ("[%p] Trg Virtual Thread Start event triggered", vthread)); JavaThread *cur_thread = JavaThread::current(); - JvmtiThreadState *state = cur_thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(cur_thread); if (state == nullptr) { return; } @@ -1598,7 +1607,7 @@ void JvmtiExport::post_vthread_end(jobject vthread) { EVT_TRIG_TRACE(JVMTI_EVENT_VIRTUAL_THREAD_END, ("[%p] Trg Virtual Thread End event triggered", vthread)); JavaThread *cur_thread = JavaThread::current(); - JvmtiThreadState *state = cur_thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(cur_thread); if (state == nullptr) { return; } @@ -1633,7 +1642,7 @@ void JvmtiExport::post_vthread_mount(jobject vthread) { HandleMark hm(thread); EVT_TRIG_TRACE(EXT_EVENT_VIRTUAL_THREAD_MOUNT, ("[%p] Trg Virtual Thread Mount event triggered", vthread)); - JvmtiThreadState *state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -1668,7 +1677,7 @@ void JvmtiExport::post_vthread_unmount(jobject vthread) { HandleMark hm(thread); EVT_TRIG_TRACE(EXT_EVENT_VIRTUAL_THREAD_UNMOUNT, ("[%p] Trg Virtual Thread Unmount event triggered", vthread)); - JvmtiThreadState *state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -1701,7 +1710,7 @@ void JvmtiExport::continuation_yield_cleanup(JavaThread* thread, jint continuati } assert(thread == JavaThread::current(), "must be"); - JvmtiThreadState *state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -1795,7 +1804,7 @@ void JvmtiExport::post_method_entry(JavaThread *thread, Method* method, frame cu HandleMark hm(thread); methodHandle mh(thread, method); - JvmtiThreadState* state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr || !state->is_interp_only_mode()) { // for any thread that actually wants method entry, interp_only_mode is set return; @@ -1835,7 +1844,7 @@ void JvmtiExport::post_method_exit(JavaThread* thread, Method* method, frame cur HandleMark hm(thread); methodHandle mh(thread, method); - JvmtiThreadState *state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr || !state->is_interp_only_mode()) { // for any thread that actually wants method exit, interp_only_mode is set @@ -1956,7 +1965,7 @@ void JvmtiExport::post_single_step(JavaThread *thread, Method* method, address l HandleMark hm(thread); methodHandle mh(thread, method); - JvmtiThreadState *state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -1998,7 +2007,7 @@ void JvmtiExport::post_exception_throw(JavaThread *thread, Method* method, addre // ensure the stack is sufficiently processed. KeepStackGCProcessedMark ksgcpm(thread); - JvmtiThreadState *state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -2086,7 +2095,7 @@ void JvmtiExport::notice_unwind_due_to_exception(JavaThread *thread, Method* met methodHandle mh(thread, method); Handle exception_handle(thread, exception); - JvmtiThreadState *state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -2202,7 +2211,7 @@ void JvmtiExport::post_field_access(JavaThread *thread, Method* method, HandleMark hm(thread); methodHandle mh(thread, method); - JvmtiThreadState *state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -2358,7 +2367,7 @@ void JvmtiExport::post_field_modification(JavaThread *thread, Method* method, HandleMark hm(thread); methodHandle mh(thread, method); - JvmtiThreadState *state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -2600,7 +2609,7 @@ void JvmtiExport::post_dynamic_code_generated_while_holding_locks(const char* na // jvmti thread state. // The collector and/or state might be null if JvmtiDynamicCodeEventCollector // has been initialized while JVMTI_EVENT_DYNAMIC_CODE_GENERATED was disabled. - JvmtiThreadState* state = thread->jvmti_thread_state(); + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state != nullptr) { JvmtiDynamicCodeEventCollector *collector = state->get_dynamic_code_event_collector(); if (collector != nullptr) { @@ -2719,7 +2728,10 @@ void JvmtiExport::post_data_dump() { void JvmtiExport::post_monitor_contended_enter(JavaThread *thread, ObjectMonitor *obj_mntr) { oop object = obj_mntr->object(); - JvmtiThreadState *state = thread->jvmti_thread_state(); + HandleMark hm(thread); + Handle h(thread, object); + + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -2727,9 +2739,6 @@ void JvmtiExport::post_monitor_contended_enter(JavaThread *thread, ObjectMonitor return; // no events should be posted if thread is in any VTMS transition } - HandleMark hm(thread); - Handle h(thread, object); - EVT_TRIG_TRACE(JVMTI_EVENT_MONITOR_CONTENDED_ENTER, ("[%s] monitor contended enter event triggered", JvmtiTrace::safe_get_thread_name(thread))); @@ -2752,7 +2761,10 @@ void JvmtiExport::post_monitor_contended_enter(JavaThread *thread, ObjectMonitor void JvmtiExport::post_monitor_contended_entered(JavaThread *thread, ObjectMonitor *obj_mntr) { oop object = obj_mntr->object(); - JvmtiThreadState *state = thread->jvmti_thread_state(); + HandleMark hm(thread); + Handle h(thread, object); + + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -2760,9 +2772,6 @@ void JvmtiExport::post_monitor_contended_entered(JavaThread *thread, ObjectMonit return; // no events should be posted if thread is in any VTMS transition } - HandleMark hm(thread); - Handle h(thread, object); - EVT_TRIG_TRACE(JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, ("[%s] monitor contended entered event triggered", JvmtiTrace::safe_get_thread_name(thread))); @@ -2786,7 +2795,10 @@ void JvmtiExport::post_monitor_contended_entered(JavaThread *thread, ObjectMonit void JvmtiExport::post_monitor_wait(JavaThread *thread, oop object, jlong timeout) { - JvmtiThreadState *state = thread->jvmti_thread_state(); + HandleMark hm(thread); + Handle h(thread, object); + + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -2794,9 +2806,6 @@ void JvmtiExport::post_monitor_wait(JavaThread *thread, oop object, return; // no events should be posted if thread is in any VTMS transition } - HandleMark hm(thread); - Handle h(thread, object); - EVT_TRIG_TRACE(JVMTI_EVENT_MONITOR_WAIT, ("[%s] monitor wait event triggered", JvmtiTrace::safe_get_thread_name(thread))); @@ -2820,7 +2829,10 @@ void JvmtiExport::post_monitor_wait(JavaThread *thread, oop object, void JvmtiExport::post_monitor_waited(JavaThread *thread, ObjectMonitor *obj_mntr, jboolean timed_out) { oop object = obj_mntr->object(); - JvmtiThreadState *state = thread->jvmti_thread_state(); + HandleMark hm(thread); + Handle h(thread, object); + + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -2828,9 +2840,6 @@ void JvmtiExport::post_monitor_waited(JavaThread *thread, ObjectMonitor *obj_mnt return; // no events should be posted if thread is in any VTMS transition } - HandleMark hm(thread); - Handle h(thread, object); - EVT_TRIG_TRACE(JVMTI_EVENT_MONITOR_WAITED, ("[%s] monitor waited event triggered", JvmtiTrace::safe_get_thread_name(thread))); @@ -2883,7 +2892,10 @@ void JvmtiExport::post_vm_object_alloc(JavaThread *thread, oop object) { } void JvmtiExport::post_sampled_object_alloc(JavaThread *thread, oop object) { - JvmtiThreadState *state = thread->jvmti_thread_state(); + HandleMark hm(thread); + Handle h(thread, object); + + JvmtiThreadState *state = get_jvmti_thread_state(thread); if (state == nullptr) { return; } @@ -2893,8 +2905,6 @@ void JvmtiExport::post_sampled_object_alloc(JavaThread *thread, oop object) { if (thread->is_in_any_VTMS_transition()) { return; // no events should be posted if thread is in any VTMS transition } - HandleMark hm(thread); - Handle h(thread, object); EVT_TRIG_TRACE(JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, ("[%s] Trg sampled object alloc triggered", diff --git a/src/hotspot/share/prims/jvmtiExport.hpp b/src/hotspot/share/prims/jvmtiExport.hpp index 4abd8f6b1a8ec..805c8c090dacc 100644 --- a/src/hotspot/share/prims/jvmtiExport.hpp +++ b/src/hotspot/share/prims/jvmtiExport.hpp @@ -298,6 +298,11 @@ class JvmtiExport : public AllStatic { static void decode_version_values(jint version, int * major, int * minor, int * micro) NOT_JVMTI_RETURN; + // If the jvmti_thread_state is absent and any thread filtered event + // is enabled globally then it is created. + // Otherwise, the thread->jvmti_thread_state() is returned. + static JvmtiThreadState* get_jvmti_thread_state(JavaThread *thread); + // single stepping management methods static void at_single_stepping_point(JavaThread *thread, Method* method, address location) NOT_JVMTI_RETURN; static void expose_single_stepping(JavaThread *thread) NOT_JVMTI_RETURN; diff --git a/src/hotspot/share/prims/jvmtiManageCapabilities.cpp b/src/hotspot/share/prims/jvmtiManageCapabilities.cpp index a3b256af84a8f..5bb354b704c04 100644 --- a/src/hotspot/share/prims/jvmtiManageCapabilities.cpp +++ b/src/hotspot/share/prims/jvmtiManageCapabilities.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "jvmtifiles/jvmtiEnv.hpp" #include "logging/log.hpp" +#include "runtime/mutexLocker.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiManageCapabilities.hpp" @@ -55,7 +56,12 @@ jvmtiCapabilities JvmtiManageCapabilities::onload_solo_remaining_capabilities; // all capabilities ever acquired jvmtiCapabilities JvmtiManageCapabilities::acquired_capabilities; +int JvmtiManageCapabilities::_can_support_virtual_threads_count = 0; + +Mutex* JvmtiManageCapabilities::_capabilities_lock = nullptr; + void JvmtiManageCapabilities::initialize() { + _capabilities_lock = new Mutex(Mutex::nosafepoint, "Capabilities_lock"); always_capabilities = init_always_capabilities(); onload_capabilities = init_onload_capabilities(); always_solo_capabilities = init_always_solo_capabilities(); @@ -211,8 +217,14 @@ void JvmtiManageCapabilities::copy_capabilities(const jvmtiCapabilities *from, j } } +Mutex* JvmtiManageCapabilities::lock() { + if (Thread::current_or_null() == nullptr) { + return nullptr; // Detached thread, can be a call from Agent_OnLoad. + } + return _capabilities_lock; +} -void JvmtiManageCapabilities::get_potential_capabilities(const jvmtiCapabilities *current, +void JvmtiManageCapabilities::get_potential_capabilities_nolock(const jvmtiCapabilities *current, const jvmtiCapabilities *prohibited, jvmtiCapabilities *result) { // exclude prohibited capabilities, must be before adding current @@ -231,13 +243,22 @@ void JvmtiManageCapabilities::get_potential_capabilities(const jvmtiCapabilities } } +void JvmtiManageCapabilities::get_potential_capabilities(const jvmtiCapabilities* current, + const jvmtiCapabilities* prohibited, + jvmtiCapabilities* result) { + MutexLocker ml(lock(), Mutex::_no_safepoint_check_flag); + get_potential_capabilities_nolock(current, prohibited, result); +} + jvmtiError JvmtiManageCapabilities::add_capabilities(const jvmtiCapabilities *current, const jvmtiCapabilities *prohibited, const jvmtiCapabilities *desired, jvmtiCapabilities *result) { + MutexLocker ml(lock(), Mutex::_no_safepoint_check_flag); + // check that the capabilities being added are potential capabilities jvmtiCapabilities temp; - get_potential_capabilities(current, prohibited, &temp); + get_potential_capabilities_nolock(current, prohibited, &temp); if (has_some(exclude(desired, &temp, &temp))) { return JVMTI_ERROR_NOT_AVAILABLE; } @@ -259,6 +280,10 @@ jvmtiError JvmtiManageCapabilities::add_capabilities(const jvmtiCapabilities *cu exclude(&always_solo_remaining_capabilities, desired, &always_solo_remaining_capabilities); exclude(&onload_solo_remaining_capabilities, desired, &onload_solo_remaining_capabilities); + if (desired->can_support_virtual_threads != 0 && current->can_support_virtual_threads == 0) { + _can_support_virtual_threads_count++; + } + // return the result either(current, desired, result); @@ -271,6 +296,8 @@ jvmtiError JvmtiManageCapabilities::add_capabilities(const jvmtiCapabilities *cu void JvmtiManageCapabilities::relinquish_capabilities(const jvmtiCapabilities *current, const jvmtiCapabilities *unwanted, jvmtiCapabilities *result) { + MutexLocker ml(lock(), Mutex::_no_safepoint_check_flag); + jvmtiCapabilities to_trash; jvmtiCapabilities temp; @@ -283,6 +310,12 @@ void JvmtiManageCapabilities::relinquish_capabilities(const jvmtiCapabilities *c either(&onload_solo_remaining_capabilities, both(&onload_solo_capabilities, &to_trash, &temp), &onload_solo_remaining_capabilities); + if (to_trash.can_support_virtual_threads != 0) { + assert(current->can_support_virtual_threads != 0, "sanity check"); + assert(_can_support_virtual_threads_count > 0, "sanity check"); + _can_support_virtual_threads_count--; + } + update(); // return the result @@ -366,7 +399,7 @@ void JvmtiManageCapabilities::update() { JvmtiExport::set_can_post_frame_pop(avail.can_generate_frame_pop_events); JvmtiExport::set_can_pop_frame(avail.can_pop_frame); JvmtiExport::set_can_force_early_return(avail.can_force_early_return); - JvmtiExport::set_can_support_virtual_threads(avail.can_support_virtual_threads); + JvmtiExport::set_can_support_virtual_threads(_can_support_virtual_threads_count != 0); JvmtiExport::set_should_clean_up_heap_objects(avail.can_generate_breakpoint_events); JvmtiExport::set_can_get_owned_monitor_info(avail.can_get_owned_monitor_info || avail.can_get_owned_monitor_stack_depth_info); diff --git a/src/hotspot/share/prims/jvmtiManageCapabilities.hpp b/src/hotspot/share/prims/jvmtiManageCapabilities.hpp index e588be4fa1579..545909e3c4eac 100644 --- a/src/hotspot/share/prims/jvmtiManageCapabilities.hpp +++ b/src/hotspot/share/prims/jvmtiManageCapabilities.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,12 @@ class JvmtiManageCapabilities : public AllStatic { // all capabilities ever acquired static jvmtiCapabilities acquired_capabilities; + // counter for the agents possess can_support_virtual_threads capability + static int _can_support_virtual_threads_count; + + // lock to access the class data + static Mutex* _capabilities_lock; + // basic intenal operations static jvmtiCapabilities *either(const jvmtiCapabilities *a, const jvmtiCapabilities *b, jvmtiCapabilities *result); static jvmtiCapabilities *both(const jvmtiCapabilities *a, const jvmtiCapabilities *b, jvmtiCapabilities *result); @@ -61,6 +67,14 @@ class JvmtiManageCapabilities : public AllStatic { static jvmtiCapabilities init_always_solo_capabilities(); static jvmtiCapabilities init_onload_solo_capabilities(); + // returns nullptr in onload phase + static Mutex* lock(); + + // get_potential_capabilities without lock + static void get_potential_capabilities_nolock(const jvmtiCapabilities* current, + const jvmtiCapabilities* prohibited, + jvmtiCapabilities* result); + public: static void initialize(); diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index 6908e1994ba7d..07709b9e0179a 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -2320,7 +2320,10 @@ bool StackRefCollector::do_frame(vframe* vf) { // Follow oops from compiled nmethod. if (jvf->cb() != nullptr && jvf->cb()->is_nmethod()) { _blk->set_context(_thread_tag, _tid, _depth, method); - jvf->cb()->as_nmethod()->oops_do(_blk); + // Need to apply load barriers for unmounted vthreads. + nmethod* nm = jvf->cb()->as_nmethod(); + nm->run_nmethod_entry_barrier(); + nm->oops_do(_blk); if (_blk->stopped()) { return false; } diff --git a/src/hotspot/share/prims/jvmtiThreadState.hpp b/src/hotspot/share/prims/jvmtiThreadState.hpp index 8340a44d1427f..4dc24487058df 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.hpp +++ b/src/hotspot/share/prims/jvmtiThreadState.hpp @@ -465,9 +465,12 @@ class JvmtiThreadState : public CHeapObj { // already holding JvmtiThreadState_lock - retrieve or create JvmtiThreadState // Can return null if JavaThread is exiting. + // Callers are responsible to call recompute_thread_filtered() to update event bits + // if thread-filtered events are enabled globally. static JvmtiThreadState *state_for_while_locked(JavaThread *thread, oop thread_oop = nullptr); // retrieve or create JvmtiThreadState // Can return null if JavaThread is exiting. + // Calls recompute_thread_filtered() to update event bits if thread-filtered events are enabled globally. static JvmtiThreadState *state_for(JavaThread *thread, Handle thread_handle = Handle()); // JVMTI ForceEarlyReturn support diff --git a/src/hotspot/share/prims/jvmtiThreadState.inline.hpp b/src/hotspot/share/prims/jvmtiThreadState.inline.hpp index bbcbe14e56e99..1737bfd6a9f4c 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.inline.hpp +++ b/src/hotspot/share/prims/jvmtiThreadState.inline.hpp @@ -109,6 +109,7 @@ inline JvmtiThreadState* JvmtiThreadState::state_for(JavaThread *thread, Handle MutexLocker mu(JvmtiThreadState_lock); // check again with the lock held state = state_for_while_locked(thread, thread_handle()); + JvmtiEventController::recompute_thread_filtered(state); } else { // Check possible safepoint even if state is non-null. // (Note: the thread argument isn't the current thread) diff --git a/src/hotspot/share/prims/resolvedMethodTable.cpp b/src/hotspot/share/prims/resolvedMethodTable.cpp index fbcbd2b15907e..c10fe1f66010c 100644 --- a/src/hotspot/share/prims/resolvedMethodTable.cpp +++ b/src/hotspot/share/prims/resolvedMethodTable.cpp @@ -126,11 +126,9 @@ class ResolvedMethodTableLookup : StackObj { uintx get_hash() const { return _hash; } - bool equals(WeakHandle* value, bool* is_dead) { + bool equals(WeakHandle* value) { oop val_oop = value->peek(); if (val_oop == nullptr) { - // dead oop, mark this hash dead for cleaning - *is_dead = true; return false; } bool equals = _method == java_lang_invoke_ResolvedMethodName::vmtarget(val_oop); @@ -141,6 +139,10 @@ class ResolvedMethodTableLookup : StackObj { _found = Handle(_thread, value->resolve()); return true; } + bool is_dead(WeakHandle* value) { + oop val_oop = value->peek(); + return val_oop == nullptr; + } }; diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index b0a497c4e63d2..f68147fea4f2f 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1865,6 +1865,12 @@ WB_ENTRY(jint, WB_GetConstantPoolCacheLength(JNIEnv* env, jobject wb, jclass kla return cp->cache()->length(); WB_END +WB_ENTRY(jobjectArray, WB_GetResolvedReferences(JNIEnv* env, jobject wb, jclass klass)) + InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + objArrayOop resolved_refs= ik->constants()->resolved_references(); + return (jobjectArray)JNIHandles::make_local(THREAD, resolved_refs); +WB_END + WB_ENTRY(jint, WB_ConstantPoolRemapInstructionOperandFromCache(JNIEnv* env, jobject wb, jclass klass, jint index)) InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); ConstantPool* cp = ik->constants(); @@ -2550,6 +2556,18 @@ WB_ENTRY(jboolean, WB_SetVirtualThreadsNotifyJvmtiMode(JNIEnv* env, jobject wb, return result; WB_END +WB_ENTRY(void, WB_PreTouchMemory(JNIEnv* env, jobject wb, jlong addr, jlong size)) + void* const from = (void*)addr; + void* const to = (void*)(addr + size); + if (from > to) { + os::pretouch_memory(from, to, os::vm_page_size()); + } +WB_END + +WB_ENTRY(void, WB_CleanMetaspaces(JNIEnv* env, jobject target)) + ClassLoaderDataGraph::safepoint_and_clean_metaspaces(); +WB_END + #define CC (char*) static JNINativeMethod methods[] = { @@ -2737,6 +2755,7 @@ static JNINativeMethod methods[] = { {CC"getConstantPool0", CC"(Ljava/lang/Class;)J", (void*)&WB_GetConstantPool }, {CC"getConstantPoolCacheIndexTag0", CC"()I", (void*)&WB_GetConstantPoolCacheIndexTag}, {CC"getConstantPoolCacheLength0", CC"(Ljava/lang/Class;)I", (void*)&WB_GetConstantPoolCacheLength}, + {CC"getResolvedReferences0", CC"(Ljava/lang/Class;)[Ljava/lang/Object;", (void*)&WB_GetResolvedReferences}, {CC"remapInstructionOperandFromCPCache0", CC"(Ljava/lang/Class;I)I", (void*)&WB_ConstantPoolRemapInstructionOperandFromCache}, {CC"encodeConstantPoolIndyIndex0", @@ -2829,6 +2848,8 @@ static JNINativeMethod methods[] = { {CC"lockCritical", CC"()V", (void*)&WB_LockCritical}, {CC"unlockCritical", CC"()V", (void*)&WB_UnlockCritical}, {CC"setVirtualThreadsNotifyJvmtiMode", CC"(Z)Z", (void*)&WB_SetVirtualThreadsNotifyJvmtiMode}, + {CC"preTouchMemory", CC"(JJ)V", (void*)&WB_PreTouchMemory}, + {CC"cleanMetaspaces", CC"()V", (void*)&WB_CleanMetaspaces}, }; diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp index 2fdb820982a93..fee840aba9ad3 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.cpp +++ b/src/hotspot/share/runtime/abstract_vm_version.cpp @@ -240,6 +240,16 @@ const char* Abstract_VM_Version::internal_vm_info_string() { #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.2 (VS2022)" #elif _MSC_VER == 1933 #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.3 (VS2022)" + #elif _MSC_VER == 1934 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.4 (VS2022)" + #elif _MSC_VER == 1935 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.5 (VS2022)" + #elif _MSC_VER == 1936 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.6 (VS2022)" + #elif _MSC_VER == 1937 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.7 (VS2022)" + #elif _MSC_VER == 1938 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.8 (VS2022)" #else #define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER) #endif diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index b0bfae08995f4..720a0e9ba29b5 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1904,23 +1904,13 @@ bool Arguments::check_vm_args_consistency() { } #endif - -#if !defined(X86) && !defined(AARCH64) && !defined(RISCV64) && !defined(ARM) && !defined(PPC64) +#if !defined(X86) && !defined(AARCH64) && !defined(RISCV64) && !defined(ARM) && !defined(PPC64) && !defined(S390) if (LockingMode == LM_LIGHTWEIGHT) { FLAG_SET_CMDLINE(LockingMode, LM_LEGACY); warning("New lightweight locking not supported on this platform"); } #endif - if (UseHeavyMonitors) { - if (FLAG_IS_CMDLINE(LockingMode) && LockingMode != LM_MONITOR) { - jio_fprintf(defaultStream::error_stream(), - "Conflicting -XX:+UseHeavyMonitors and -XX:LockingMode=%d flags", LockingMode); - return false; - } - FLAG_SET_CMDLINE(LockingMode, LM_MONITOR); - } - #if !defined(X86) && !defined(AARCH64) && !defined(PPC64) && !defined(RISCV64) && !defined(S390) if (LockingMode == LM_MONITOR) { jio_fprintf(defaultStream::error_stream(), diff --git a/src/hotspot/share/runtime/atomic.hpp b/src/hotspot/share/runtime/atomic.hpp index c85bf9055ab39..ac0ce49d26e56 100644 --- a/src/hotspot/share/runtime/atomic.hpp +++ b/src/hotspot/share/runtime/atomic.hpp @@ -398,11 +398,15 @@ class Atomic : AllStatic { T compare_value, T exchange_value); - // Support platforms that do not provide Read-Modify-Write - // byte-level atomic access. To use, derive PlatformCmpxchg<1> from - // this class. + // Support platforms that do not provide Read-Modify-Write atomic + // accesses for 1-byte and 8-byte widths. To use, derive PlatformCmpxchg<1>, + // PlatformAdd, PlatformXchg from these classes. public: // Temporary, can't be private: C++03 11.4/2. Fixed by C++11. struct CmpxchgByteUsingInt; + template + struct XchgUsingCmpxchg; + template + class AddUsingCmpxchg; private: // Dispatch handler for xchg. Provides type-based validity @@ -677,6 +681,47 @@ struct Atomic::CmpxchgByteUsingInt { atomic_memory_order order) const; }; +// Define the class before including platform file, which may use this +// as a base class, requiring it be complete. The definition is later +// in this file, near the other definitions related to xchg. +template +struct Atomic::XchgUsingCmpxchg { + template + T operator()(T volatile* dest, + T exchange_value, + atomic_memory_order order) const; +}; + +// Define the class before including platform file, which may use this +// as a base class, requiring it be complete. +template +class Atomic::AddUsingCmpxchg { +public: + template + static inline D add_then_fetch(D volatile* dest, + I add_value, + atomic_memory_order order) { + D addend = add_value; + return fetch_then_add(dest, add_value, order) + add_value; + } + + template + static inline D fetch_then_add(D volatile* dest, + I add_value, + atomic_memory_order order) { + STATIC_ASSERT(byte_size == sizeof(I)); + STATIC_ASSERT(byte_size == sizeof(D)); + + D old_value; + D new_value; + do { + old_value = Atomic::load(dest); + new_value = old_value + add_value; + } while (old_value != Atomic::cmpxchg(dest, old_value, new_value, order)); + return old_value; + } +}; + // Define the class before including platform file, which may specialize // the operator definition. No generic definition of specializations // of the operator template are provided, nor are there any generic @@ -1170,4 +1215,18 @@ inline D Atomic::xchg(volatile D* dest, T exchange_value, atomic_memory_order or return XchgImpl()(dest, exchange_value, order); } +template +template +inline T Atomic::XchgUsingCmpxchg::operator()(T volatile* dest, + T exchange_value, + atomic_memory_order order) const { + STATIC_ASSERT(byte_size == sizeof(T)); + + T old_value; + do { + old_value = Atomic::load(dest); + } while (old_value != Atomic::cmpxchg(dest, old_value, exchange_value, order)); + return old_value; +} + #endif // SHARE_RUNTIME_ATOMIC_HPP diff --git a/src/hotspot/share/runtime/continuationWrapper.cpp b/src/hotspot/share/runtime/continuationWrapper.cpp index 3b967a075545e..9ef02bed67033 100644 --- a/src/hotspot/share/runtime/continuationWrapper.cpp +++ b/src/hotspot/share/runtime/continuationWrapper.cpp @@ -38,16 +38,12 @@ #include "runtime/stackChunkFrameStream.inline.hpp" ContinuationWrapper::ContinuationWrapper(const RegisterMap* map) - : _thread(map->thread()), - _entry(Continuation::get_continuation_entry_for_continuation(_thread, map->stack_chunk()->cont())), - _continuation(map->stack_chunk()->cont()) - { - assert(oopDesc::is_oop(_continuation),"Invalid cont: " INTPTR_FORMAT, p2i((void*)_continuation)); + : ContinuationWrapper(map->thread(), + Continuation::get_continuation_entry_for_continuation(map->thread(), map->stack_chunk()->cont()), + map->stack_chunk()->cont()) { assert(_entry == nullptr || _continuation == _entry->cont_oop(map->thread()), "cont: " INTPTR_FORMAT " entry: " INTPTR_FORMAT " entry_sp: " INTPTR_FORMAT, p2i( (oopDesc*)_continuation), p2i((oopDesc*)_entry->cont_oop(map->thread())), p2i(entrySP())); - disallow_safepoint(); - read(); } const frame ContinuationWrapper::last_frame() { @@ -96,4 +92,3 @@ bool ContinuationWrapper::chunk_invariant() const { return true; } #endif // ASSERT - diff --git a/src/hotspot/share/runtime/continuationWrapper.inline.hpp b/src/hotspot/share/runtime/continuationWrapper.inline.hpp index 03b2c726a0e59..0215f765c5dad 100644 --- a/src/hotspot/share/runtime/continuationWrapper.inline.hpp +++ b/src/hotspot/share/runtime/continuationWrapper.inline.hpp @@ -49,6 +49,7 @@ class ContinuationWrapper : public StackObj { // These oops are managed by SafepointOp oop _continuation; // jdk.internal.vm.Continuation instance stackChunkOop _tail; + bool _done; ContinuationWrapper(const ContinuationWrapper& cont); // no copy constructor @@ -58,6 +59,7 @@ class ContinuationWrapper : public StackObj { void disallow_safepoint() { #ifdef ASSERT + assert(!_done, ""); assert(_continuation != nullptr, ""); _current_thread = Thread::current(); if (_current_thread->is_Java_thread()) { @@ -69,16 +71,19 @@ class ContinuationWrapper : public StackObj { void allow_safepoint() { #ifdef ASSERT // we could have already allowed safepoints in done - if (_continuation != nullptr && _current_thread->is_Java_thread()) { + if (!_done && _current_thread->is_Java_thread()) { JavaThread::cast(_current_thread)->dec_no_safepoint_count(); } #endif } + ContinuationWrapper(JavaThread* thread, ContinuationEntry* entry, oop continuation); + public: void done() { allow_safepoint(); // must be done first - _continuation = nullptr; + _done = true; + *reinterpret_cast(&_continuation) = badHeapOopVal; *reinterpret_cast(&_tail) = badHeapOopVal; } @@ -140,23 +145,19 @@ class ContinuationWrapper : public StackObj { #endif }; -inline ContinuationWrapper::ContinuationWrapper(JavaThread* thread, oop continuation) - : _thread(thread), _entry(thread->last_continuation()), _continuation(continuation) - { +inline ContinuationWrapper::ContinuationWrapper(JavaThread* thread, ContinuationEntry* entry, oop continuation) + : _thread(thread), _entry(entry), _continuation(continuation), _done(false) { assert(oopDesc::is_oop(_continuation), "Invalid continuation object: " INTPTR_FORMAT, p2i((void*)_continuation)); disallow_safepoint(); read(); } +inline ContinuationWrapper::ContinuationWrapper(JavaThread* thread, oop continuation) + : ContinuationWrapper(thread, thread->last_continuation(), continuation) {} + inline ContinuationWrapper::ContinuationWrapper(oop continuation) - : _thread(nullptr), _entry(nullptr), _continuation(continuation) - { - assert(oopDesc::is_oop(_continuation), - "Invalid continuation object: " INTPTR_FORMAT, p2i((void*)_continuation)); - disallow_safepoint(); - read(); -} + : ContinuationWrapper(nullptr, nullptr, continuation) {} inline bool ContinuationWrapper::is_preempted() { return jdk_internal_vm_Continuation::is_preempted(_continuation); diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index d62100c4cf84a..44baccc3bc7c3 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,7 @@ #include "runtime/stackValue.hpp" #include "runtime/stackWatermarkSet.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/synchronizer.hpp" #include "runtime/threadSMR.hpp" #include "runtime/threadWXSetters.inline.hpp" #include "runtime/vframe.hpp" @@ -1614,6 +1615,10 @@ void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableAr reassign_object_array_elements(fr, reg_map, sv, (objArrayOop) obj()); } } + // These objects may escape when we return to Interpreter after deoptimization. + // We need barrier so that stores that initialize these objects can't be reordered + // with subsequent stores that make these objects accessible by other threads. + OrderAccess::storestore(); } @@ -1648,9 +1653,19 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArraylock(); - ObjectSynchronizer::enter(obj, lock, deoptee_thread); - assert(mon_info->owner()->is_locked(), "object must be locked now"); + if (LockingMode == LM_LIGHTWEIGHT && exec_mode == Unpack_none) { + // We have lost information about the correct state of the lock stack. + // Inflate the locks instead. Enter then inflate to avoid races with + // deflation. + ObjectSynchronizer::enter(obj, nullptr, deoptee_thread); + assert(mon_info->owner()->is_locked(), "object must be locked now"); + ObjectMonitor* mon = ObjectSynchronizer::inflate(deoptee_thread, obj(), ObjectSynchronizer::inflate_cause_vm_internal); + assert(mon->owner() == deoptee_thread, "must be"); + } else { + BasicLock* lock = mon_info->lock(); + ObjectSynchronizer::enter(obj, lock, deoptee_thread); + assert(mon_info->owner()->is_locked(), "object must be locked now"); + } } } } diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index d4e7c26f18b6e..6266bd004ea25 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -52,6 +52,7 @@ #include "runtime/monitorChunk.hpp" #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" +#include "runtime/safefetch.hpp" #include "runtime/signature.hpp" #include "runtime/stackValue.hpp" #include "runtime/stubCodeGenerator.hpp" @@ -301,6 +302,14 @@ bool frame::is_entry_frame_valid(JavaThread* thread) const { return (jfa->last_Java_sp() > sp()); } +Method* frame::safe_interpreter_frame_method() const { + Method** m_addr = interpreter_frame_method_addr(); + if (m_addr == nullptr) { + return nullptr; + } + return (Method*) SafeFetchN((intptr_t*) m_addr, 0); +} + bool frame::should_be_deoptimized() const { if (_deopt_state == is_deoptimized || !is_compiled_frame() ) return false; diff --git a/src/hotspot/share/runtime/frame.hpp b/src/hotspot/share/runtime/frame.hpp index 2b62b4e1c730f..a66b9dee291f0 100644 --- a/src/hotspot/share/runtime/frame.hpp +++ b/src/hotspot/share/runtime/frame.hpp @@ -236,6 +236,8 @@ class frame { bool is_entry_frame_valid(JavaThread* thread) const; + Method* safe_interpreter_frame_method() const; + // All frames: // A low-level interface for vframes: @@ -370,6 +372,7 @@ class frame { BasicObjectLock* next_monitor_in_interpreter_frame(BasicObjectLock* current) const; BasicObjectLock* previous_monitor_in_interpreter_frame(BasicObjectLock* current) const; static int interpreter_frame_monitor_size(); + static int interpreter_frame_monitor_size_in_bytes(); void interpreter_frame_verify_monitor(BasicObjectLock* value) const; diff --git a/src/hotspot/share/runtime/frame.inline.hpp b/src/hotspot/share/runtime/frame.inline.hpp index b6116a0341d7c..2cfaba170540d 100644 --- a/src/hotspot/share/runtime/frame.inline.hpp +++ b/src/hotspot/share/runtime/frame.inline.hpp @@ -104,4 +104,9 @@ inline CodeBlob* frame::get_cb() const { return _cb; } +inline int frame::interpreter_frame_monitor_size_in_bytes() { + // Number of bytes for a monitor. + return frame::interpreter_frame_monitor_size() * wordSize; +} + #endif // SHARE_RUNTIME_FRAME_INLINE_HPP diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 5b609f858b7e3..7137270fd1749 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -295,6 +295,9 @@ const int ObjectAlignmentInBytes = 8; product(bool, UseInlineCaches, true, \ "Use Inline Caches for virtual calls ") \ \ + product(size_t, InlineCacheBufferSize, 10*K, EXPERIMENTAL, \ + "InlineCacheBuffer size") \ + \ product(bool, InlineArrayCopy, true, DIAGNOSTIC, \ "Inline arraycopy native that is known to be part of " \ "base library DLL") \ @@ -1050,13 +1053,9 @@ const int ObjectAlignmentInBytes = 8; product(bool, ErrorFileToStdout, false, \ "If true, error data is printed to stdout instead of a file") \ \ - develop(bool, UseHeavyMonitors, false, \ - "(Deprecated) Use heavyweight instead of lightweight Java " \ - "monitors") \ - \ develop(bool, VerifyHeavyMonitors, false, \ "Checks that no stack locking happens when using " \ - "+UseHeavyMonitors") \ + "-XX:LockingMode=0 (LM_MONITOR)") \ \ product(bool, PrintStringTableStatistics, false, \ "print statistics about the StringTable and SymbolTable") \ @@ -1976,6 +1975,13 @@ const int ObjectAlignmentInBytes = 8; "1: monitors & legacy stack-locking (LM_LEGACY, default), " \ "2: monitors & new lightweight locking (LM_LIGHTWEIGHT)") \ range(0, 2) \ + \ + product(uint, TrimNativeHeapInterval, 0, \ + "Interval, in ms, at which the JVM will trim the native heap if " \ + "the platform supports that. Lower values will reclaim memory " \ + "more eagerly at the cost of higher overhead. A value of 0 " \ + "(default) disables native heap trimming.") \ + range(0, UINT_MAX) \ // end of RUNTIME_FLAGS diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp index b4534837cad37..e3ecc2be6fd06 100644 --- a/src/hotspot/share/runtime/handshake.cpp +++ b/src/hotspot/share/runtime/handshake.cpp @@ -497,8 +497,17 @@ HandshakeOperation* HandshakeState::get_op_for_self(bool allow_suspend, bool che } bool HandshakeState::has_operation(bool allow_suspend, bool check_async_exception) { - MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag); - return get_op_for_self(allow_suspend, check_async_exception) != nullptr; + // We must not block here as that could lead to deadlocks if we already hold an + // "external" mutex. If the try_lock fails then we assume that there is an operation + // and force the caller to check more carefully in a safer context. If we can't get + // the lock it means another thread is trying to handshake with us, so it can't + // happen during thread termination and destruction. + bool ret = true; + if (_lock.try_lock()) { + ret = get_op_for_self(allow_suspend, check_async_exception) != nullptr; + _lock.unlock(); + } + return ret; } bool HandshakeState::has_async_exception_operation() { diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 8746efebc21d9..48709aa5c4390 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -70,6 +70,7 @@ #include "runtime/task.hpp" #include "runtime/threads.hpp" #include "runtime/timer.hpp" +#include "runtime/trimNativeHeap.hpp" #include "runtime/vmOperations.hpp" #include "runtime/vmThread.hpp" #include "runtime/vm_version.hpp" @@ -477,6 +478,8 @@ void before_exit(JavaThread* thread, bool halt) { StatSampler::disengage(); StatSampler::destroy(); + NativeHeapTrimmer::cleanup(); + // Stop concurrent GC threads Universe::heap()->stop(); diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index b469c1a679010..ff8c842daaafb 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -1587,6 +1587,13 @@ const char* JavaThread::name() const { return Thread::name(); } +// Like name() but doesn't include the protection check. This must only be +// called when it is known to be safe, even though the protection check can't tell +// that e.g. when this thread is the init_thread() - see instanceKlass.cpp. +const char* JavaThread::name_raw() const { + return get_thread_name_string(); +} + // Returns a non-null representation of this thread's name, or a suitable // descriptive string if there is no set name. const char* JavaThread::get_thread_name_string(char* buf, int buflen) const { diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index f2cb56646d4cc..e8e6ccbfe6a57 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -904,6 +904,7 @@ class JavaThread: public Thread { // Misc. operations const char* name() const; + const char* name_raw() const; const char* type_name() const { return "JavaThread"; } static const char* name_for(oop thread_obj); diff --git a/src/hotspot/share/runtime/jniHandles.cpp b/src/hotspot/share/runtime/jniHandles.cpp index feceec366a597..25c8aa8b10b6e 100644 --- a/src/hotspot/share/runtime/jniHandles.cpp +++ b/src/hotspot/share/runtime/jniHandles.cpp @@ -199,13 +199,9 @@ jobjectRefType JNIHandles::handle_type(JavaThread* thread, jobject handle) { default: ShouldNotReachHere(); } - } else { + } else if (is_local_handle(thread, handle) || is_frame_handle(thread, handle)) { // Not in global storage. Might be a local handle. - if (is_local_handle(thread, handle) || is_frame_handle(thread, handle)) { - result = JNILocalRefType; - } else { - ShouldNotReachHere(); - } + result = JNILocalRefType; } return result; } diff --git a/src/hotspot/share/runtime/lockStack.cpp b/src/hotspot/share/runtime/lockStack.cpp index 5fd5297fd5c02..b4a3bf1e8e6c0 100644 --- a/src/hotspot/share/runtime/lockStack.cpp +++ b/src/hotspot/share/runtime/lockStack.cpp @@ -77,3 +77,15 @@ void LockStack::verify(const char* msg) const { } } #endif + +void LockStack::print_on(outputStream* st) { + for (int i = to_index(_top); (--i) >= 0;) { + st->print("LockStack[%d]: ", i); + oop o = _base[i]; + if (oopDesc::is_oop(o)) { + o->print_on(st); + } else { + st->print_cr("not an oop: " PTR_FORMAT, p2i(o)); + } + } +} diff --git a/src/hotspot/share/runtime/lockStack.hpp b/src/hotspot/share/runtime/lockStack.hpp index ce6a96bcfe624..25ab7a8de052a 100644 --- a/src/hotspot/share/runtime/lockStack.hpp +++ b/src/hotspot/share/runtime/lockStack.hpp @@ -30,8 +30,9 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/sizes.hpp" -class Thread; +class JavaThread; class OopClosure; +class outputStream; class LockStack { friend class VMStructs; @@ -91,6 +92,8 @@ class LockStack { // GC support inline void oops_do(OopClosure* cl); + // Printing + void print_on(outputStream* st); }; #endif // SHARE_RUNTIME_LOCKSTACK_HPP diff --git a/src/hotspot/share/runtime/lockStack.inline.hpp b/src/hotspot/share/runtime/lockStack.inline.hpp index 186c7169fae11..b36be2f72de0e 100644 --- a/src/hotspot/share/runtime/lockStack.inline.hpp +++ b/src/hotspot/share/runtime/lockStack.inline.hpp @@ -47,10 +47,14 @@ inline bool LockStack::can_push() const { } inline bool LockStack::is_owning_thread() const { - JavaThread* thread = JavaThread::current(); - bool is_owning = &thread->lock_stack() == this; - assert(is_owning == (get_thread() == thread), "is_owning sanity"); - return is_owning; + Thread* current = Thread::current(); + if (current->is_Java_thread()) { + JavaThread* thread = JavaThread::cast(current); + bool is_owning = &thread->lock_stack() == this; + assert(is_owning == (get_thread() == thread), "is_owning sanity"); + return is_owning; + } + return false; } inline void LockStack::push(oop o) { @@ -100,16 +104,10 @@ inline void LockStack::remove(oop o) { inline bool LockStack::contains(oop o) const { verify("pre-contains"); - if (!SafepointSynchronize::is_at_safepoint() && !is_owning_thread()) { - // When a foreign thread inspects this thread's lock-stack, it may see - // bad references here when a concurrent collector has not gotten - // to processing the lock-stack, yet. Call StackWaterMark::start_processing() - // to ensure that all references are valid. - StackWatermark* watermark = StackWatermarkSet::get(get_thread(), StackWatermarkKind::gc); - if (watermark != nullptr) { - watermark->start_processing(); - } - } + + // Can't poke around in thread oops without having started stack watermark processing. + assert(StackWatermarkSet::processing_started(get_thread()), "Processing must have started!"); + int end = to_index(_top); for (int i = end - 1; i >= 0; i--) { if (_base[i] == o) { diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index a94061c5d8c57..ea46300d14521 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -224,9 +224,9 @@ void mutex_init() { MUTEX_DEFN(MarkStackFreeList_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(MarkStackChunkList_lock , PaddedMutex , nosafepoint); - - MUTEX_DEFN(MonitoringSupport_lock , PaddedMutex , service-1); // used for serviceability monitoring support } + MUTEX_DEFN(MonitoringSupport_lock , PaddedMutex , service-1); // used for serviceability monitoring support + MUTEX_DEFN(StringDedup_lock , PaddedMonitor, nosafepoint); MUTEX_DEFN(StringDedupIntern_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(RawMonitor_lock , PaddedMutex , nosafepoint-1); diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 12a0e953771b1..c8952cf8af369 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -276,24 +276,15 @@ ObjectMonitor::ObjectMonitor(oop object) : { } ObjectMonitor::~ObjectMonitor() { - if (!_object.is_null()) { - // Release object's oop storage if it hasn't already been done. - release_object(); - } + _object.release(_oop_storage); } oop ObjectMonitor::object() const { check_object_context(); - if (_object.is_null()) { - return nullptr; - } return _object.resolve(); } oop ObjectMonitor::object_peek() const { - if (_object.is_null()) { - return nullptr; - } return _object.peek(); } @@ -598,9 +589,6 @@ bool ObjectMonitor::deflate_monitor() { install_displaced_markword_in_object(obj); } - // Release object's oop storage since the ObjectMonitor has been deflated: - release_object(); - // We leave owner == DEFLATER_MARKER and contentions < 0 // to force any racing threads to retry. return true; // Success, ObjectMonitor has been deflated. diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index 92fb58dadb5d5..d6c0e31f7a18c 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -363,7 +363,6 @@ class ObjectMonitor : public CHeapObj { // Deflation support bool deflate_monitor(); void install_displaced_markword_in_object(const oop obj); - void release_object() { _object.release(_oop_storage); _object.set_null(); } }; #endif // SHARE_RUNTIME_OBJECTMONITOR_HPP diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 997bf3a968fb1..a5ea07d8c6459 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1391,7 +1391,7 @@ bool os::write(int fd, const void *buf, size_t nBytes) { if (res == OS_ERR) { return false; } - buf = (void *)((char *)buf + nBytes); + buf = (void *)((char *)buf + res); nBytes -= res; } diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 49c56b3375ed7..f445669ab23d1 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -663,6 +663,8 @@ class os: AllStatic { static const char* get_temp_directory(); static const char* get_current_directory(char *buf, size_t buflen); + static void prepare_native_symbols(); + // Builds the platform-specific name of a library. // Returns false if the buffer is too small. static bool dll_build_name(char* buffer, size_t size, @@ -773,7 +775,7 @@ class os: AllStatic { static void print_context(outputStream* st, const void* context); static void print_tos_pc(outputStream* st, const void* context); static void print_tos(outputStream* st, address sp); - static void print_instructions(outputStream* st, address pc, int unitsize); + static void print_instructions(outputStream* st, address pc, int unitsize = 1); static void print_register_info(outputStream* st, const void* context, int& continuation); static void print_register_info(outputStream* st, const void* context); static bool signal_sent_by_kill(const void* siginfo); @@ -1053,6 +1055,7 @@ class os: AllStatic { char pathSep); static bool set_boot_path(char fileSep, char pathSep); + static bool pd_dll_unload(void* libhandle, char* ebuf, int ebuflen); }; // Note that "PAUSE" is almost always used with synchronization diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index fb3f00f38ad7e..edbdad4f24bc8 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -1872,7 +1872,8 @@ methodHandle SharedRuntime::reresolve_call_site(TRAPS) { // nmethod could be deoptimized by the time we get here // so no update to the caller is needed. - if (caller.is_compiled_frame() && !caller.is_deoptimized_frame()) { + if ((caller.is_compiled_frame() && !caller.is_deoptimized_frame()) || + (caller.is_native_frame() && ((CompiledMethod*)caller.cb())->method()->is_continuation_enter_intrinsic())) { address pc = caller.pc(); diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index 09ed8d1a7f811..6e6f2115e1efd 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "classfile/vmSymbols.hpp" -#include "gc/shared/suspendibleThreadSet.hpp" +#include "gc/shared/collectedHeap.hpp" #include "jfr/jfrEvents.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" @@ -54,6 +54,7 @@ #include "runtime/synchronizer.hpp" #include "runtime/threads.hpp" #include "runtime/timer.hpp" +#include "runtime/trimNativeHeap.hpp" #include "runtime/vframe.hpp" #include "runtime/vmThread.hpp" #include "utilities/align.hpp" @@ -1640,18 +1641,25 @@ class VM_RendezvousGCThreads : public VM_Operation { bool evaluate_at_safepoint() const override { return false; } VMOp_Type type() const override { return VMOp_RendezvousGCThreads; } void doit() override { - SuspendibleThreadSet::synchronize(); - SuspendibleThreadSet::desynchronize(); + Universe::heap()->safepoint_synchronize_begin(); + Universe::heap()->safepoint_synchronize_end(); }; }; -static size_t delete_monitors(GrowableArray* delete_list) { - size_t count = 0; +static size_t delete_monitors(Thread* current, GrowableArray* delete_list, + LogStream* ls, elapsedTimer* timer_p) { + NativeHeapTrimmer::SuspendMark sm("monitor deletion"); + size_t deleted_count = 0; for (ObjectMonitor* monitor: *delete_list) { delete monitor; - count++; + deleted_count++; + if (current->is_Java_thread()) { + // A JavaThread must check for a safepoint/handshake and honor it. + ObjectSynchronizer::chk_for_block_req(JavaThread::cast(current), "deletion", "deleted_count", + deleted_count, ls, timer_p); + } } - return count; + return deleted_count; } // This function is called by the MonitorDeflationThread to deflate @@ -1729,30 +1737,7 @@ size_t ObjectSynchronizer::deflate_idle_monitors(ObjectMonitorsHashtable* table) // After the handshake, safely free the ObjectMonitors that were // deflated and unlinked in this cycle. - if (current->is_Java_thread()) { - if (ls != NULL) { - timer.stop(); - ls->print_cr("before setting blocked: unlinked_count=" SIZE_FORMAT - ", in_use_list stats: ceiling=" SIZE_FORMAT ", count=" - SIZE_FORMAT ", max=" SIZE_FORMAT, - unlinked_count, in_use_list_ceiling(), - _in_use_list.count(), _in_use_list.max()); - } - // Mark the calling JavaThread blocked (safepoint safe) while we free - // the ObjectMonitors so we don't delay safepoints whilst doing that. - ThreadBlockInVM tbivm(JavaThread::cast(current)); - if (ls != NULL) { - ls->print_cr("after setting blocked: in_use_list stats: ceiling=" - SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT, - in_use_list_ceiling(), _in_use_list.count(), _in_use_list.max()); - timer.start(); - } - deleted_count = delete_monitors(&delete_list); - // ThreadBlockInVM is destroyed here - } else { - // A non-JavaThread can just free the ObjectMonitors: - deleted_count = delete_monitors(&delete_list); - } + deleted_count = delete_monitors(current, &delete_list, ls, &timer); assert(unlinked_count == deleted_count, "must be"); } diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index fd213086ccb1f..51a9e8471501e 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -73,6 +73,7 @@ Thread::Thread() { set_lgrp_id(-1); DEBUG_ONLY(clear_suspendible_thread();) DEBUG_ONLY(clear_indirectly_suspendible_thread();) + DEBUG_ONLY(clear_indirectly_safepoint_thread();) // allocated data structures set_osthread(nullptr); diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 80114ddf7eda3..9bd839dc4dba6 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -206,6 +206,7 @@ class Thread: public ThreadShadow { private: DEBUG_ONLY(bool _suspendible_thread;) DEBUG_ONLY(bool _indirectly_suspendible_thread;) + DEBUG_ONLY(bool _indirectly_safepoint_thread;) public: // Determines if a heap allocation failure will be retried @@ -224,6 +225,10 @@ class Thread: public ThreadShadow { void set_indirectly_suspendible_thread() { _indirectly_suspendible_thread = true; } void clear_indirectly_suspendible_thread() { _indirectly_suspendible_thread = false; } bool is_indirectly_suspendible_thread() { return _indirectly_suspendible_thread; } + + void set_indirectly_safepoint_thread() { _indirectly_safepoint_thread = true; } + void clear_indirectly_safepoint_thread() { _indirectly_safepoint_thread = false; } + bool is_indirectly_safepoint_thread() { return _indirectly_safepoint_thread; } #endif private: diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 302c3672ce063..3e121e3bf741a 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -80,6 +80,7 @@ #include "runtime/safepointVerifiers.hpp" #include "runtime/serviceThread.hpp" #include "runtime/sharedRuntime.hpp" +#include "runtime/stackWatermarkSet.inline.hpp" #include "runtime/statSampler.hpp" #include "runtime/stubCodeGenerator.hpp" #include "runtime/thread.inline.hpp" @@ -87,6 +88,7 @@ #include "runtime/threadSMR.inline.hpp" #include "runtime/timer.hpp" #include "runtime/timerTrace.hpp" +#include "runtime/trimNativeHeap.hpp" #include "runtime/vmOperations.hpp" #include "runtime/vm_version.hpp" #include "services/attachListener.hpp" @@ -759,6 +761,10 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { } #endif + if (NativeHeapTrimmer::enabled()) { + NativeHeapTrimmer::initialize(); + } + // Always call even when there are not JVMTI environments yet, since environments // may be attached late and JVMTI must track phases of VM execution JvmtiExport::enter_live_phase(); @@ -1224,6 +1230,12 @@ JavaThread *Threads::owning_thread_from_monitor_owner(ThreadsList * t_list, JavaThread* Threads::owning_thread_from_object(ThreadsList * t_list, oop obj) { assert(LockingMode == LM_LIGHTWEIGHT, "Only with new lightweight locking"); for (JavaThread* q : *t_list) { + // Need to start processing before accessing oops in the thread. + StackWatermark* watermark = StackWatermarkSet::get(q, StackWatermarkKind::gc); + if (watermark != nullptr) { + watermark->start_processing(); + } + if (q->lock_stack().contains(obj)) { return q; } diff --git a/src/hotspot/share/runtime/trimNativeHeap.cpp b/src/hotspot/share/runtime/trimNativeHeap.cpp new file mode 100644 index 0000000000000..7700c8e5109fe --- /dev/null +++ b/src/hotspot/share/runtime/trimNativeHeap.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2023 SAP SE. All rights reserved. + * Copyright (c) 2023 Red Hat Inc. All rights reserved. + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "logging/log.hpp" +#include "runtime/globals.hpp" +#include "runtime/globals_extension.hpp" +#include "runtime/mutex.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/nonJavaThread.hpp" +#include "runtime/os.inline.hpp" +#include "runtime/safepoint.hpp" +#include "runtime/trimNativeHeap.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" +#include "utilities/vmError.hpp" + +class NativeHeapTrimmerThread : public NamedThread { + + // Upper limit for the backoff during pending/in-progress safepoint. + // Chosen as reasonable value to balance the overheads of waking up + // during the safepoint, which might have undesired effects on latencies, + // and the accuracy in tracking the trimming interval. + static constexpr int64_t safepoint_poll_ms = 250; + + Monitor* const _lock; + bool _stop; + uint16_t _suspend_count; + + // Statistics + uint64_t _num_trims_performed; + + bool is_suspended() const { + assert(_lock->is_locked(), "Must be"); + return _suspend_count > 0; + } + + uint16_t inc_suspend_count() { + assert(_lock->is_locked(), "Must be"); + assert(_suspend_count < UINT16_MAX, "Sanity"); + return ++_suspend_count; + } + + uint16_t dec_suspend_count() { + assert(_lock->is_locked(), "Must be"); + assert(_suspend_count != 0, "Sanity"); + return --_suspend_count; + } + + bool is_stopped() const { + assert(_lock->is_locked(), "Must be"); + return _stop; + } + + bool at_or_nearing_safepoint() const { + return SafepointSynchronize::is_at_safepoint() || + SafepointSynchronize::is_synchronizing(); + } + + // in seconds + static double now() { return os::elapsedTime(); } + static double to_ms(double seconds) { return seconds * 1000.0; } + + struct LogStartStopMark { + void log(const char* s) { log_info(trimnative)("Native heap trimmer %s", s); } + LogStartStopMark() { log("start"); } + ~LogStartStopMark() { log("stop"); } + }; + + void run() override { + assert(NativeHeapTrimmer::enabled(), "Only call if enabled"); + + LogStartStopMark lssm; + + const double interval_secs = (double)TrimNativeHeapInterval / 1000; + + while (true) { + double tnow = now(); + double next_trim_time = tnow + interval_secs; + + unsigned times_suspended = 0; + unsigned times_waited = 0; + unsigned times_safepoint = 0; + + { + MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag); + if (_stop) return; + + while (at_or_nearing_safepoint() || is_suspended() || next_trim_time > tnow) { + if (is_suspended()) { + times_suspended ++; + ml.wait(0); // infinite + } else if (next_trim_time > tnow) { + times_waited ++; + const int64_t wait_ms = MAX2(1.0, to_ms(next_trim_time - tnow)); + ml.wait(wait_ms); + } else if (at_or_nearing_safepoint()) { + times_safepoint ++; + const int64_t wait_ms = MIN2(TrimNativeHeapInterval, safepoint_poll_ms); + ml.wait(wait_ms); + } + + if (_stop) return; + + tnow = now(); + } + } + + log_trace(trimnative)("Times: %u suspended, %u timed, %u safepoint", + times_suspended, times_waited, times_safepoint); + + execute_trim_and_log(tnow); + } + } + + // Execute the native trim, log results. + void execute_trim_and_log(double t1) { + assert(os::can_trim_native_heap(), "Unexpected"); + + os::size_change_t sc = { 0, 0 }; + LogTarget(Info, trimnative) lt; + const bool logging_enabled = lt.is_enabled(); + + // We only collect size change information if we are logging; save the access to procfs otherwise. + if (os::trim_native_heap(logging_enabled ? &sc : nullptr)) { + _num_trims_performed++; + if (logging_enabled) { + double t2 = now(); + if (sc.after != SIZE_MAX) { + const size_t delta = sc.after < sc.before ? (sc.before - sc.after) : (sc.after - sc.before); + const char sign = sc.after < sc.before ? '-' : '+'; + log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT ") %.3fms", + _num_trims_performed, + PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta), + to_ms(t2 - t1)); + } else { + log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): complete (no details) %.3fms", + _num_trims_performed, + to_ms(t2 - t1)); + } + } + } + } + +public: + + NativeHeapTrimmerThread() : + _lock(new (std::nothrow) PaddedMonitor(Mutex::nosafepoint, "NativeHeapTrimmer_lock")), + _stop(false), + _suspend_count(0), + _num_trims_performed(0) + { + set_name("Native Heap Trimmer"); + if (os::create_thread(this, os::vm_thread)) { + os::start_thread(this); + } + } + + void suspend(const char* reason) { + assert(NativeHeapTrimmer::enabled(), "Only call if enabled"); + uint16_t n = 0; + { + MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag); + n = inc_suspend_count(); + // No need to wakeup trimmer + } + log_debug(trimnative)("Trim suspended for %s (%u suspend requests)", reason, n); + } + + void resume(const char* reason) { + assert(NativeHeapTrimmer::enabled(), "Only call if enabled"); + uint16_t n = 0; + { + MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag); + n = dec_suspend_count(); + if (n == 0) { + ml.notify_all(); // pause end + } + } + if (n == 0) { + log_debug(trimnative)("Trim resumed after %s", reason); + } else { + log_debug(trimnative)("Trim still suspended after %s (%u suspend requests)", reason, n); + } + } + + void stop() { + MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag); + _stop = true; + ml.notify_all(); + } + + void print_state(outputStream* st) const { + // Don't pull lock during error reporting + Mutex* const lock = VMError::is_error_reported() ? nullptr : _lock; + int64_t num_trims = 0; + bool stopped = false; + uint16_t suspenders = 0; + { + MutexLocker ml(lock, Mutex::_no_safepoint_check_flag); + num_trims = _num_trims_performed; + stopped = _stop; + suspenders = _suspend_count; + } + st->print_cr("Trims performed: " UINT64_FORMAT ", current suspend count: %d, stopped: %d", + num_trims, suspenders, stopped); + } + +}; // NativeHeapTrimmer + +static NativeHeapTrimmerThread* g_trimmer_thread = nullptr; + +void NativeHeapTrimmer::initialize() { + assert(g_trimmer_thread == nullptr, "Only once"); + if (TrimNativeHeapInterval > 0) { + if (!os::can_trim_native_heap()) { + FLAG_SET_ERGO(TrimNativeHeapInterval, 0); + log_warning(trimnative)("Native heap trim is not supported on this platform"); + return; + } + g_trimmer_thread = new NativeHeapTrimmerThread(); + log_info(trimnative)("Periodic native trim enabled (interval: %u ms)", TrimNativeHeapInterval); + } +} + +void NativeHeapTrimmer::cleanup() { + if (g_trimmer_thread != nullptr) { + g_trimmer_thread->stop(); + } +} + +void NativeHeapTrimmer::suspend_periodic_trim(const char* reason) { + if (g_trimmer_thread != nullptr) { + g_trimmer_thread->suspend(reason); + } +} + +void NativeHeapTrimmer::resume_periodic_trim(const char* reason) { + if (g_trimmer_thread != nullptr) { + g_trimmer_thread->resume(reason); + } +} + +void NativeHeapTrimmer::print_state(outputStream* st) { + if (g_trimmer_thread != nullptr) { + st->print_cr("Periodic native trim enabled (interval: %u ms)", TrimNativeHeapInterval); + g_trimmer_thread->print_state(st); + } else { + st->print_cr("Periodic native trim disabled"); + } +} diff --git a/src/hotspot/share/runtime/trimNativeHeap.hpp b/src/hotspot/share/runtime/trimNativeHeap.hpp new file mode 100644 index 0000000000000..06dc88ebb0899 --- /dev/null +++ b/src/hotspot/share/runtime/trimNativeHeap.hpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023 SAP SE. All rights reserved. + * Copyright (c) 2023 Red Hat Inc. All rights reserved. + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_RUNTIME_TRIMNATIVEHEAP_HPP +#define SHARE_RUNTIME_TRIMNATIVEHEAP_HPP + +#include "memory/allStatic.hpp" +#include "runtime/globals.hpp" + +class outputStream; + +class NativeHeapTrimmer : public AllStatic { + + // Pause periodic trim (if enabled). + static void suspend_periodic_trim(const char* reason); + + // Unpause periodic trim (if enabled). + static void resume_periodic_trim(const char* reason); + +public: + + static void initialize(); + static void cleanup(); + + static inline bool enabled() { return TrimNativeHeapInterval > 0; } + + static void print_state(outputStream* st); + + // Pause periodic trimming while in scope; when leaving scope, + // resume periodic trimming. + struct SuspendMark { + const char* const _reason; + SuspendMark(const char* reason = "unknown") : _reason(reason) { + if (NativeHeapTrimmer::enabled()) { + suspend_periodic_trim(_reason); + } + } + ~SuspendMark() { + if (NativeHeapTrimmer::enabled()) { + resume_periodic_trim(_reason); + } + } + }; +}; + +#endif // SHARE_RUNTIME_TRIMNATIVEHEAP_HPP diff --git a/src/hotspot/share/services/finalizerService.cpp b/src/hotspot/share/services/finalizerService.cpp index 202a1af08011a..ecd9168cd65d3 100644 --- a/src/hotspot/share/services/finalizerService.cpp +++ b/src/hotspot/share/services/finalizerService.cpp @@ -137,11 +137,14 @@ class FinalizerEntryLookup : StackObj { public: FinalizerEntryLookup(const InstanceKlass* ik) : _ik(ik) {} uintx get_hash() const { return hash_function(_ik); } - bool equals(FinalizerEntry** value, bool* is_dead) { + bool equals(FinalizerEntry** value) { assert(value != nullptr, "invariant"); assert(*value != nullptr, "invariant"); return (*value)->klass() == _ik; } + bool is_dead(FinalizerEntry** value) { + return false; + } }; class FinalizerTableConfig : public AllStatic { diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 1d947cff1d010..74786534069c0 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -37,6 +37,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" +#include "oops/fieldStreams.inline.hpp" #include "oops/klass.inline.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" @@ -48,7 +49,6 @@ #include "runtime/javaThread.inline.hpp" #include "runtime/jniHandles.hpp" #include "runtime/os.hpp" -#include "runtime/reflectionUtils.hpp" #include "runtime/threads.hpp" #include "runtime/threadSMR.hpp" #include "runtime/vframe.hpp" @@ -1096,7 +1096,7 @@ u4 DumperSupport::instance_size(Klass* k) { InstanceKlass* ik = InstanceKlass::cast(k); u4 size = 0; - for (FieldStream fld(ik, false, false); !fld.eos(); fld.next()) { + for (HierarchicalFieldStream fld(ik); !fld.done(); fld.next()) { if (!fld.access_flags().is_static()) { size += sig2size(fld.signature()); } @@ -1108,7 +1108,7 @@ u4 DumperSupport::get_static_fields_size(InstanceKlass* ik, u2& field_count) { field_count = 0; u4 size = 0; - for (FieldStream fldc(ik, true, true); !fldc.eos(); fldc.next()) { + for (JavaFieldStream fldc(ik); !fldc.done(); fldc.next()) { if (fldc.access_flags().is_static()) { field_count++; size += sig2size(fldc.signature()); @@ -1142,7 +1142,7 @@ void DumperSupport::dump_static_fields(AbstractDumpWriter* writer, Klass* k) { InstanceKlass* ik = InstanceKlass::cast(k); // dump the field descriptors and raw values - for (FieldStream fld(ik, true, true); !fld.eos(); fld.next()) { + for (JavaFieldStream fld(ik); !fld.done(); fld.next()) { if (fld.access_flags().is_static()) { Symbol* sig = fld.signature(); @@ -1176,7 +1176,7 @@ void DumperSupport::dump_static_fields(AbstractDumpWriter* writer, Klass* k) { void DumperSupport::dump_instance_fields(AbstractDumpWriter* writer, oop o) { InstanceKlass* ik = InstanceKlass::cast(o->klass()); - for (FieldStream fld(ik, false, false); !fld.eos(); fld.next()) { + for (HierarchicalFieldStream fld(ik); !fld.done(); fld.next()) { if (!fld.access_flags().is_static()) { Symbol* sig = fld.signature(); dump_field_value(writer, sig->char_at(0), o, fld.offset()); @@ -1188,7 +1188,7 @@ void DumperSupport::dump_instance_fields(AbstractDumpWriter* writer, oop o) { u2 DumperSupport::get_instance_fields_count(InstanceKlass* ik) { u2 field_count = 0; - for (FieldStream fldc(ik, true, true); !fldc.eos(); fldc.next()) { + for (JavaFieldStream fldc(ik); !fldc.done(); fldc.next()) { if (!fldc.access_flags().is_static()) field_count++; } @@ -1200,7 +1200,7 @@ void DumperSupport::dump_instance_field_descriptors(AbstractDumpWriter* writer, InstanceKlass* ik = InstanceKlass::cast(k); // dump the field descriptors - for (FieldStream fld(ik, true, true); !fld.eos(); fld.next()) { + for (JavaFieldStream fld(ik); !fld.done(); fld.next()) { if (!fld.access_flags().is_static()) { Symbol* sig = fld.signature(); diff --git a/src/hotspot/share/services/mallocTracker.cpp b/src/hotspot/share/services/mallocTracker.cpp index bddfcfffc0820..5dab383770795 100644 --- a/src/hotspot/share/services/mallocTracker.cpp +++ b/src/hotspot/share/services/mallocTracker.cpp @@ -45,7 +45,6 @@ size_t MallocMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(MallocMemorySnapshot, size_t)]; -#ifdef ASSERT void MemoryCounter::update_peak(size_t size, size_t cnt) { size_t peak_sz = peak_size(); while (peak_sz < size) { @@ -59,7 +58,6 @@ void MemoryCounter::update_peak(size_t size, size_t cnt) { } } } -#endif // ASSERT // Total malloc'd memory used by arenas size_t MallocMemorySnapshot::total_arena() const { @@ -213,7 +211,8 @@ bool MallocTracker::print_pointer_information(const void* p, outputStream* st) { const uint8_t* here = align_down(addr, smallest_possible_alignment); const uint8_t* const end = here - (0x1000 + sizeof(MallocHeader)); // stop searching after 4k for (; here >= end; here -= smallest_possible_alignment) { - if (!os::is_readable_pointer(here)) { + // JDK-8306561: cast to a MallocHeader needs to guarantee it can reside in readable memory + if (!os::is_readable_range(here, here + sizeof(MallocHeader))) { // Probably OOB, give up break; } diff --git a/src/hotspot/share/services/mallocTracker.hpp b/src/hotspot/share/services/mallocTracker.hpp index f4f824bb07c49..ed66f643c74b3 100644 --- a/src/hotspot/share/services/mallocTracker.hpp +++ b/src/hotspot/share/services/mallocTracker.hpp @@ -46,25 +46,20 @@ class MemoryCounter { volatile size_t _count; volatile size_t _size; -#ifdef ASSERT // Peak size and count. Note: Peak count is the count at the point // peak size was reached, not the absolute highest peak count. volatile size_t _peak_count; volatile size_t _peak_size; void update_peak(size_t size, size_t cnt); -#endif // ASSERT public: - MemoryCounter() : _count(0), _size(0) { - DEBUG_ONLY(_peak_count = 0;) - DEBUG_ONLY(_peak_size = 0;) - } + MemoryCounter() : _count(0), _size(0), _peak_count(0), _peak_size(0) {} inline void allocate(size_t sz) { size_t cnt = Atomic::add(&_count, size_t(1), memory_order_relaxed); if (sz > 0) { size_t sum = Atomic::add(&_size, sz, memory_order_relaxed); - DEBUG_ONLY(update_peak(sum, cnt);) + update_peak(sum, cnt); } } @@ -81,7 +76,7 @@ class MemoryCounter { if (sz != 0) { assert(sz >= 0 || size() >= size_t(-sz), "Must be"); size_t sum = Atomic::add(&_size, size_t(sz), memory_order_relaxed); - DEBUG_ONLY(update_peak(sum, _count);) + update_peak(sum, _count); } } @@ -89,11 +84,11 @@ class MemoryCounter { inline size_t size() const { return Atomic::load(&_size); } inline size_t peak_count() const { - return DEBUG_ONLY(Atomic::load(&_peak_count)) NOT_DEBUG(0); + return Atomic::load(&_peak_count); } inline size_t peak_size() const { - return DEBUG_ONLY(Atomic::load(&_peak_size)) NOT_DEBUG(0); + return Atomic::load(&_peak_size); } }; @@ -181,11 +176,6 @@ class MallocMemorySnapshot : public ResourceObj { // Total malloc'd memory used by arenas size_t total_arena() const; - inline size_t thread_count() const { - MallocMemorySnapshot* s = const_cast(this); - return s->by_type(mtThreadStack)->malloc_count(); - } - void copy_to(MallocMemorySnapshot* s) { // Need to make sure that mtChunks don't get deallocated while the // copy is going on, because their size is adjusted using this diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index b8674d1ca45fb..a9c50a8bf06df 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -2116,6 +2116,7 @@ JVM_ENTRY(jlong, jmm_GetTotalThreadAllocatedMemory(JNIEnv *env)) } { + assert(MonitoringSupport_lock != nullptr, "Must be"); MutexLocker ml(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag); if (result < high_water_result) { // Encountered (2) above, or result wrapped to a negative value. In diff --git a/src/hotspot/share/services/memBaseline.cpp b/src/hotspot/share/services/memBaseline.cpp index 4167e43f6b15e..c0522016e1eca 100644 --- a/src/hotspot/share/services/memBaseline.cpp +++ b/src/hotspot/share/services/memBaseline.cpp @@ -110,22 +110,25 @@ class MallocAllocationSiteWalker : public MallocSiteWalker { } }; -// Compare virtual memory region's base address -int compare_virtual_memory_base(const ReservedMemoryRegion& r1, const ReservedMemoryRegion& r2) { - return r1.compare(r2); -} - // Walk all virtual memory regions for baselining class VirtualMemoryAllocationWalker : public VirtualMemoryWalker { private: - SortedLinkedList - _virtual_memory_regions; - size_t _count; - + typedef LinkedListImpl EntryList; + EntryList _virtual_memory_regions; + size_t _count; + DEBUG_ONLY(address _last_base;) public: - VirtualMemoryAllocationWalker() : _count(0) { } + VirtualMemoryAllocationWalker() : + _count(0) +#ifdef ASSERT + , _last_base(nullptr) +#endif + {} bool do_allocation_site(const ReservedMemoryRegion* rgn) { + assert(rgn->base() >= _last_base, "region unordered?"); + DEBUG_ONLY(_last_base = rgn->base()); if (rgn->size() > 0) { if (_virtual_memory_regions.add(*rgn) != nullptr) { _count ++; @@ -190,6 +193,7 @@ void MemBaseline::baseline(bool summaryOnly) { _instance_class_count = ClassLoaderDataGraph::num_instance_classes(); _array_class_count = ClassLoaderDataGraph::num_array_classes(); + _thread_count = ThreadStackTracker::thread_count(); baseline_summary(); _baseline_type = Summary_baselined; diff --git a/src/hotspot/share/services/memBaseline.hpp b/src/hotspot/share/services/memBaseline.hpp index 5f2442d371061..fa44a45470461 100644 --- a/src/hotspot/share/services/memBaseline.hpp +++ b/src/hotspot/share/services/memBaseline.hpp @@ -64,6 +64,7 @@ class MemBaseline { size_t _instance_class_count; size_t _array_class_count; + size_t _thread_count; // Allocation sites information // Malloc allocation sites @@ -84,7 +85,7 @@ class MemBaseline { public: // create a memory baseline MemBaseline(): - _instance_class_count(0), _array_class_count(0), + _instance_class_count(0), _array_class_count(0), _thread_count(0), _baseline_type(Not_baselined) { } @@ -171,7 +172,7 @@ class MemBaseline { size_t thread_count() const { assert(baseline_type() != Not_baselined, "Not yet baselined"); - return _malloc_memory_snapshot.thread_count(); + return _thread_count; } // reset the baseline for reuse @@ -180,6 +181,7 @@ class MemBaseline { // _malloc_memory_snapshot and _virtual_memory_snapshot are copied over. _instance_class_count = 0; _array_class_count = 0; + _thread_count = 0; _malloc_sites.clear(); _virtual_memory_sites.clear(); diff --git a/src/hotspot/share/services/memReporter.cpp b/src/hotspot/share/services/memReporter.cpp index 7c5f37c69924d..717699d84ea6a 100644 --- a/src/hotspot/share/services/memReporter.cpp +++ b/src/hotspot/share/services/memReporter.cpp @@ -233,7 +233,6 @@ void MemSummaryReporter::report_summary_of_type(MEMFLAGS flag, MallocMemory* thread_stack_memory = _malloc_snapshot->by_type(mtThreadStack); const char* scale = current_scale(); // report thread count - assert(ThreadStackTracker::thread_count() == 0, "Not used"); out->print_cr("%27s (thread #" SIZE_FORMAT ")", " ", thread_stack_memory->malloc_count()); out->print("%27s (Stack: " SIZE_FORMAT "%s", " ", amount_in_current_scale(thread_stack_memory->malloc_size()), scale); @@ -243,7 +242,7 @@ void MemSummaryReporter::report_summary_of_type(MEMFLAGS flag, // report malloc'd memory if (amount_in_current_scale(malloc_memory->malloc_size()) > 0 - DEBUG_ONLY(|| amount_in_current_scale(malloc_memory->malloc_peak_size()) > 0)) { + || amount_in_current_scale(malloc_memory->malloc_peak_size()) > 0) { print_malloc_line(malloc_memory->malloc_counter()); } diff --git a/src/hotspot/share/services/nmtDCmd.cpp b/src/hotspot/share/services/nmtDCmd.cpp index f64c65c2dc89d..d6f80613b37c3 100644 --- a/src/hotspot/share/services/nmtDCmd.cpp +++ b/src/hotspot/share/services/nmtDCmd.cpp @@ -77,7 +77,7 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) { return; } - const char* scale_value = _scale.value(); + const char* scale_value = _scale.value() != nullptr ? _scale.value() : "(null)"; size_t scale_unit = get_scale(scale_value); if (scale_unit == 0) { output()->print_cr("Incorrect scale value: %s", scale_value); diff --git a/src/hotspot/share/services/threadIdTable.cpp b/src/hotspot/share/services/threadIdTable.cpp index ba0e6bdd4fdba..168b2e085adf2 100644 --- a/src/hotspot/share/services/threadIdTable.cpp +++ b/src/hotspot/share/services/threadIdTable.cpp @@ -187,13 +187,16 @@ class ThreadIdTableLookup : public StackObj { uintx get_hash() const { return _hash; } - bool equals(ThreadIdTableEntry** value, bool* is_dead) { + bool equals(ThreadIdTableEntry** value) { bool equals = primitive_equals(_tid, (*value)->tid()); if (!equals) { return false; } return true; } + bool is_dead(ThreadIdTableEntry** value) { + return false; + } }; class ThreadGet : public StackObj { diff --git a/src/hotspot/share/services/threadStackTracker.cpp b/src/hotspot/share/services/threadStackTracker.cpp index afed620bb8890..a6b14efc65700 100644 --- a/src/hotspot/share/services/threadStackTracker.cpp +++ b/src/hotspot/share/services/threadStackTracker.cpp @@ -49,40 +49,38 @@ int ThreadStackTracker::compare_thread_stack_base(const SimpleThreadStackSite& s void ThreadStackTracker::new_thread_stack(void* base, size_t size, const NativeCallStack& stack) { assert(MemTracker::tracking_level() >= NMT_summary, "Must be"); assert(base != nullptr, "Should have been filtered"); + ThreadCritical tc; if (track_as_vm()) { - ThreadCritical tc; VirtualMemoryTracker::add_reserved_region((address)base, size, stack, mtThreadStack); - _thread_count ++; } else { // Use a slot in mallocMemorySummary for thread stack bookkeeping MallocMemorySummary::record_malloc(size, mtThreadStack); if (MemTracker::tracking_level() == NMT_detail) { - ThreadCritical tc; assert(_simple_thread_stacks != nullptr, "Must be initialized"); SimpleThreadStackSite site((address)base, size, stack); _simple_thread_stacks->add(site); } } + _thread_count++; } void ThreadStackTracker::delete_thread_stack(void* base, size_t size) { assert(MemTracker::tracking_level() >= NMT_summary, "Must be"); assert(base != nullptr, "Should have been filtered"); + ThreadCritical tc; if(track_as_vm()) { - ThreadCritical tc; VirtualMemoryTracker::remove_released_region((address)base, size); - _thread_count--; } else { // Use a slot in mallocMemorySummary for thread stack bookkeeping MallocMemorySummary::record_free(size, mtThreadStack); if (MemTracker::tracking_level() == NMT_detail) { - ThreadCritical tc; assert(_simple_thread_stacks != nullptr, "Must be initialized"); SimpleThreadStackSite site((address)base, size, NativeCallStack::empty_stack()); // Fake object just to serve as compare target for delete bool removed = _simple_thread_stacks->remove(site); assert(removed, "Must exist"); } } + _thread_count--; } bool ThreadStackTracker::walk_simple_thread_stack_site(MallocSiteWalker* walker) { diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index 0d62a9f162e29..b222d379b722b 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -455,9 +455,8 @@ inline bool ConcurrentHashTable:: assert(bucket->is_locked(), "Must be locked."); Node* const volatile * rem_n_prev = bucket->first_ptr(); Node* rem_n = bucket->first(); - bool have_dead = false; while (rem_n != nullptr) { - if (lookup_f.equals(rem_n->value(), &have_dead)) { + if (lookup_f.equals(rem_n->value())) { bucket->release_assign_node_ptr(rem_n_prev, rem_n->next()); break; } else { @@ -546,9 +545,7 @@ inline void ConcurrentHashTable:: Node* const volatile * rem_n_prev = bucket->first_ptr(); Node* rem_n = bucket->first(); while (rem_n != nullptr) { - bool is_dead = false; - lookup_f.equals(rem_n->value(), &is_dead); - if (is_dead) { + if (lookup_f.is_dead(rem_n->value())) { ndel[dels++] = rem_n; Node* next_node = rem_n->next(); bucket->release_assign_node_ptr(rem_n_prev, next_node); @@ -626,12 +623,11 @@ ConcurrentHashTable:: size_t loop_count = 0; Node* node = bucket->first(); while (node != nullptr) { - bool is_dead = false; ++loop_count; - if (lookup_f.equals(node->value(), &is_dead)) { + if (lookup_f.equals(node->value())) { break; } - if (is_dead && !(*have_dead)) { + if (!(*have_dead) && lookup_f.is_dead(node->value())) { *have_dead = true; } node = node->next(); diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index becaf7957990f..7e6ebf9fdde13 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -411,6 +411,9 @@ inline size_t byte_size_in_exact_unit(size_t s) { return s; } +#define EXACTFMT SIZE_FORMAT "%s" +#define EXACTFMTARGS(s) byte_size_in_exact_unit(s), exact_unit_for_byte_size(s) + // Memory size transition formatting. #define HEAP_CHANGE_FORMAT "%s: " SIZE_FORMAT "K(" SIZE_FORMAT "K)->" SIZE_FORMAT "K(" SIZE_FORMAT "K)" @@ -638,7 +641,7 @@ const bool support_IRIW_for_not_multiple_copy_atomic_cpu = PPC64_ONLY(true) NOT_ // The expected size in bytes of a cache line, used to pad data structures. #ifndef DEFAULT_CACHE_LINE_SIZE - #define DEFAULT_CACHE_LINE_SIZE 64 +#error "Platform should define DEFAULT_CACHE_LINE_SIZE" #endif diff --git a/src/hotspot/share/utilities/growableArray.hpp b/src/hotspot/share/utilities/growableArray.hpp index 13de5dec6c1b1..d9c47e8360fdb 100644 --- a/src/hotspot/share/utilities/growableArray.hpp +++ b/src/hotspot/share/utilities/growableArray.hpp @@ -142,17 +142,17 @@ class GrowableArrayView : public GrowableArrayBase { } E& at(int i) { - assert(0 <= i && i < _len, "illegal index"); + assert(0 <= i && i < _len, "illegal index %d for length %d", i, _len); return _data[i]; } E const& at(int i) const { - assert(0 <= i && i < _len, "illegal index"); + assert(0 <= i && i < _len, "illegal index %d for length %d", i, _len); return _data[i]; } E* adr_at(int i) const { - assert(0 <= i && i < _len, "illegal index"); + assert(0 <= i && i < _len, "illegal index %d for length %d", i, _len); return &_data[i]; } @@ -184,7 +184,7 @@ class GrowableArrayView : public GrowableArrayBase { } void at_put(int i, const E& elem) { - assert(0 <= i && i < _len, "illegal index"); + assert(0 <= i && i < _len, "illegal index %d for length %d", i, _len); _data[i] = elem; } @@ -245,7 +245,7 @@ class GrowableArrayView : public GrowableArrayBase { } void remove_at(int index) { - assert(0 <= index && index < _len, "illegal index"); + assert(0 <= index && index < _len, "illegal index %d for length %d", index, _len); for (int j = index + 1; j < _len; j++) { _data[j-1] = _data[j]; } @@ -259,8 +259,8 @@ class GrowableArrayView : public GrowableArrayBase { // Remove all elements in the range [start - end). The order is preserved. void remove_range(int start, int end) { - assert(0 <= start, "illegal index"); - assert(start < end && end <= _len, "erase called with invalid range"); + assert(0 <= start, "illegal start index %d", start); + assert(start < end && end <= _len, "erase called with invalid range (%d, %d) for length %d", start, end, _len); for (int i = start, j = end; j < length(); i++, j++) { at_put(i, at(j)); @@ -270,7 +270,7 @@ class GrowableArrayView : public GrowableArrayBase { // The order is changed. void delete_at(int index) { - assert(0 <= index && index < _len, "illegal index"); + assert(0 <= index && index < _len, "illegal index %d for length %d", index, _len); if (index < --_len) { // Replace removed element with last one. _data[index] = _data[_len]; @@ -403,7 +403,7 @@ class GrowableArrayWithAllocator : public GrowableArrayView { void push(const E& elem) { append(elem); } E at_grow(int i, const E& fill = E()) { - assert(0 <= i, "negative index"); + assert(0 <= i, "negative index %d", i); if (i >= this->_len) { if (i >= this->_capacity) grow(i); for (int j = this->_len; j <= i; j++) @@ -414,7 +414,7 @@ class GrowableArrayWithAllocator : public GrowableArrayView { } void at_put_grow(int i, const E& elem, const E& fill = E()) { - assert(0 <= i, "negative index"); + assert(0 <= i, "negative index %d", i); if (i >= this->_len) { if (i >= this->_capacity) grow(i); for (int j = this->_len; j < i; j++) @@ -426,7 +426,7 @@ class GrowableArrayWithAllocator : public GrowableArrayView { // inserts the given element before the element at index i void insert_before(const int idx, const E& elem) { - assert(0 <= idx && idx <= this->_len, "illegal index"); + assert(0 <= idx && idx <= this->_len, "illegal index %d for length %d", idx, this->_len); if (this->_len == this->_capacity) grow(this->_len); for (int j = this->_len - 1; j >= idx; j--) { this->_data[j + 1] = this->_data[j]; @@ -436,7 +436,7 @@ class GrowableArrayWithAllocator : public GrowableArrayView { } void insert_before(const int idx, const GrowableArrayView* array) { - assert(0 <= idx && idx <= this->_len, "illegal index"); + assert(0 <= idx && idx <= this->_len, "illegal index %d for length %d", idx, this->_len); int array_len = array->length(); int new_len = this->_len + array_len; if (new_len >= this->_capacity) grow(new_len); diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 2bcc1ddc2215f..5c0b4440e2cd5 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -54,6 +54,7 @@ #include "runtime/stackOverflow.hpp" #include "runtime/threads.hpp" #include "runtime/threadSMR.hpp" +#include "runtime/trimNativeHeap.hpp" #include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" #include "runtime/vm_version.hpp" @@ -106,6 +107,8 @@ static const char* env_list[] = { "JAVA_HOME", "JAVA_TOOL_OPTIONS", "_JAVA_OPTIONS", "CLASSPATH", "PATH", "USERNAME", + "XDG_CACHE_HOME", "XDG_CONFIG_HOME", "FC_LANG", "FONTCONFIG_USE_MMAP", + // Env variables that are defined on Linux/BSD "LD_LIBRARY_PATH", "LD_PRELOAD", "SHELL", "DISPLAY", "HOSTTYPE", "OSTYPE", "ARCH", "MACHTYPE", @@ -423,7 +426,7 @@ static frame next_frame(frame fr, Thread* t) { if (!t->is_in_full_stack((address)(fr.real_fp() + 1))) { return invalid; } - if (fr.is_java_frame() || fr.is_native_frame() || fr.is_runtime_frame()) { + if (fr.is_interpreted_frame() || (fr.cb() != nullptr && fr.cb()->frame_size() > 0)) { RegisterMap map(JavaThread::cast(t), RegisterMap::UpdateMap::skip, RegisterMap::ProcessFrames::include, @@ -479,7 +482,7 @@ static void print_oom_reasons(outputStream* st) { st->print_cr("# Possible reasons:"); st->print_cr("# The system is out of physical RAM or swap space"); if (UseCompressedOops) { - st->print_cr("# The process is running with CompressedOops enabled, and the Java Heap may be blocking the growth of the native heap"); + st->print_cr("# This process is running with CompressedOops enabled, and the Java Heap may be blocking the growth of the native heap"); } if (LogBytesPerWord == 2) { st->print_cr("# In 32 bit mode, the process size limit was hit"); @@ -711,6 +714,11 @@ void VMError::report(outputStream* st, bool _verbose) { "Runtime Environment to continue."); } + // avoid the cache update for malloc/mmap errors + if (should_report_bug(_id)) { + os::prepare_native_symbols(); + } + #ifdef ASSERT // Error handler self tests // Meaning of codes passed through in the tests. @@ -817,9 +825,9 @@ void VMError::report(outputStream* st, bool _verbose) { "(mprotect) failed to protect "); jio_snprintf(buf, sizeof(buf), SIZE_FORMAT, _size); st->print("%s", buf); - st->print(" bytes"); + st->print(" bytes."); if (strlen(_detail_msg) > 0) { - st->print(" for "); + st->print(" Error detail: "); st->print("%s", _detail_msg); } st->cr(); @@ -1091,6 +1099,11 @@ void VMError::report(outputStream* st, bool _verbose) { print_stack_location(st, _context, continuation); st->cr(); + STEP_IF("printing lock stack", _verbose && _thread != nullptr && _thread->is_Java_thread() && LockingMode == LM_LIGHTWEIGHT); + st->print_cr("Lock stack of current Java thread (top to bottom):"); + JavaThread::cast(_thread)->lock_stack().print_on(st); + st->cr(); + STEP_IF("printing code blobs if possible", _verbose) const int printed_capacity = max_error_log_print_code; address printed[printed_capacity]; @@ -1284,9 +1297,13 @@ void VMError::report(outputStream* st, bool _verbose) { STEP_IF("Native Memory Tracking", _verbose) MemTracker::error_report(st); + st->cr(); - STEP_IF("printing system", _verbose) + STEP_IF("printing periodic trim state", _verbose) + NativeHeapTrimmer::print_state(st); st->cr(); + + STEP_IF("printing system", _verbose) st->print_cr("--------------- S Y S T E M ---------------"); st->cr(); @@ -1325,6 +1342,8 @@ void VMError::report(outputStream* st, bool _verbose) { void VMError::print_vm_info(outputStream* st) { char buf[O_BUFLEN]; + os::prepare_native_symbols(); + report_vm_version(st, buf, sizeof(buf)); // STEP("printing summary") @@ -1453,10 +1472,14 @@ void VMError::print_vm_info(outputStream* st) { // STEP("Native Memory Tracking") MemTracker::error_report(st); + st->cr(); - // STEP("printing system") - + // STEP("printing periodic trim state") + NativeHeapTrimmer::print_state(st); st->cr(); + + + // STEP("printing system") st->print_cr("--------------- S Y S T E M ---------------"); st->cr(); @@ -1827,6 +1850,7 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt int e = errno; out.print_raw("#\n# Can't open file to dump replay data. Error: "); out.print_raw_cr(os::strerror(e)); + close(fd); } } } diff --git a/src/java.base/aix/native/libjava/ProcessHandleImpl_aix.c b/src/java.base/aix/native/libjava/ProcessHandleImpl_aix.c index 93347bd8c2071..3568af24ce438 100644 --- a/src/java.base/aix/native/libjava/ProcessHandleImpl_aix.c +++ b/src/java.base/aix/native/libjava/ProcessHandleImpl_aix.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,10 +24,12 @@ */ #include "jni.h" +#include "jni_util.h" #include "ProcessHandleImpl_unix.h" #include +#include /* * Implementation of native ProcessHandleImpl functions for AIX. @@ -36,9 +38,127 @@ void os_initNative(JNIEnv *env, jclass clazz) {} +/* + * Return pids of active processes, and optionally parent pids and + * start times for each process. + * For a specific non-zero pid, only the direct children are returned. + * If the pid is zero, all active processes are returned. + * Use getprocs64 to accumulate any process following the rules above. + * The resulting pids are stored into an array of longs named jarray. + * The number of pids is returned if they all fit. + * If the parentArray is non-null, store also the parent pid. + * In this case the parentArray must have the same length as the result pid array. + * Of course in the case of a given non-zero pid all entries in the parentArray + * will contain this pid, so this array does only make sense in the case of a given + * zero pid. + * If the jstimesArray is non-null, store also the start time of the pid. + * In this case the jstimesArray must have the same length as the result pid array. + * If the array(s) (is|are) too short, excess pids are not stored and + * the desired length is returned. + */ jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray, jlongArray jparentArray, jlongArray jstimesArray) { - return unix_getChildren(env, jpid, jarray, jparentArray, jstimesArray); + pid_t pid = (pid_t) jpid; + jlong* pids = NULL; + jlong* ppids = NULL; + jlong* stimes = NULL; + jsize parentArraySize = 0; + jsize arraySize = 0; + jsize stimesSize = 0; + jsize count = 0; + + arraySize = (*env)->GetArrayLength(env, jarray); + JNU_CHECK_EXCEPTION_RETURN(env, -1); + if (jparentArray != NULL) { + parentArraySize = (*env)->GetArrayLength(env, jparentArray); + JNU_CHECK_EXCEPTION_RETURN(env, -1); + + if (arraySize != parentArraySize) { + JNU_ThrowIllegalArgumentException(env, "array sizes not equal"); + return 0; + } + } + if (jstimesArray != NULL) { + stimesSize = (*env)->GetArrayLength(env, jstimesArray); + JNU_CHECK_EXCEPTION_RETURN(env, -1); + + if (arraySize != stimesSize) { + JNU_ThrowIllegalArgumentException(env, "array sizes not equal"); + return 0; + } + } + + const int chunk = 100; + struct procentry64 ProcessBuffer[chunk]; + pid_t idxptr = 0; + int i, num = 0; + + do { // Block to break out of on Exception + pids = (*env)->GetLongArrayElements(env, jarray, NULL); + if (pids == NULL) { + break; + } + if (jparentArray != NULL) { + ppids = (*env)->GetLongArrayElements(env, jparentArray, NULL); + if (ppids == NULL) { + break; + } + } + if (jstimesArray != NULL) { + stimes = (*env)->GetLongArrayElements(env, jstimesArray, NULL); + if (stimes == NULL) { + break; + } + } + + while ((num = getprocs64(ProcessBuffer, sizeof(struct procentry64), NULL, + sizeof(struct fdsinfo64), &idxptr, chunk)) != -1) { + for (i = 0; i < num; i++) { + pid_t childpid = (pid_t) ProcessBuffer[i].pi_pid; + pid_t ppid = (pid_t) ProcessBuffer[i].pi_ppid; + + // Get the parent pid, and start time + if (pid == 0 || ppid == pid) { + if (count < arraySize) { + // Only store if it fits + pids[count] = (jlong) childpid; + + if (ppids != NULL) { + // Store the parentPid + ppids[count] = (jlong) ppid; + } + if (stimes != NULL) { + // Store the process start time + stimes[count] = ((jlong) ProcessBuffer[i].pi_start) * 1000;; + } + } + count++; // Count to tabulate size needed + } + } + if (num < chunk) { + break; + } + } + } while (0); + + if (pids != NULL) { + (*env)->ReleaseLongArrayElements(env, jarray, pids, 0); + } + if (ppids != NULL) { + (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0); + } + if (stimes != NULL) { + (*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0); + } + + if (num == -1) { + JNU_ThrowByNameWithLastError(env, + "java/lang/RuntimeException", "Unable to retrieve Process info"); + return -1; + } + + // If more pids than array had size for; count will be greater than array size + return count; } pid_t os_getParentPidAndTimings(JNIEnv *env, pid_t pid, jlong *total, jlong *start) { diff --git a/src/java.base/aix/native/libnio/MappedMemoryUtils.c b/src/java.base/aix/native/libnio/MappedMemoryUtils.c new file mode 100644 index 0000000000000..5d0216cc25102 --- /dev/null +++ b/src/java.base/aix/native/libnio/MappedMemoryUtils.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "java_nio_MappedMemoryUtils.h" +#include +#include +#include +#include +#include +#include +#include + +typedef char mincore_vec_t; + +static long calculate_number_of_pages_in_range(void* address, size_t len, size_t pagesize) { + uintptr_t address_unaligned = (uintptr_t) address; + uintptr_t address_aligned = address_unaligned & (~(pagesize - 1)); + size_t len2 = len + (address_unaligned - address_aligned); + long numPages = (len2 + pagesize - 1) / pagesize; + return numPages; +} + +JNIEXPORT jboolean JNICALL +Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, + jlong len, jlong numPages) +{ + jboolean loaded = JNI_TRUE; + int result = 0; + long i = 0; + void *a = (void *) jlong_to_ptr(address); + mincore_vec_t* vec = NULL; + + /* See JDK-8186665 */ + size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); + if ((long)pagesize == -1) { + return JNI_FALSE; + } + numPages = (jlong) calculate_number_of_pages_in_range(a, len, pagesize); + + /* Include space for one sentinel byte at the end of the buffer + * to catch overflows. */ + vec = (mincore_vec_t*) malloc(numPages + 1); + + if (vec == NULL) { + JNU_ThrowOutOfMemoryError(env, NULL); + return JNI_FALSE; + } + + vec[numPages] = '\x7f'; /* Write sentinel. */ + result = mincore(a, (size_t)len, vec); + assert(vec[numPages] == '\x7f'); /* Check sentinel. */ + + if (result == -1) { + JNU_ThrowIOExceptionWithLastError(env, "mincore failed"); + free(vec); + return JNI_FALSE; + } + + for (i=0; ipr_mflags & MA_SHARED) { + // MA_SHARED => MAP_SHARED => !MAP_PRIVATE. This error is valid and should be thrown. + JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed (MAP_SHARED)"); + return; + } else { + // O.W. MAP_PRIVATE or no flag was specified and EINVAL is the expected behaviour. + return; + } +} + +static void check_proc_map_array(JNIEnv* env, FILE* proc_file, prmap_t* map_entry, void* end_address) +{ + while (!feof(proc_file)) { + memset(map_entry, '\0', sizeof(prmap_t)); + fread((char*)map_entry, sizeof(prmap_t), 1, proc_file); + if (ferror(proc_file)) { + JNU_ThrowIOExceptionWithMessageAndLastError(env, + "msync with parameter MS_SYNC failed (could not read /proc//map)"); + return; + } else if (map_entry->pr_vaddr <= end_address && + (uint64_t)end_address <= (uint64_t)map_entry->pr_vaddr + map_entry->pr_size) { + set_error_if_shared(env, map_entry); + return; + } + } + JNU_ThrowIOExceptionWithMessageAndLastError(env, + "msync with parameter MS_SYNC failed (address not found)"); +} + +// '/proc/' + + '/map' + '\0' +#define PFNAME_LEN 32 +static void check_aix_einval(JNIEnv* env, void* end_address) +{ + // If EINVAL is set for a mmap address on AIX, additional validation is required. + // AIX will set EINVAL when msync is called on a mmap address that didn't receive MAP_SHARED + // as a flag (since MAP_PRIVATE is the default). + // https://www.ibm.com/docs/en/aix/7.2?topic=m-msync-subroutine + + FILE* proc_file; + { + char* fname = (char*) malloc(sizeof(char) * PFNAME_LEN); + if (fname == NULL) { + JNU_ThrowOutOfMemoryError(env, NULL); + return; + } + + pid_t the_pid = getpid(); + jio_snprintf(fname, PFNAME_LEN, "/proc/%d/map", the_pid); + proc_file = fopen(fname, "r"); + free(fname); + } + if (!proc_file) { + JNU_ThrowIOExceptionWithMessageAndLastError(env, + "msync with parameter MS_SYNC failed (could not open /proc//map)"); + return; + } + { + prmap_t* map_entry = (prmap_t*) malloc(sizeof(prmap_t)); + if (map_entry == NULL) { + JNU_ThrowOutOfMemoryError(env, NULL); + fclose(proc_file); + return; + } + check_proc_map_array(env, proc_file, map_entry, end_address); + free(map_entry); + } + fclose(proc_file); +} + +// Normally we would just let msync handle this, but since we'll be (potentially) ignoring +// the error code returned by msync, we check the args before the call instead. +static int validate_msync_address(size_t address) +{ + size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); + if (address % pagesize != 0) { + errno = EINVAL; + return -1; + } + return 0; +} + +JNIEXPORT void JNICALL +Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, + jlong address, jlong len) +{ + void* a = (void *)jlong_to_ptr(address); + if (validate_msync_address((size_t)a) > 0) { + JNU_ThrowIOExceptionWithMessageAndLastError(env, + "msync with parameter MS_SYNC failed (arguments invalid)"); + return; + } + int result = msync(a, (size_t)len, MS_SYNC); + if (result == -1) { + void* end_address = (void*)jlong_to_ptr(address + len); + if (errno == EINVAL) { + check_aix_einval(env, end_address); + return; + } + JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed"); + } +} diff --git a/src/java.base/aix/native/libnio/fs/AixNativeDispatcher.c b/src/java.base/aix/native/libnio/fs/AixNativeDispatcher.c index a4fb473507c62..c0a59f651971a 100644 --- a/src/java.base/aix/native/libnio/fs/AixNativeDispatcher.c +++ b/src/java.base/aix/native/libnio/fs/AixNativeDispatcher.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2013, 2019 SAP SE. All rights reserved. + * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2023 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 @@ -105,6 +105,10 @@ Java_sun_nio_fs_AixNativeDispatcher_getmntctl(JNIEnv* env, jclass this) } buffer_size *= 8; buffer = malloc(buffer_size); + if (buffer == NULL) { + throwUnixException(env, errno); + return NULL; + } must_free_buf = 1; } /* Treat zero entries like errors. */ diff --git a/src/java.base/linux/native/libjava/CgroupMetrics.c b/src/java.base/linux/native/libjava/CgroupMetrics.c index 4f7847edbde16..a5e41167bc319 100644 --- a/src/java.base/linux/native/libjava/CgroupMetrics.c +++ b/src/java.base/linux/native/libjava/CgroupMetrics.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Red Hat, Inc. + * Copyright (c) 2020, 2024, 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 @@ -54,5 +54,5 @@ Java_jdk_internal_platform_CgroupMetrics_getTotalSwapSize0 if (retval < 0) { return 0; // syinfo failed, treat as no swap } - return (jlong)si.totalswap; + return (jlong)(si.totalswap * si.mem_unit); } diff --git a/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c b/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c index 8987f0b97a4da..e3d811cfca6c3 100644 --- a/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c +++ b/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c @@ -47,13 +47,21 @@ void os_initNative(JNIEnv *env, jclass clazz) {} /* - * Returns the children of the requested pid and optionally each parent. - * - * Use sysctl to accumulate any process whose parent pid is zero or matches. - * The resulting pids are stored into the array of longs. + * Return pids of active processes, and optionally parent pids and + * start times for each process. + * For a specific non-zero pid jpid, only the direct children are returned. + * If the pid jpid is zero, all active processes are returned. + * Uses sysctl to accumulates any process following the rules above. + * The resulting pids are stored into an array of longs named jarray. * The number of pids is returned if they all fit. - * If the parentArray is non-null, store the parent pid. - * If the array is too short, excess pids are not stored and + * If the parentArray is non-null, store also the parent pid. + * In this case the parentArray must have the same length as the result pid array. + * Of course in the case of a given non-zero pid all entries in the parentArray + * will contain this pid, so this array does only make sense in the case of a given + * zero pid. + * If the jstimesArray is non-null, store also the start time of the pid. + * In this case the jstimesArray must have the same length as the result pid array. + * If the array(s) (is|are) too short, excess pids are not stored and * the desired length is returned. */ jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray, diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java index 21e7247e87b90..daea2659f6353 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package com.sun.crypto.provider; +import java.io.IOException; +import java.io.InvalidObjectException; import java.lang.ref.Reference; import java.security.MessageDigest; import java.security.KeyRep; @@ -44,7 +46,7 @@ final class DESKey implements SecretKey { @java.io.Serial - static final long serialVersionUID = 7724971015953279128L; + private static final long serialVersionUID = 7724971015953279128L; private byte[] key; @@ -113,7 +115,7 @@ public int hashCode() { for (int i = 1; i < this.key.length; i++) { retval += this.key[i] * i; } - return(retval ^= "des".hashCode()); + return(retval ^ "des".hashCode()); } public boolean equals(Object obj) { @@ -134,15 +136,28 @@ public boolean equals(Object obj) { } /** - * readObject is called to restore the state of this key from - * a stream. + * Restores the state of this object from the stream. + * + * @param s the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded */ @java.io.Serial private void readObject(java.io.ObjectInputStream s) - throws java.io.IOException, ClassNotFoundException + throws IOException, ClassNotFoundException { s.defaultReadObject(); + if ((key == null) || (key.length != DESKeySpec.DES_KEY_LEN)) { + throw new InvalidObjectException("Wrong key size"); + } key = key.clone(); + + DESKeyGenerator.setParityBit(key, 0); + + // Use the cleaner to zero the key when no longer referenced + final byte[] k = key; + CleanerFactory.cleaner().register(this, + () -> java.util.Arrays.fill(k, (byte)0x00)); } /** diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java index 2847f30501793..031495f27a441 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package com.sun.crypto.provider; +import java.io.IOException; +import java.io.InvalidObjectException; import java.lang.ref.Reference; import java.security.MessageDigest; import java.security.KeyRep; @@ -44,7 +46,7 @@ final class DESedeKey implements SecretKey { @java.io.Serial - static final long serialVersionUID = 2463986565756745178L; + private static final long serialVersionUID = 2463986565756745178L; private byte[] key; @@ -112,7 +114,7 @@ public int hashCode() { for (int i = 1; i < this.key.length; i++) { retval += this.key[i] * i; } - return(retval ^= "desede".hashCode()); + return(retval ^ "desede".hashCode()); } public boolean equals(Object obj) { @@ -134,15 +136,30 @@ public boolean equals(Object obj) { } /** - * readObject is called to restore the state of this key from - * a stream. + * Restores the state of this object from the stream. + * + * @param s the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded */ @java.io.Serial private void readObject(java.io.ObjectInputStream s) - throws java.io.IOException, ClassNotFoundException + throws IOException, ClassNotFoundException { s.defaultReadObject(); + if ((key == null) || (key.length != DESedeKeySpec.DES_EDE_KEY_LEN)) { + throw new InvalidObjectException("Wrong key size"); + } key = key.clone(); + + DESKeyGenerator.setParityBit(key, 0); + DESKeyGenerator.setParityBit(key, 8); + DESKeyGenerator.setParityBit(key, 16); + + // Use the cleaner to zero the key when no longer referenced + final byte[] k = key; + CleanerFactory.cleaner().register(this, + () -> java.util.Arrays.fill(k, (byte)0x00)); } /** diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java index c2c8348fffad6..a8e5c6cba73b0 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,8 +40,6 @@ * algorithm. * * @author Jan Luehe - * - * * @see DHPublicKey * @see javax.crypto.KeyAgreement */ @@ -49,7 +47,7 @@ final class DHPrivateKey implements PrivateKey, javax.crypto.interfaces.DHPrivateKey, Serializable { @java.io.Serial - static final long serialVersionUID = 7565477590005668886L; + private static final long serialVersionUID = 7565477590005668886L; // only supported version of PKCS#8 PrivateKeyInfo private static final BigInteger PKCS8_VERSION = BigInteger.ZERO; @@ -64,10 +62,10 @@ final class DHPrivateKey implements PrivateKey, private byte[] encodedKey; // the prime modulus - private BigInteger p; + private final BigInteger p; // the base generator - private BigInteger g; + private final BigInteger g; // the private-value length (optional) private int l; @@ -321,4 +319,28 @@ private Object writeReplace() throws java.io.ObjectStreamException { getFormat(), encodedKey); } + + /** + * Restores the state of this object from the stream. + *

+ * JDK 1.5+ objects use KeyReps instead. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + if ((key == null) || (key.length == 0)) { + throw new InvalidObjectException("key not deserializable"); + } + this.key = key.clone(); + if ((encodedKey == null) || (encodedKey.length == 0)) { + throw new InvalidObjectException( + "encoded key not deserializable"); + } + this.encodedKey = encodedKey.clone(); + } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java index c786743aab053..565a71da0cf56 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,8 +39,6 @@ * A public key in X.509 format for the Diffie-Hellman key agreement algorithm. * * @author Jan Luehe - * - * * @see DHPrivateKey * @see javax.crypto.KeyAgreement */ @@ -48,7 +46,7 @@ final class DHPublicKey implements PublicKey, javax.crypto.interfaces.DHPublicKey, Serializable { @java.io.Serial - static final long serialVersionUID = 7647557958927458271L; + private static final long serialVersionUID = 7647557958927458271L; // the public key private BigInteger y; @@ -60,10 +58,10 @@ final class DHPublicKey implements PublicKey, private byte[] encodedKey; // the prime modulus - private BigInteger p; + private final BigInteger p; // the base generator - private BigInteger g; + private final BigInteger g; // the private-value length (optional) private int l; @@ -313,4 +311,28 @@ private Object writeReplace() throws java.io.ObjectStreamException { getFormat(), getEncoded()); } + + /** + * Restores the state of this object from the stream. + *

+ * JDK 1.5+ objects use KeyReps instead. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + if ((key == null) || (key.length == 0)) { + throw new InvalidObjectException("key not deserializable"); + } + this.key = key.clone(); + if ((encodedKey == null) || (encodedKey.length == 0)) { + throw new InvalidObjectException( + "encoded key not deserializable"); + } + this.encodedKey = encodedKey.clone(); + } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java index f676c4dd1a669..03b481af6c2f4 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java @@ -1572,6 +1572,13 @@ public int doFinal(ByteBuffer src, ByteBuffer dst) len += buffer.remaining(); } + // Check that input data is long enough to fit the expected tag. + if (len < 0) { + throw new AEADBadTagException("Input data too short to " + + "contain an expected tag length of " + tagLenBytes + + "bytes"); + } + checkDataLength(len); // Verify dst is large enough diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java b/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java index 15c9c1f3d59c9..67efe74f8587a 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package com.sun.crypto.provider; +import java.io.IOException; +import java.io.InvalidObjectException; import java.lang.ref.Reference; import java.security.MessageDigest; import java.security.KeyRep; @@ -45,11 +47,11 @@ final class PBEKey implements SecretKey { @java.io.Serial - static final long serialVersionUID = -2234768909660948176L; + private static final long serialVersionUID = -2234768909660948176L; private byte[] key; - private String type; + private final String type; /** * Creates a PBE key from a given PBE key specification. @@ -110,7 +112,7 @@ public int hashCode() { for (int i = 1; i < this.key.length; i++) { retval += this.key[i] * i; } - return(retval ^= getAlgorithm().toLowerCase(Locale.ENGLISH).hashCode()); + return(retval ^ getAlgorithm().toLowerCase(Locale.ENGLISH).hashCode()); } public boolean equals(Object obj) { @@ -144,15 +146,38 @@ public void destroy() { } /** - * readObject is called to restore the state of this key from - * a stream. + * Restores the state of this object from the stream. + * + * @param s the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded */ @java.io.Serial private void readObject(java.io.ObjectInputStream s) - throws java.io.IOException, ClassNotFoundException + throws IOException, ClassNotFoundException { s.defaultReadObject(); + if (key == null) { + throw new InvalidObjectException( + "PBEKey couldn't be deserialized"); + } key = key.clone(); + + // Accept "\0" to signify "zero-length password with no terminator". + if (!(key.length == 1 && key[0] == 0)) { + for (int i = 0; i < key.length; i++) { + if ((key[i] < '\u0020') || (key[i] > '\u007E')) { + throw new InvalidObjectException( + "PBEKey had non-ASCII chars"); + } + } + } + + // Use the cleaner to zero the key when no longer referenced + final byte[] k = this.key; + CleanerFactory.cleaner().register(this, + () -> Arrays.fill(k, (byte) 0x00)); + } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java index 5815b5ca0639c..1e9e7615081d5 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java @@ -25,7 +25,7 @@ package com.sun.crypto.provider; -import java.io.ObjectStreamException; +import java.io.*; import java.lang.ref.Reference; import java.lang.ref.Cleaner; import java.nio.ByteBuffer; @@ -58,15 +58,15 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey { @java.io.Serial - static final long serialVersionUID = -2234868909660948157L; + private static final long serialVersionUID = -2234868909660948157L; - private char[] passwd; - private byte[] salt; - private int iterCount; + private final char[] passwd; + private final byte[] salt; + private final int iterCount; private byte[] key; // The following fields are not Serializable. See writeReplace method. - private transient Mac prf; + private transient final Mac prf; private transient Cleaner.Cleanable cleaner; private static byte[] getPasswordBytes(char[] passwd) { @@ -141,13 +141,14 @@ private static byte[] deriveKey(final Mac prf, final byte[] password, int intR = keyLength - (intL - 1)*hlen; // residue byte[] ui = new byte[hlen]; byte[] ti = new byte[hlen]; + String algName = prf.getAlgorithm(); // SecretKeySpec cannot be used, since password can be empty here. SecretKey macKey = new SecretKey() { @java.io.Serial private static final long serialVersionUID = 7874493593505141603L; @Override public String getAlgorithm() { - return prf.getAlgorithm(); + return algName; } @Override public String getFormat() { @@ -160,18 +161,27 @@ public byte[] getEncoded() { @Override public int hashCode() { return Arrays.hashCode(password) * 41 + - prf.getAlgorithm().toLowerCase(Locale.ENGLISH).hashCode(); + algName.toLowerCase(Locale.ENGLISH).hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (this.getClass() != obj.getClass()) return false; SecretKey sk = (SecretKey)obj; - return prf.getAlgorithm().equalsIgnoreCase( + return algName.equalsIgnoreCase( sk.getAlgorithm()) && MessageDigest.isEqual(password, sk.getEncoded()); } + // This derived key can't be deserialized. + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "PBKDF2KeyImpl SecretKeys are not " + + "directly deserializable"); + } }; + prf.init(macKey); byte[] ibytes = new byte[4]; @@ -307,4 +317,20 @@ private Object writeReplace() throws ObjectStreamException { Reference.reachabilityFence(this); } } + + /** + * Restores the state of this object from the stream. + *

+ * Deserialization of this class is not supported. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "PBKDF2KeyImpl keys are not directly deserializable"); + } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java index f9c910e2ff1a8..df76f78bfb5e0 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,6 +98,7 @@ public final class RSACipher extends CipherSpi { // cipher parameter for OAEP padding and TLS RSA premaster secret private AlgorithmParameterSpec spec = null; + private boolean forTlsPremasterSecret = false; // buffer for the data private byte[] buffer; @@ -286,6 +287,7 @@ private void init(int opmode, Key key, SecureRandom random, } spec = params; + forTlsPremasterSecret = true; this.random = random; // for TLS RSA premaster secret } int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2 @@ -349,21 +351,38 @@ private byte[] doFinal() throws BadPaddingException, switch (mode) { case MODE_SIGN: paddingCopy = padding.pad(buffer, 0, bufOfs); - result = RSACore.rsa(paddingCopy, privateKey, true); + if (paddingCopy != null) { + result = RSACore.rsa(paddingCopy, privateKey, true); + } else { + throw new BadPaddingException("Padding error in signing"); + } break; case MODE_VERIFY: byte[] verifyBuffer = RSACore.convert(buffer, 0, bufOfs); paddingCopy = RSACore.rsa(verifyBuffer, publicKey); result = padding.unpad(paddingCopy); + if (result == null) { + throw new BadPaddingException + ("Padding error in verification"); + } break; case MODE_ENCRYPT: paddingCopy = padding.pad(buffer, 0, bufOfs); - result = RSACore.rsa(paddingCopy, publicKey); + if (paddingCopy != null) { + result = RSACore.rsa(paddingCopy, publicKey); + } else { + throw new BadPaddingException + ("Padding error in encryption"); + } break; case MODE_DECRYPT: byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs); paddingCopy = RSACore.rsa(decryptBuffer, privateKey, false); result = padding.unpad(paddingCopy); + if (result == null && !forTlsPremasterSecret) { + throw new BadPaddingException + ("Padding error in decryption"); + } break; default: throw new AssertionError("Internal error"); @@ -372,9 +391,9 @@ private byte[] doFinal() throws BadPaddingException, } finally { Arrays.fill(buffer, 0, bufOfs, (byte)0); bufOfs = 0; - if (paddingCopy != null // will not happen + if (paddingCopy != null && paddingCopy != buffer // already cleaned - && paddingCopy != result) { // DO NOT CLEAN, THIS IS RESULT! + && paddingCopy != result) { // DO NOT CLEAN, THIS IS RESULT Arrays.fill(paddingCopy, (byte)0); } } @@ -449,26 +468,22 @@ protected Key engineUnwrap(byte[] wrappedKey, String algorithm, boolean isTlsRsaPremasterSecret = algorithm.equals("TlsRsaPremasterSecret"); - Exception failover = null; byte[] encoded = null; update(wrappedKey, 0, wrappedKey.length); try { encoded = doFinal(); - } catch (BadPaddingException e) { - if (isTlsRsaPremasterSecret) { - failover = e; - } else { - throw new InvalidKeyException("Unwrapping failed", e); - } - } catch (IllegalBlockSizeException e) { - // should not occur, handled with length check above + } catch (BadPaddingException | IllegalBlockSizeException e) { + // BadPaddingException cannot happen for TLS RSA unwrap. + // In that case, padding error is indicated by returning null. + // IllegalBlockSizeException cannot happen in any case, + // because of the length check above. throw new InvalidKeyException("Unwrapping failed", e); } try { if (isTlsRsaPremasterSecret) { - if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { + if (!forTlsPremasterSecret) { throw new IllegalStateException( "No TlsRsaPremasterSecretParameterSpec specified"); } @@ -477,7 +492,7 @@ protected Key engineUnwrap(byte[] wrappedKey, String algorithm, encoded = KeyUtil.checkTlsPreMasterSecretKey( ((TlsRsaPremasterSecretParameterSpec) spec).getClientVersion(), ((TlsRsaPremasterSecretParameterSpec) spec).getServerVersion(), - random, encoded, (failover != null)); + random, encoded, encoded == null); } return ConstructKeys.constructKey(encoded, algorithm, type); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java index 203d54495f22c..14ada1699c18c 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,9 @@ package com.sun.crypto.provider; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; import java.security.*; import java.security.spec.AlgorithmParameterSpec; import java.util.Arrays; @@ -62,11 +65,11 @@ protected void engineInit(SecureRandom random) { @SuppressWarnings("deprecation") protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { - if (params instanceof TlsMasterSecretParameterSpec == false) { + if (!(params instanceof TlsMasterSecretParameterSpec)) { throw new InvalidAlgorithmParameterException(MSG); } this.spec = (TlsMasterSecretParameterSpec)params; - if ("RAW".equals(spec.getPremasterSecret().getFormat()) == false) { + if (!"RAW".equals(spec.getPremasterSecret().getFormat())) { throw new InvalidAlgorithmParameterException( "Key format must be RAW"); } @@ -191,6 +194,22 @@ public byte[] getEncoded() { return key.clone(); } - } + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + if ((key == null) || (key.length == 0)) { + throw new InvalidObjectException("TlsMasterSecretKey is null"); + } + key = key.clone(); + } + } } diff --git a/src/java.base/share/classes/java/io/ByteArrayInputStream.java b/src/java.base/share/classes/java/io/ByteArrayInputStream.java index 08a3ec982d1d9..e3e755361b6b6 100644 --- a/src/java.base/share/classes/java/io/ByteArrayInputStream.java +++ b/src/java.base/share/classes/java/io/ByteArrayInputStream.java @@ -44,6 +44,7 @@ * @since 1.0 */ public class ByteArrayInputStream extends InputStream { + private static final int MAX_TRANSFER_SIZE = 128*1024; /** * An array of bytes that was provided @@ -205,8 +206,16 @@ public int readNBytes(byte[] b, int off, int len) { @Override public synchronized long transferTo(OutputStream out) throws IOException { int len = count - pos; - out.write(buf, pos, len); - pos = count; + if (len > 0) { + int nwritten = 0; + while (nwritten < len) { + int nbyte = Integer.min(len - nwritten, MAX_TRANSFER_SIZE); + out.write(buf, pos, nbyte); + pos += nbyte; + nwritten += nbyte; + } + assert pos == count; + } return len; } diff --git a/src/java.base/share/classes/java/io/FileDescriptor.java b/src/java.base/share/classes/java/io/FileDescriptor.java index 6723877937cc6..c7e638a167504 100644 --- a/src/java.base/share/classes/java/io/FileDescriptor.java +++ b/src/java.base/share/classes/java/io/FileDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import jdk.internal.access.JavaIOFileDescriptorAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.Blocker; import jdk.internal.ref.PhantomCleanable; /** @@ -205,7 +206,17 @@ public boolean valid() { * buffers have been synchronized with physical media. * @since 1.1 */ - public native void sync() throws SyncFailedException; + public void sync() throws SyncFailedException { + long comp = Blocker.begin(); + try { + sync0(); + } finally { + Blocker.end(comp); + } + } + + /* fsync/equivalent this file descriptor */ + private native void sync0() throws SyncFailedException; /* This routine initializes JNI field offsets for the class */ private static native void initIDs(); diff --git a/src/java.base/share/classes/java/lang/Byte.java b/src/java.base/share/classes/java/lang/Byte.java index 74a42d98a4321..18502abf69c4d 100644 --- a/src/java.base/share/classes/java/lang/Byte.java +++ b/src/java.base/share/classes/java/lang/Byte.java @@ -27,6 +27,7 @@ import jdk.internal.misc.CDS; import jdk.internal.vm.annotation.IntrinsicCandidate; +import jdk.internal.vm.annotation.Stable; import java.lang.constant.Constable; import java.lang.constant.DynamicConstantDesc; @@ -105,9 +106,10 @@ public Optional> describeConstable() { return Optional.of(DynamicConstantDesc.ofNamed(BSM_EXPLICIT_CAST, DEFAULT_NAME, CD_byte, intValue())); } - private static class ByteCache { + private static final class ByteCache { private ByteCache() {} + @Stable static final Byte[] cache; static Byte[] archivedCache; diff --git a/src/java.base/share/classes/java/lang/Character.java b/src/java.base/share/classes/java/lang/Character.java index 81548aae73dd0..d4399d2af6ab7 100644 --- a/src/java.base/share/classes/java/lang/Character.java +++ b/src/java.base/share/classes/java/lang/Character.java @@ -27,6 +27,7 @@ import jdk.internal.misc.CDS; import jdk.internal.vm.annotation.IntrinsicCandidate; +import jdk.internal.vm.annotation.Stable; import java.lang.constant.Constable; import java.lang.constant.DynamicConstantDesc; @@ -8956,9 +8957,10 @@ public Character(char value) { this.value = value; } - private static class CharacterCache { + private static final class CharacterCache { private CharacterCache(){} + @Stable static final Character[] cache; static Character[] archivedCache; diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 1e136cdde0cae..8c8bcb9226f4d 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -29,6 +29,7 @@ import jdk.internal.misc.VM; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; +import jdk.internal.vm.annotation.Stable; import java.lang.annotation.Native; import java.lang.constant.Constable; @@ -1005,9 +1006,11 @@ public static Integer valueOf(String s) throws NumberFormatException { * with new Integer object(s) after initialization. */ - private static class IntegerCache { + private static final class IntegerCache { static final int low = -128; static final int high; + + @Stable static final Integer[] cache; static Integer[] archivedCache; diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index 6db8f8a96c1d7..fb5e4cecca80b 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -36,6 +36,7 @@ import jdk.internal.misc.CDS; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; +import jdk.internal.vm.annotation.Stable; import static java.lang.String.COMPACT_STRINGS; import static java.lang.String.LATIN1; @@ -1156,9 +1157,10 @@ public static Long valueOf(String s) throws NumberFormatException return Long.valueOf(parseLong(s, 10)); } - private static class LongCache { + private static final class LongCache { private LongCache() {} + @Stable static final Long[] cache; static Long[] archivedCache; diff --git a/src/java.base/share/classes/java/lang/ScopedValue.java b/src/java.base/share/classes/java/lang/ScopedValue.java index 7fea72469e219..cd45818dff67e 100644 --- a/src/java.base/share/classes/java/lang/ScopedValue.java +++ b/src/java.base/share/classes/java/lang/ScopedValue.java @@ -787,7 +787,8 @@ private static Snapshot scopedValueBindings() { // Bindings can be in one of four states: // // 1: class Thread: this is a new Thread instance, and no - // scoped values have ever been bound in this Thread. + // scoped values have ever been bound in this Thread, and neither + // have any scoped value bindings been inherited from a parent. // 2: EmptySnapshot.SINGLETON: This is effectively an empty binding. // 3: A Snapshot instance: this contains one or more scoped value // bindings. @@ -798,18 +799,18 @@ private static Snapshot scopedValueBindings() { Object bindings = Thread.scopedValueBindings(); if (bindings == NEW_THREAD_BINDINGS) { // This must be a new thread - return Snapshot.EMPTY_SNAPSHOT; + return Snapshot.EMPTY_SNAPSHOT; } if (bindings == null) { // Search the stack bindings = Thread.findScopedValueBindings(); - if (bindings == null) { - // Nothing on the stack. + if (bindings == NEW_THREAD_BINDINGS || bindings == null) { + // We've walked the stack without finding anything. bindings = Snapshot.EMPTY_SNAPSHOT; } + Thread.setScopedValueBindings(bindings); } assert (bindings != null); - Thread.setScopedValueBindings(bindings); return (Snapshot) bindings; } diff --git a/src/java.base/share/classes/java/lang/Short.java b/src/java.base/share/classes/java/lang/Short.java index fa93dcbccabd7..6a148d1edac00 100644 --- a/src/java.base/share/classes/java/lang/Short.java +++ b/src/java.base/share/classes/java/lang/Short.java @@ -27,6 +27,7 @@ import jdk.internal.misc.CDS; import jdk.internal.vm.annotation.IntrinsicCandidate; +import jdk.internal.vm.annotation.Stable; import java.lang.constant.Constable; import java.lang.constant.DynamicConstantDesc; @@ -231,9 +232,10 @@ public Optional> describeConstable() { return Optional.of(DynamicConstantDesc.ofNamed(BSM_EXPLICIT_CAST, DEFAULT_NAME, CD_short, intValue())); } - private static class ShortCache { + private static final class ShortCache { private ShortCache() {} + @Stable static final Short[] cache; static Short[] archivedCache; diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 5c234d4dfacac..9b19d7e2ac132 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -2156,6 +2156,10 @@ public boolean regionMatches(int toffset, String other, int ooffset, int len) { (ooffset > (long)other.length() - len)) { return false; } + // Any strings match if len <= 0 + if (len <= 0) { + return true; + } byte[] tv = value; byte[] ov = other.value; byte coder = coder(); diff --git a/src/java.base/share/classes/java/lang/StringBuffer.java b/src/java.base/share/classes/java/lang/StringBuffer.java index ec7ecb5d2451f..d77462f0c706f 100644 --- a/src/java.base/share/classes/java/lang/StringBuffer.java +++ b/src/java.base/share/classes/java/lang/StringBuffer.java @@ -715,6 +715,7 @@ public synchronized StringBuffer reverse() { */ @Override public synchronized StringBuffer repeat(int codePoint, int count) { + toStringCache = null; super.repeat(codePoint, count); return this; } @@ -726,6 +727,7 @@ public synchronized StringBuffer repeat(int codePoint, int count) { */ @Override public synchronized StringBuffer repeat(CharSequence cs, int count) { + toStringCache = null; super.repeat(cs, count); return this; } diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 9d9dbf886e6b3..53c4ed4ddda2d 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -68,6 +68,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; +import jdk.internal.logger.LoggerFinderLoader.TemporaryLoggerFinder; import jdk.internal.misc.CarrierThreadLocal; import jdk.internal.misc.Unsafe; import jdk.internal.util.StaticProperty; @@ -1766,13 +1767,16 @@ static LoggerFinder accessProvider() { // We do not need to synchronize: LoggerFinderLoader will // always return the same instance, so if we don't have it, // just fetch it again. - if (service == null) { + LoggerFinder finder = service; + if (finder == null) { PrivilegedAction pa = () -> LoggerFinderLoader.getLoggerFinder(); - service = AccessController.doPrivileged(pa, null, + finder = AccessController.doPrivileged(pa, null, LOGGERFINDER_PERMISSION); + if (finder instanceof TemporaryLoggerFinder) return finder; + service = finder; } - return service; + return finder; } } @@ -2666,7 +2670,7 @@ public StackWalker newStackWalkerInstance(Set options, } public String getLoaderNameID(ClassLoader loader) { - return loader.nameAndId(); + return loader != null ? loader.nameAndId() : "null"; } }); } diff --git a/src/java.base/share/classes/java/lang/Thread.java b/src/java.base/share/classes/java/lang/Thread.java index 97a7d2df1b640..4ff54446a2393 100644 --- a/src/java.base/share/classes/java/lang/Thread.java +++ b/src/java.base/share/classes/java/lang/Thread.java @@ -1591,7 +1591,7 @@ public void run() { */ @Hidden @ForceInline - private void runWith(Object bindings, Runnable op) { + final void runWith(Object bindings, Runnable op) { ensureMaterializedForStackWalk(bindings); op.run(); Reference.reachabilityFence(bindings); diff --git a/src/java.base/share/classes/java/lang/ThreadBuilders.java b/src/java.base/share/classes/java/lang/ThreadBuilders.java index c75548d2c3688..37ca9b8e922e9 100644 --- a/src/java.base/share/classes/java/lang/ThreadBuilders.java +++ b/src/java.base/share/classes/java/lang/ThreadBuilders.java @@ -433,7 +433,8 @@ public void run() { // run is specified to do nothing when Thread is a virtual thread if (Thread.currentThread() == this && !runInvoked) { runInvoked = true; - task.run(); + Object bindings = Thread.scopedValueBindings(); + runWith(bindings, task); } } diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index 746f93cdfac05..37d092e20118b 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -24,7 +24,6 @@ */ package java.lang; -import java.lang.ref.Reference; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Locale; @@ -54,7 +53,6 @@ import jdk.internal.vm.ThreadContainer; import jdk.internal.vm.ThreadContainers; import jdk.internal.vm.annotation.ChangesCurrentThread; -import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.Hidden; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.JvmtiMountTransition; @@ -306,7 +304,7 @@ private void run(Runnable task) { event.commit(); } - Object bindings = scopedValueBindings(); + Object bindings = Thread.scopedValueBindings(); try { runWith(bindings, task); } catch (Throwable exc) { @@ -334,14 +332,6 @@ private void run(Runnable task) { } } - @Hidden - @ForceInline - private void runWith(Object bindings, Runnable op) { - ensureMaterializedForStackWalk(bindings); - op.run(); - Reference.reachabilityFence(bindings); - } - /** * Mounts this virtual thread onto the current platform thread. On * return, the current thread is the virtual thread. @@ -640,10 +630,8 @@ void parkNanos(long nanos) { // park on carrier thread for remaining time when pinned if (!yielded) { - long deadline = startTime + nanos; - if (deadline < 0L) - deadline = Long.MAX_VALUE; - parkOnCarrierThread(true, deadline - System.nanoTime()); + long remainingNanos = nanos - (System.nanoTime() - startTime); + parkOnCarrierThread(true, remainingNanos); } } } @@ -874,13 +862,14 @@ public boolean isInterrupted() { @Override boolean getAndClearInterrupt() { assert Thread.currentThread() == this; - synchronized (interruptLock) { - boolean oldValue = interrupted; - if (oldValue) + boolean oldValue = interrupted; + if (oldValue) { + synchronized (interruptLock) { interrupted = false; - carrierThread.clearInterrupt(); - return oldValue; + carrierThread.clearInterrupt(); + } } + return oldValue; } @Override diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java index 3dfd9c061bfd6..edcecce37e05d 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -1719,7 +1719,8 @@ MethodHandle setVarargs(MemberName member) throws IllegalAccessException { try { return this.withVarargs(true); } catch (IllegalArgumentException ex) { - throw member.makeAccessException("cannot make variable arity", null); + throw new IllegalAccessException("cannot make variable arity: " + member + + " does not have a trailing array parameter"); } } diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index 4743b00997030..6810fa6222d1a 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -394,9 +394,13 @@ private static boolean enumEqCheck(Object value, EnumDesc label, MethodHandle Object resolved; try { + if (!(value instanceof Enum enumValue)) { + return false; + } + Class clazz = label.constantType().resolveConstantDesc(lookup); - if (value.getClass() != clazz) { + if (enumValue.getDeclaringClass() != clazz) { return false; } diff --git a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template index f7f1d33228d66..e8551bd78c6f7 100644 --- a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template @@ -75,31 +75,15 @@ class Direct$Type$Buffer$RW$$BO$ #if[byte] - private static class Deallocator - implements Runnable - { - - private long address; - private long size; - private int capacity; - - private Deallocator(long address, long size, int capacity) { - assert (address != 0); - this.address = address; - this.size = size; - this.capacity = capacity; + private record Deallocator(long address, long size, int capacity) implements Runnable { + private Deallocator { + assert address != 0; } public void run() { - if (address == 0) { - // Paranoia - return; - } UNSAFE.freeMemory(address); - address = 0; Bits.unreserveMemory(size, capacity); } - } private final Cleaner cleaner; diff --git a/src/java.base/share/classes/java/nio/MappedByteBuffer.java b/src/java.base/share/classes/java/nio/MappedByteBuffer.java index be7a7988ec3f5..8b51d602f28aa 100644 --- a/src/java.base/share/classes/java/nio/MappedByteBuffer.java +++ b/src/java.base/share/classes/java/nio/MappedByteBuffer.java @@ -116,28 +116,33 @@ public abstract sealed class MappedByteBuffer } UnmapperProxy unmapper() { - return fd != null ? - new UnmapperProxy() { - @Override - public long address() { - return address; - } - - @Override - public FileDescriptor fileDescriptor() { - return fd; - } - - @Override - public boolean isSync() { - return isSync; - } - - @Override - public void unmap() { - Unsafe.getUnsafe().invokeCleaner(MappedByteBuffer.this); - } - } : null; + return fd == null + ? null + : new UnmapperProxy() { + + // Ensure safe publication as MappedByteBuffer.this.address is not final + private final long addr = address; + + @Override + public long address() { + return addr; + } + + @Override + public FileDescriptor fileDescriptor() { + return fd; + } + + @Override + public boolean isSync() { + return isSync; + } + + @Override + public void unmap() { + Unsafe.getUnsafe().invokeCleaner(MappedByteBuffer.this); + } + }; } /** diff --git a/src/java.base/share/classes/java/security/CodeSigner.java b/src/java.base/share/classes/java/security/CodeSigner.java index c1d0615ceaa11..1edb97f2a196d 100644 --- a/src/java.base/share/classes/java/security/CodeSigner.java +++ b/src/java.base/share/classes/java/security/CodeSigner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -156,9 +156,9 @@ public boolean equals(Object obj) { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("("); - sb.append("Signer: " + signerCertPath.getCertificates().get(0)); + sb.append("Signer: ").append(signerCertPath.getCertificates().get(0)); if (timestamp != null) { - sb.append("timestamp: " + timestamp); + sb.append("timestamp: ").append(timestamp); } sb.append(")"); return sb.toString(); @@ -174,8 +174,11 @@ public String toString() { */ @java.io.Serial private void readObject(ObjectInputStream ois) - throws IOException, ClassNotFoundException { - ois.defaultReadObject(); - myhash = -1; + throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + if (signerCertPath == null) { + throw new InvalidObjectException("signerCertPath is null"); + } + myhash = -1; } } diff --git a/src/java.base/share/classes/java/security/cert/CertPathHelperImpl.java b/src/java.base/share/classes/java/security/cert/CertPathHelperImpl.java index bd6545a735753..3da6cb3dd4f07 100644 --- a/src/java.base/share/classes/java/security/cert/CertPathHelperImpl.java +++ b/src/java.base/share/classes/java/security/cert/CertPathHelperImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,10 @@ package java.security.cert; -import java.util.*; +import java.util.Date; import sun.security.provider.certpath.CertPathHelper; -import sun.security.x509.GeneralNameInterface; - /** * Helper class that allows the Sun CertPath provider to access * implementation dependent APIs in CertPath framework. @@ -55,11 +53,6 @@ static synchronized void initialize() { } } - protected void implSetPathToNames(X509CertSelector sel, - Set names) { - sel.setPathToNamesInternal(names); - } - protected void implSetDateAndTime(X509CRLSelector sel, Date date, long skew) { sel.setDateAndTime(date, skew); } diff --git a/src/java.base/share/classes/java/security/cert/X509CertSelector.java b/src/java.base/share/classes/java/security/cert/X509CertSelector.java index c472d58b473f6..9b712411a615f 100644 --- a/src/java.base/share/classes/java/security/cert/X509CertSelector.java +++ b/src/java.base/share/classes/java/security/cert/X509CertSelector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,10 +87,6 @@ public class X509CertSelector implements CertSelector { private static final ObjectIdentifier ANY_EXTENDED_KEY_USAGE = ObjectIdentifier.of(KnownOIDs.anyExtendedKeyUsage); - static { - CertPathHelperImpl.initialize(); - } - private BigInteger serialNumber; private X500Principal issuer; private X500Principal subject; @@ -1127,14 +1123,6 @@ public void setPathToNames(Collection> names) throws IOException { } } - // called from CertPathHelper - void setPathToNamesInternal(Set names) { - // set names to non-null dummy value - // this breaks getPathToNames() - pathToNames = Collections.>emptySet(); - pathToGeneralNames = names; - } - /** * Adds a name to the pathToNames criterion. The {@code X509Certificate} * must not include name constraints that would prohibit building a diff --git a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java index cb6b33ddb7d62..a0d3176c76251 100644 --- a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java @@ -47,6 +47,7 @@ import java.util.Spliterator; import java.util.Spliterators; import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.ForkJoinWorkerThread; import java.util.function.Consumer; import java.util.function.Predicate; @@ -107,7 +108,11 @@ public class LinkedTransferQueue extends AbstractQueue * http://www.cs.rochester.edu/u/scott/papers/2009_Scherer_CACM_SSQ.pdf) * additionally arrange that threads enqueuing unmatched data also * block. Dual Transfer Queues support all of these modes, as - * dictated by callers. + * dictated by callers. All enqueue/dequeue operations can be + * handled by a single method (here, "xfer") with parameters + * indicating whether to act as some form of offer, put, poll, + * take, or transfer (each possibly with timeout), as described + * below. * * A FIFO dual queue may be implemented using a variation of the * Michael & Scott (M&S) lock-free queue algorithm @@ -126,44 +131,33 @@ public class LinkedTransferQueue extends AbstractQueue * * The M&S queue algorithm is known to be prone to scalability and * overhead limitations when maintaining (via CAS) these head and - * tail pointers. This has led to the development of - * contention-reducing variants such as elimination arrays (see - * Moir et al http://portal.acm.org/citation.cfm?id=1074013) and - * optimistic back pointers (see Ladan-Mozes & Shavit - * http://people.csail.mit.edu/edya/publications/OptimisticFIFOQueue-journal.pdf). - * However, the nature of dual queues enables a simpler tactic for - * improving M&S-style implementations when dual-ness is needed. + * tail pointers. To address these, dual queues with slack differ + * from plain M&S dual queues by virtue of only sometimes updating + * head or tail pointers when matching, appending, or even + * traversing nodes. * * In a dual queue, each node must atomically maintain its match - * status. While there are other possible variants, we implement - * this here as: for a data-mode node, matching entails CASing an - * "item" field from a non-null data value to null upon match, and - * vice-versa for request nodes, CASing from null to a data - * value. (Note that the linearization properties of this style of - * queue are easy to verify -- elements are made available by - * linking, and unavailable by matching.) Compared to plain M&S - * queues, this property of dual queues requires one additional - * successful atomic operation per enq/deq pair. But it also - * enables lower cost variants of queue maintenance mechanics. (A - * variation of this idea applies even for non-dual queues that - * support deletion of interior elements, such as - * j.u.c.ConcurrentLinkedQueue.) - * - * Once a node is matched, its match status can never again - * change. We may thus arrange that the linked list of them - * contain a prefix of zero or more matched nodes, followed by a - * suffix of zero or more unmatched nodes. (Note that we allow - * both the prefix and suffix to be zero length, which in turn - * means that we do not use a dummy header.) If we were not - * concerned with either time or space efficiency, we could - * correctly perform enqueue and dequeue operations by traversing - * from a pointer to the initial node; CASing the item of the - * first unmatched node on match and CASing the next field of the - * trailing node on appends. While this would be a terrible idea - * in itself, it does have the benefit of not requiring ANY atomic - * updates on head/tail fields. - * - * We introduce here an approach that lies between the extremes of + * status. Matching entails CASing an "item" field from a non-null + * data value to null upon match, and vice-versa for request + * nodes, CASing from null to a data value. (To reduce the need + * for re-reads, we use the compareAndExchange forms of CAS for + * pointer updates, that provide the current value to continue + * with on failure.) Note that the linearization properties of + * this style of queue are easy to verify -- elements are made + * available by linking, and unavailable by matching. Compared to + * plain M&S queues, this property of dual queues requires one + * additional successful atomic operation per enq/deq pair. But it + * also enables lower cost variants of queue maintenance + * mechanics. + * + * Once a node is matched, it is no longer live -- its match + * status can never again change. We may thus arrange that the + * linked list of them contain a prefix of zero or more dead + * nodes, followed by a suffix of zero or more live nodes. Note + * that we allow both the prefix and suffix to be zero length, + * which in turn means that we do not require a dummy header. + * + * We use here an approach that lies between the extremes of * never versus always updating queue (head and tail) pointers. * This offers a tradeoff between sometimes requiring extra * traversal steps to locate the first and/or last unmatched @@ -178,143 +172,43 @@ public class LinkedTransferQueue extends AbstractQueue * * The best value for this "slack" (the targeted maximum distance * between the value of "head" and the first unmatched node, and - * similarly for "tail") is an empirical matter. We have found - * that using very small constants in the range of 1-3 work best - * over a range of platforms. Larger values introduce increasing - * costs of cache misses and risks of long traversal chains, while - * smaller values increase CAS contention and overhead. - * - * Dual queues with slack differ from plain M&S dual queues by - * virtue of only sometimes updating head or tail pointers when - * matching, appending, or even traversing nodes; in order to - * maintain a targeted slack. The idea of "sometimes" may be - * operationalized in several ways. The simplest is to use a - * per-operation counter incremented on each traversal step, and - * to try (via CAS) to update the associated queue pointer - * whenever the count exceeds a threshold. Another, that requires - * more overhead, is to use random number generators to update - * with a given probability per traversal step. - * - * In any strategy along these lines, because CASes updating - * fields may fail, the actual slack may exceed targeted slack. - * However, they may be retried at any time to maintain targets. - * Even when using very small slack values, this approach works - * well for dual queues because it allows all operations up to the - * point of matching or appending an item (hence potentially - * allowing progress by another thread) to be read-only, thus not - * introducing any further contention. As described below, we - * implement this by performing slack maintenance retries only - * after these points. - * - * As an accompaniment to such techniques, traversal overhead can - * be further reduced without increasing contention of head - * pointer updates: Threads may sometimes shortcut the "next" link - * path from the current "head" node to be closer to the currently - * known first unmatched node, and similarly for tail. Again, this - * may be triggered with using thresholds or randomization. + * similarly for "tail") is an empirical matter. Larger values + * introduce increasing costs of cache misses and risks of long + * traversal chains and out-of-order updates, while smaller values + * increase CAS contention and overhead. Using the smallest + * non-zero value of one is both simple and empirically a good + * choice in most applicatkions. The slack value is hard-wired: a + * path greater than one is usually implemented by checking + * equality of traversal pointers. Because CASes updating fields + * attempting to do so may stall, the writes may appear out of + * order (an older CAS from the same head or tail may execute + * after a newer one), the actual slack may exceed targeted + * slack. To reduce impact, other threads may help update by + * unsplicing dead nodes while traversing. * * These ideas must be further extended to avoid unbounded amounts * of costly-to-reclaim garbage caused by the sequential "next" * links of nodes starting at old forgotten head nodes: As first * described in detail by Boehm - * (http://portal.acm.org/citation.cfm?doid=503272.503282), if a GC - * delays noticing that any arbitrarily old node has become + * (http://portal.acm.org/citation.cfm?doid=503272.503282), if a + * GC delays noticing that any arbitrarily old node has become * garbage, all newer dead nodes will also be unreclaimed. * (Similar issues arise in non-GC environments.) To cope with - * this in our implementation, upon CASing to advance the head - * pointer, we set the "next" link of the previous head to point - * only to itself; thus limiting the length of chains of dead nodes. - * (We also take similar care to wipe out possibly garbage - * retaining values held in other Node fields.) However, doing so - * adds some further complexity to traversal: If any "next" - * pointer links to itself, it indicates that the current thread - * has lagged behind a head-update, and so the traversal must - * continue from the "head". Traversals trying to find the - * current tail starting from "tail" may also encounter - * self-links, in which case they also continue at "head". - * - * It is tempting in slack-based scheme to not even use CAS for - * updates (similarly to Ladan-Mozes & Shavit). However, this - * cannot be done for head updates under the above link-forgetting - * mechanics because an update may leave head at a detached node. - * And while direct writes are possible for tail updates, they - * increase the risk of long retraversals, and hence long garbage - * chains, which can be much more costly than is worthwhile - * considering that the cost difference of performing a CAS vs - * write is smaller when they are not triggered on each operation - * (especially considering that writes and CASes equally require - * additional GC bookkeeping ("write barriers") that are sometimes - * more costly than the writes themselves because of contention). - * - * *** Overview of implementation *** - * - * We use a threshold-based approach to updates, with a slack - * threshold of two -- that is, we update head/tail when the - * current pointer appears to be two or more steps away from the - * first/last node. The slack value is hard-wired: a path greater - * than one is naturally implemented by checking equality of - * traversal pointers except when the list has only one element, - * in which case we keep slack threshold at one. Avoiding tracking - * explicit counts across method calls slightly simplifies an - * already-messy implementation. Using randomization would - * probably work better if there were a low-quality dirt-cheap - * per-thread one available, but even ThreadLocalRandom is too - * heavy for these purposes. - * - * With such a small slack threshold value, it is not worthwhile - * to augment this with path short-circuiting (i.e., unsplicing - * interior nodes) except in the case of cancellation/removal (see - * below). - * - * All enqueue/dequeue operations are handled by the single method - * "xfer" with parameters indicating whether to act as some form - * of offer, put, poll, take, or transfer (each possibly with - * timeout). The relative complexity of using one monolithic - * method outweighs the code bulk and maintenance problems of - * using separate methods for each case. - * - * Operation consists of up to two phases. The first is implemented - * in method xfer, the second in method awaitMatch. - * - * 1. Traverse until matching or appending (method xfer) - * - * Conceptually, we simply traverse all nodes starting from head. - * If we encounter an unmatched node of opposite mode, we match - * it and return, also updating head (by at least 2 hops) to - * one past the matched node (or the node itself if it's the - * pinned trailing node). Traversals also check for the - * possibility of falling off-list, in which case they restart. - * - * If the trailing node of the list is reached, a match is not - * possible. If this call was untimed poll or tryTransfer - * (argument "how" is NOW), return empty-handed immediately. - * Else a new node is CAS-appended. On successful append, if - * this call was ASYNC (e.g. offer), an element was - * successfully added to the end of the queue and we return. - * - * Of course, this naive traversal is O(n) when no match is - * possible. We optimize the traversal by maintaining a tail - * pointer, which is expected to be "near" the end of the list. - * It is only safe to fast-forward to tail (in the presence of - * arbitrary concurrent changes) if it is pointing to a node of - * the same mode, even if it is dead (in this case no preceding - * node could still be matchable by this traversal). If we - * need to restart due to falling off-list, we can again - * fast-forward to tail, but only if it has changed since the - * last traversal (else we might loop forever). If tail cannot - * be used, traversal starts at head (but in this case we - * expect to be able to match near head). As with head, we - * CAS-advance the tail pointer by at least two hops. - * - * 2. Await match or cancellation (method awaitMatch) - * - * Wait for another thread to match node; instead cancelling if - * the current thread was interrupted or the wait timed out. To - * improve performance in common single-source / single-sink - * usages when there are more tasks that cores, an initial - * Thread.yield is tried when there is apparently only one - * waiter. In other cases, waiters may help with some - * bookkeeping, then park/unpark. + * this in our implementation, upon advancing the head pointer, we + * set the "next" link of the previous head to point only to + * itself; thus limiting the length of chains of dead nodes. (We + * also take similar care to wipe out possibly garbage retaining + * values held in other node fields.) This is easy to accommodate + * in the primary xfer method, but adds a lot of complexity to + * Collection operations including traversal; mainly because if + * any "next" pointer links to itself, the current thread has + * lagged behind a head-update, and so must restart. + * + * *** Blocking *** + * + * The DualNode class is shared with class SynchronousQueue. It + * houses method await, which is used for all blocking control, as + * described below in DualNode internal documentation. * * ** Unlinking removed interior nodes ** * @@ -330,15 +224,13 @@ public class LinkedTransferQueue extends AbstractQueue * unreachable in this way: (1) If s is the trailing node of list * (i.e., with null next), then it is pinned as the target node * for appends, so can only be removed later after other nodes are - * appended. (2) We cannot necessarily unlink s given a - * predecessor node that is matched (including the case of being - * cancelled): the predecessor may already be unspliced, in which - * case some previous reachable node may still point to s. - * (For further explanation see Herlihy & Shavit "The Art of - * Multiprocessor Programming" chapter 9). Although, in both - * cases, we can rule out the need for further action if either s - * or its predecessor are (or can be made to be) at, or fall off - * from, the head of list. + * appended. (2) Unless we know it is already off-list, we cannot + * necessarily unlink s given a predecessor node that is matched + * (including the case of being cancelled): the predecessor may + * already be unspliced, in which case some previous reachable + * node may still point to s. (For further explanation see + * Herlihy & Shavit "The Art of Multiprocessor Programming" + * chapter 9). * * Without taking these into account, it would be possible for an * unbounded number of supposedly removed nodes to remain reachable. @@ -350,337 +242,472 @@ public class LinkedTransferQueue extends AbstractQueue * * When these cases arise, rather than always retraversing the * entire list to find an actual predecessor to unlink (which - * won't help for case (1) anyway), we record the need to sweep the - * next time any thread would otherwise block in awaitMatch. Also, - * because traversal operations on the linked list of nodes are a - * natural opportunity to sweep dead nodes, we generally do so, - * including all the operations that might remove elements as they - * traverse, such as removeIf and Iterator.remove. This largely - * eliminates long chains of dead interior nodes, except from - * cancelled or timed out blocking operations. + * won't help for case (1) anyway), we record a conservative + * estimate of possible unsplice failures (in "sweepVotes"). + * We trigger a full sweep when the estimate exceeds a threshold + * ("SWEEP_THRESHOLD") indicating the maximum number of estimated + * removal failures to tolerate before sweeping through, unlinking + * cancelled nodes that were not unlinked upon initial removal. + * We perform sweeps by the thread hitting threshold (rather than + * background threads or by spreading work to other threads) + * because in the main contexts in which removal occurs, the + * caller is timed-out or cancelled, which are not time-critical + * enough to warrant the overhead that alternatives would impose + * on other threads. + * + * Because the sweepVotes estimate is conservative, and because + * nodes become unlinked "naturally" as they fall off the head of + * the queue, and because we allow votes to accumulate even while + * sweeps are in progress, there are typically significantly fewer + * such nodes than estimated. * * Note that we cannot self-link unlinked interior nodes during * sweeps. However, the associated garbage chains terminate when * some successor ultimately falls off the head of the list and is * self-linked. + * + * *** Revision notes *** + * + * This version differs from previous releases as follows: + * + * * Class DualNode replaces Qnode, with fields and methods + * that apply to any match-based dual data structure, and now + * usable in other j.u.c classes. in particular, SynchronousQueue. + * * Blocking control (in class DualNode) accommodates + * VirtualThreads and (perhaps virtualized) uniprocessors. + * * All fields of this class (LinkedTransferQueue) are + * default-initializable (to null), allowing further extension + * (in particular, SynchronousQueue.Transferer) + * * Head and tail fields are lazily initialized rather than set + * to a dummy node, while also reducing retries under heavy + * contention and misorderings, and relaxing some accesses, + * requiring accommodation in many places (as well as + * adjustments in WhiteBox tests). */ /** - * The number of nanoseconds for which it is faster to spin - * rather than to use timed park. A rough estimate suffices. - * Using a power of two minus one simplifies some comparisons. - */ - static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1023L; - - /** - * The maximum number of estimated removal failures (sweepVotes) - * to tolerate before sweeping through the queue unlinking - * cancelled nodes that were not unlinked upon initial - * removal. See above for explanation. The value must be at least - * two to avoid useless sweeps when removing trailing nodes. - */ - static final int SWEEP_THRESHOLD = 32; - - /** - * Queue nodes. Uses Object, not E, for items to allow forgetting - * them after use. Writes that are intrinsically ordered wrt - * other accesses or CASes use simple relaxed forms. + * Node for linked dual data structures. Uses type Object, not E, + * for items to allow cancellation and forgetting after use. Only + * field "item" is declared volatile (with bypasses for + * pre-publication and post-match writes), although field "next" + * is also CAS-able. Other accesses are constrained by context + * (including dependent chains of next's headed by a volatile + * read). + * + * This class also arranges blocking while awaiting matches. + * Control of blocking (and thread scheduling in general) for + * possibly-synchronous queues (and channels etc constructed + * from them) must straddle two extremes: If there are too few + * underlying cores for a fulfilling party to continue, then + * the caller must park to cause a context switch. On the + * other hand, if the queue is busy with approximately the + * same number of independent producers and consumers, then + * that context switch may cause an order-of-magnitude + * slowdown. Many cases are somewhere in-between, in which + * case threads should try spinning and then give up and + * block. We deal with this as follows: + * + * 1. Callers to method await indicate eligibility for + * spinning when the node is either the only waiting node, or + * the next matchable node is still spinning. Otherwise, the + * caller may block (almost) immediately. + * + * 2. Even if eligible to spin, a caller blocks anyway in two + * cases where it is normally best: If the thread isVirtual, + * or the system is a uniprocessor. Uniprocessor status can + * vary over time (due to virtualization at other system + * levels), but checking Runtime availableProcessors can be + * slow and may itself acquire blocking locks, so we only + * occasionally (using ThreadLocalRandom) update when an + * otherwise-eligible spin elapses. + * + * 3. When enabled, spins should be long enough to cover + * bookeeping overhead of almost-immediate fulfillments, but + * much less than the expected time of a (non-virtual) + * park/unpark context switch. The optimal value is + * unknowable, in part because the relative costs of + * Thread.onSpinWait versus park/unpark vary across platforms. + * The current value is an empirical compromise across tested + * platforms. + * + * 4. When using timed waits, callers spin instead of invoking + * timed park if the remaining time is less than the likely cost + * of park/unpark. This also avoids re-parks when timed park + * returns just barely too soon. As is the case in most j.u.c + * blocking support, untimed waits use ManagedBlockers when + * callers are ForkJoin threads, but timed waits use plain + * parkNanos, under the rationale that known-to-be transient + * blocking doesn't require compensation. (This decision should be + * revisited here and elsewhere to deal with very long timeouts.) + * + * 5. Park/unpark signalling otherwise relies on a Dekker-like + * scheme in which the caller advertises the need to unpark by + * setting its waiter field, followed by a full fence and recheck + * before actually parking. An explicit fence in used here rather + * than unnecessarily requiring volatile accesses elsewhere. This + * fence also separates accesses to field isUniprocessor. + * + * 6. To make the above work, callers must precheck that + * timeouts are not already elapsed, and that interruptible + * operations were not already interrupted on call to the + * corresponding queue operation. Cancellation on timeout or + * interrupt otherwise proceeds by trying to fulfill with an + * impossible value (which is one reason that we use Object + * types here rather than typed fields). */ - static final class Node implements ForkJoinPool.ManagedBlocker { - final boolean isData; // false if this is a request node + static final class DualNode implements ForkJoinPool.ManagedBlocker { volatile Object item; // initially non-null if isData; CASed to match - volatile Node next; - volatile Thread waiter; // null when not waiting for a match + DualNode next; // accessed only in chains of volatile ops + Thread waiter; // access order constrained by context + final boolean isData; // false if this is a request node - /** - * Constructs a data node holding item if item is non-null, - * else a request node. Uses relaxed write because item can - * only be seen after piggy-backing publication via CAS. - */ - Node(Object item) { - ITEM.set(this, item); - isData = (item != null); + DualNode(Object item, boolean isData) { + ITEM.set(this, item); // relaxed write before publication + this.isData = isData; } - /** Constructs a (matched data) dummy node. */ - Node() { - isData = true; + // Atomic updates + final Object cmpExItem(Object cmp, Object val) { // try to match + return ITEM.compareAndExchange(this, cmp, val); } - - final boolean casNext(Node cmp, Node val) { - // assert val != null; - return NEXT.compareAndSet(this, cmp, val); + final DualNode cmpExNext(DualNode cmp, DualNode val) { + return (DualNode)NEXT.compareAndExchange(this, cmp, val); } - final boolean casItem(Object cmp, Object val) { - // assert isData == (cmp != null); - // assert isData == (val == null); - // assert !(cmp instanceof Node); - return ITEM.compareAndSet(this, cmp, val); + /** Returns true if this node has been matched or cancelled */ + final boolean matched() { + return isData != (item != null); } /** - * Links node to itself to avoid garbage retention. Called - * only after CASing head field, so uses relaxed write. + * Relaxed write to replace reference to user data with + * self-link. Can be used only if not already null after + * match. */ - final void selfLink() { - // assert isMatched(); - NEXT.setRelease(this, this); + final void selfLinkItem() { + ITEM.set(this, this); } - final void appendRelaxed(Node next) { - // assert next != null; - // assert this.next == null; - NEXT.setOpaque(this, next); - } + /** The number of times to spin when eligible */ + private static final int SPINS = 1 << 7; /** - * Returns true if this node has been matched, including the - * case of artificial matches due to cancellation. + * The number of nanoseconds for which it is faster to spin + * rather than to use timed park. A rough estimate suffices. */ - final boolean isMatched() { - return isData == (item == null); - } + private static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1L << 10; - /** Tries to CAS-match this node; if successful, wakes waiter. */ - final boolean tryMatch(Object cmp, Object val) { - if (casItem(cmp, val)) { - LockSupport.unpark(waiter); - return true; - } - return false; - } + /** + * True if system is a uniprocessor, occasionally rechecked. + */ + private static boolean isUniprocessor = + (Runtime.getRuntime().availableProcessors() == 1); /** - * Returns true if a node with the given mode cannot be - * appended to this node because this node is unmatched and - * has opposite data mode. + * Refresh rate (probablility) for updating isUniprocessor + * field, to reduce the likeihood that multiple calls to await + * will contend invoking Runtime.availableProcessors. Must be + * a power of two minus one. */ - final boolean cannotPrecede(boolean haveData) { - boolean d = isData; - return d != haveData && d != (item == null); + private static final int UNIPROCESSOR_REFRESH_RATE = (1 << 5) - 1; + + /** + * Possibly blocks until matched or caller gives up. + * + * @param e the comparison value for checking match + * @param ns timeout, or Long.MAX_VALUE if untimed + * @param blocker the LockSupport.setCurrentBlocker argument + * @param spin true if should spin when enabled + * @return matched item, or e if unmatched on interrupt or timeout + */ + final Object await(Object e, long ns, Object blocker, boolean spin) { + Object m; // the match or e if none + boolean timed = (ns != Long.MAX_VALUE); + long deadline = (timed) ? System.nanoTime() + ns : 0L; + boolean upc = isUniprocessor; // don't spin but later recheck + Thread w = Thread.currentThread(); + if (w.isVirtual()) // don't spin + spin = false; + int spins = (spin & !upc) ? SPINS : 0; // negative when may park + while ((m = item) == e) { + if (spins >= 0) { + if (--spins >= 0) + Thread.onSpinWait(); + else { // prepare to park + if (spin) // occasionally recheck + checkForUniprocessor(upc); + LockSupport.setCurrentBlocker(blocker); + waiter = w; // ensure ordering + VarHandle.fullFence(); + } + } else if (w.isInterrupted() || + (timed && // try to cancel with impossible match + ((ns = deadline - System.nanoTime()) <= 0L))) { + m = cmpExItem(e, (e == null) ? this : null); + break; + } else if (timed) { + if (ns < SPIN_FOR_TIMEOUT_THRESHOLD) + Thread.onSpinWait(); + else + LockSupport.parkNanos(ns); + } else if (w instanceof ForkJoinWorkerThread) { + try { + ForkJoinPool.managedBlock(this); + } catch (InterruptedException cannotHappen) { } + } else + LockSupport.park(); + } + if (spins < 0) { + LockSupport.setCurrentBlocker(null); + waiter = null; + } + return m; } - public final boolean isReleasable() { - return (isData == (item == null)) || - Thread.currentThread().isInterrupted(); + /** Occasionally updates isUniprocessor field */ + private void checkForUniprocessor(boolean prev) { + int r = ThreadLocalRandom.nextSecondarySeed(); + if ((r & UNIPROCESSOR_REFRESH_RATE) == 0) { + boolean u = (Runtime.getRuntime().availableProcessors() == 1); + if (u != prev) + isUniprocessor = u; + } } + // ManagedBlocker support + public final boolean isReleasable() { + return (matched() || Thread.currentThread().isInterrupted()); + } public final boolean block() { while (!isReleasable()) LockSupport.park(); return true; } - private static final long serialVersionUID = -3375979862319811754L; + // VarHandle mechanics + static final VarHandle ITEM; + static final VarHandle NEXT; + static { + try { + Class tn = DualNode.class; + MethodHandles.Lookup l = MethodHandles.lookup(); + ITEM = l.findVarHandle(tn, "item", Object.class); + NEXT = l.findVarHandle(tn, "next", tn); + } catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } + // Reduce the risk of rare disastrous classloading in first call to + // LockSupport.park: https://bugs.openjdk.org/browse/JDK-8074773 + Class ensureLoaded = LockSupport.class; + } } /** - * A node from which the first live (non-matched) node (if any) - * can be reached in O(1) time. + * Unless empty (in which case possibly null), a node from which + * all live nodes are reachable. * Invariants: - * - all live nodes are reachable from head via .next - * - head != null - * - (tmp = head).next != tmp || tmp != head + * - head is never self-linked * Non-invariants: * - head may or may not be live - * - it is permitted for tail to lag behind head, that is, for tail - * to not be reachable from head! + * + * This field is used by subclass SynchronousQueue.Transferer to + * record the top of a Lifo stack, with tail always null, but + * otherwise maintaining the same properties. */ - transient volatile Node head; + transient volatile DualNode head; /** - * A node from which the last node on list (that is, the unique - * node with node.next == null) can be reached in O(1) time. - * Invariants: - * - the last node is always reachable from tail via .next - * - tail != null + * Unless null, a node from which the last node on list (that is, + * the unique node with node.next == null), if one exists, can be + * reached. * Non-invariants: * - tail may or may not be live - * - it is permitted for tail to lag behind head, that is, for tail - * to not be reachable from head! - * - tail.next may or may not be self-linked. + * - tail may be the same as head + * - tail may or may not be self-linked. + * - tail may lag behind head, so need not be reachable from head */ - private transient volatile Node tail; + transient volatile DualNode tail; /** The number of apparent failures to unsplice cancelled nodes */ - private transient volatile boolean needSweep; + transient volatile int sweepVotes; - private boolean casTail(Node cmp, Node val) { - // assert cmp != null; - // assert val != null; - return TAIL.compareAndSet(this, cmp, val); - } + // Atomic updates - private boolean casHead(Node cmp, Node val) { - return HEAD.compareAndSet(this, cmp, val); + final DualNode cmpExTail(DualNode cmp, DualNode val) { + return (DualNode)TAIL.compareAndExchange(this, cmp, val); + } + final DualNode cmpExHead(DualNode cmp, DualNode val) { + return (DualNode)HEAD.compareAndExchange(this, cmp, val); } /** - * Tries to CAS pred.next (or head, if pred is null) from c to p. - * Caller must ensure that we're not unlinking the trailing node. + * The maximum number of estimated removal failures (sweepVotes) + * to tolerate before sweeping through the queue unlinking + * dead nodes that were initially pinned. Must be a power of + * two minus one, at least 3. */ - private boolean tryCasSuccessor(Node pred, Node c, Node p) { - // assert p != null; - // assert c.isData != (c.item != null); - // assert c != p; - if (pred != null) - return pred.casNext(c, p); - if (casHead(c, p)) { - c.selfLink(); - return true; - } - return false; + static final int SWEEP_THRESHOLD = (1 << 4) - 1; + + /** + * Adds a sweepVote and returns true if triggered threshold. + */ + final boolean sweepNow() { + return (SWEEP_THRESHOLD == + ((int)SWEEPVOTES.getAndAdd(this, 1) & (SWEEP_THRESHOLD))); } /** - * Collapses dead (matched) nodes between pred and q. - * @param pred the last known live node, or null if none - * @param c the first dead node - * @param p the last dead node - * @param q p.next: the next live node, or null if at end - * @return pred if pred still alive and CAS succeeded; else p + * Implements all queuing methods. Loops, trying: + * + * * If not initialized, try to add new node (unless immediate) and exit + * * If tail has same mode, start traversing at tail for a likely + * append, else at head for a likely match + * * Traverse over dead or wrong-mode nodes until finding a spot + * to match/append, or falling off the list because of self-links. + * * On success, update head or tail if slacked, and possibly wait, + * depending on ns argument + * + * @param e the item or null for take + * @param ns timeout or negative if async, 0 if immediate, + * Long.MAX_VALUE if untimed + * @return an item if matched, else e */ - private Node skipDeadNodes(Node pred, Node c, Node p, Node q) { - // assert pred != c; - // assert p != q; - // assert c.isMatched(); - // assert p.isMatched(); - if (q == null) { - // Never unlink trailing node. - if (c == p) return pred; - q = p; + final Object xfer(Object e, long ns) { + boolean haveData = (e != null); + Object m; // the match or e if none + DualNode s = null, p; // enqueued node and its predecessor + restart: for (DualNode prevp = null;;) { + DualNode h, t, q; + if ((h = head) == null && // initialize unless immediate + (ns == 0L || + (h = cmpExHead(null, s = new DualNode(e, haveData))) == null)) { + p = null; // no predecessor + break; // else lost init race + } + p = (t = tail) != null && t.isData == haveData && t != prevp ? t : h; + prevp = p; // avoid known self-linked tail path + do { + m = p.item; + q = p.next; + if (p.isData != haveData && haveData != (m != null) && + p.cmpExItem(m, e) == m) { + Thread w = p.waiter; // matched complementary node + if (p != h && h == cmpExHead(h, (q == null) ? p : q)) + h.next = h; // advance head; self-link old + LockSupport.unpark(w); + return m; + } else if (q == null) { + if (ns == 0L) // try to append unless immediate + break restart; + if (s == null) + s = new DualNode(e, haveData); + if ((q = p.cmpExNext(null, s)) == null) { + if (p != t) + cmpExTail(t, s); + break restart; + } + } + } while (p != (p = q)); // restart if self-linked } - return (tryCasSuccessor(pred, c, q) - && (pred == null || !pred.isMatched())) - ? pred : p; + if (s == null || ns <= 0L) + m = e; // don't wait + else if ((m = s.await(e, ns, this, // spin if at or near head + p == null || p.waiter == null)) == e) + unsplice(p, s); // cancelled + else if (m != null) + s.selfLinkItem(); + + return m; } + /* -------------- Removals -------------- */ + /** - * Collapses dead (matched) nodes from h (which was once head) to p. - * Caller ensures all nodes from h up to and including p are dead. + * Unlinks (now or later) the given (non-live) node with given + * predecessor. See above for rationale. + * + * @param pred if nonnull, a node that was at one time known to be the + * predecessor of s (else s may have been head) + * @param s the node to be unspliced */ - private void skipDeadNodesNearHead(Node h, Node p) { - // assert h != null; - // assert h != p; - // assert p.isMatched(); - for (;;) { - final Node q; - if ((q = p.next) == null) break; - else if (!q.isMatched()) { p = q; break; } - else if (p == (p = q)) return; + private void unsplice(DualNode pred, DualNode s) { + boolean seen = false; // try removing by collapsing head + for (DualNode h = head, p = h, f; p != null;) { + boolean matched; + if (p == s) + matched = seen = true; + else + matched = p.matched(); + if ((f = p.next) == p) + p = h = head; + else if (f != null && matched) + p = f; + else { + if (p != h && cmpExHead(h, p) == h) + h.next = h; // self-link + break; + } + } + DualNode sn; // try to unsplice if not pinned + if (!seen && + pred != null && pred.next == s && s != null && (sn = s.next) != s && + (sn == null || pred.cmpExNext(s, sn) != s || pred.matched()) && + sweepNow()) { // occasionally sweep if might not have been removed + for (DualNode p = head, f, n, u; + p != null && (f = p.next) != null && (n = f.next) != null;) { + p = (f == p ? head : // stale + !f.matched() ? f : // skip + f == (u = p.cmpExNext(f, n)) ? n : u); // unspliced + } } - if (casHead(h, p)) - h.selfLink(); } - /* Possible values for "how" argument in xfer method. */ + /** + * Tries to CAS pred.next (or head, if pred is null) from c to p. + * Caller must ensure that we're not unlinking the trailing node. + */ + final boolean tryCasSuccessor(DualNode pred, DualNode c, DualNode p) { + // assert p != null && c.matched() && c != p; + if (pred != null) + return pred.cmpExNext(c, p) == c; + else if (cmpExHead(c, p) != c) + return false; + if (c != null) + c.next = c; - private static final int NOW = 0; // for untimed poll, tryTransfer - private static final int ASYNC = 1; // for offer, put, add - private static final int SYNC = 2; // for transfer, take - private static final int TIMED = 3; // for timed poll, tryTransfer + return true; + } /** - * Implements all queuing methods. See above for explanation. - * - * @param e the item or null for take - * @param haveData true if this is a put, else a take - * @param how NOW, ASYNC, SYNC, or TIMED - * @param nanos timeout in nanosecs, used only if mode is TIMED - * @return an item if matched, else e - * @throws NullPointerException if haveData mode but e is null + * Collapses dead (matched) nodes between pred and q. + * @param pred the last known live node, or null if none + * @param c the first dead node + * @param p the last dead node + * @param q p.next: the next live node, or null if at end + * @return pred if pred still alive and CAS succeeded; else p */ - @SuppressWarnings("unchecked") - private E xfer(E e, boolean haveData, int how, long nanos) { - if (haveData && (e == null)) - throw new NullPointerException(); - - restart: for (Node s = null, t = null, h = null;;) { - for (Node p = (t != (t = tail) && t.isData == haveData) ? t - : (h = head);; ) { - final Node q; final Object item; - if (p.isData != haveData - && haveData == ((item = p.item) == null)) { - if (h == null) h = head; - if (p.tryMatch(item, e)) { - if (h != p) skipDeadNodesNearHead(h, p); - return (E) item; - } - } - if ((q = p.next) == null) { - if (how == NOW) return e; - if (s == null) s = new Node(e); - if (!p.casNext(null, s)) continue; - if (p != t) casTail(t, s); - if (how == ASYNC) return e; - return awaitMatch(s, p, e, (how == TIMED), nanos); - } - if (p == (p = q)) continue restart; - } + final DualNode skipDeadNodes(DualNode pred, DualNode c, + DualNode p, DualNode q) { + // assert pred != c && p != q; && c.matched() && p.matched(); + if (q == null) { // Never unlink trailing node. + if (c == p) + return pred; + q = p; } + return (tryCasSuccessor(pred, c, q) && (pred == null || !pred.matched())) + ? pred : p; } /** - * Possibly blocks until node s is matched or caller gives up. - * - * @param s the waiting node - * @param pred the predecessor of s, or null if unknown (the null - * case does not occur in any current calls but may in possible - * future extensions) - * @param e the comparison value for checking match - * @param timed if true, wait only until timeout elapses - * @param nanos timeout in nanosecs, used only if timed is true - * @return matched item, or e if unmatched on interrupt or timeout + * Tries to match the given object only if p is a data + * node. Signals waiter on success. */ - @SuppressWarnings("unchecked") - private E awaitMatch(Node s, Node pred, E e, boolean timed, long nanos) { - final boolean isData = s.isData; - final long deadline = timed ? System.nanoTime() + nanos : 0L; - final Thread w = Thread.currentThread(); - int stat = -1; // -1: may yield, +1: park, else 0 - Object item; - while ((item = s.item) == e) { - if (needSweep) // help clean - sweep(); - else if ((timed && nanos <= 0L) || w.isInterrupted()) { - if (s.casItem(e, (e == null) ? s : null)) { - unsplice(pred, s); // cancelled - return e; - } - } - else if (stat <= 0) { - if (pred != null && pred.next == s) { - if (stat < 0 && - (pred.isData != isData || pred.isMatched())) { - stat = 0; // yield once if first - Thread.yield(); - } - else { - stat = 1; - s.waiter = w; // enable unpark - } - } // else signal in progress - } - else if ((item = s.item) != e) - break; // recheck - else if (!timed) { - LockSupport.setCurrentBlocker(this); - try { - ForkJoinPool.managedBlock(s); - } catch (InterruptedException cannotHappen) { } - LockSupport.setCurrentBlocker(null); - } - else { - nanos = deadline - System.nanoTime(); - if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD) - LockSupport.parkNanos(this, nanos); - } + final boolean tryMatchData(DualNode p, Object x) { + if (p != null && p.isData && + x != null && p.cmpExItem(x, null) == x) { + LockSupport.unpark(p.waiter); + return true; } - if (stat == 1) - WAITER.set(s, null); - if (!isData) - ITEM.set(s, s); // self-link to avoid garbage - return (E) item; + return false; } /* -------------- Traversal methods -------------- */ @@ -690,40 +717,39 @@ else if (!timed) { * Callers must recheck if the returned node is unmatched * before using. */ - final Node firstDataNode() { - Node first = null; - restartFromHead: for (;;) { - Node h = head, p = h; - while (p != null) { - if (p.item != null) { - if (p.isData) { - first = p; - break; - } - } - else if (!p.isData) - break; - final Node q; - if ((q = p.next) == null) - break; - if (p == (p = q)) - continue restartFromHead; + final DualNode firstDataNode() { + for (DualNode h = head, p = h, q, u; p != null;) { + boolean isData = p.isData; + Object item = p.item; + if (isData && item != null) // is live data + return p; + else if (!isData && item == null) // is live request + break; + else if ((q = p.next) == null) // end of list + break; + else if (p == q) // self-link; restart + p = h = head; + else if (p == h) // traverse past header + p = q; + else if ((u = cmpExHead(h, q)) != h) + p = h = u; // lost update race + else { + h.next = h; // collapse; self-link + p = h = q; } - if (p != h && casHead(h, p)) - h.selfLink(); - return first; } + return null; } /** * Traverses and counts unmatched nodes of the given mode. * Used by methods size and getWaitingConsumerCount. */ - private int countOfMode(boolean data) { + final int countOfMode(boolean data) { restartFromHead: for (;;) { int count = 0; - for (Node p = head; p != null;) { - if (!p.isMatched()) { + for (DualNode p = head; p != null;) { + if (!p.matched()) { if (p.isData != data) return 0; if (++count == Integer.MAX_VALUE) @@ -741,7 +767,7 @@ public String toString() { restartFromHead: for (;;) { int charLength = 0; int size = 0; - for (Node p = head; p != null;) { + for (DualNode p = head; p != null;) { Object item = p.item; if (p.isData) { if (item != null) { @@ -770,7 +796,7 @@ private Object[] toArrayInternal(Object[] a) { Object[] x = a; restartFromHead: for (;;) { int size = 0; - for (Node p = head; p != null;) { + for (DualNode p = head; p != null;) { Object item = p.item; if (p.isData) { if (item != null) { @@ -863,27 +889,28 @@ public T[] toArray(T[] a) { * but O(n) in the worst case, when lastRet is concurrently deleted. */ final class Itr implements Iterator { - private Node nextNode; // next node to return item for - private E nextItem; // the corresponding item - private Node lastRet; // last returned node, to support remove - private Node ancestor; // Helps unlink lastRet on remove() + private DualNode nextNode; // next node to return item for + private E nextItem; // the corresponding item + private DualNode lastRet; // last returned node, to support remove + private DualNode ancestor; // Helps unlink lastRet on remove() /** * Moves to next node after pred, or first node if pred null. */ @SuppressWarnings("unchecked") - private void advance(Node pred) { - for (Node p = (pred == null) ? head : pred.next, c = p; + private void advance(DualNode pred) { + for (DualNode p = (pred == null) ? head : pred.next, c = p; p != null; ) { - final Object item; - if ((item = p.item) != null && p.isData) { + boolean isData = p.isData; + Object item = p.item; + if (isData && item != null) { nextNode = p; nextItem = (E) item; if (c != p) tryCasSuccessor(pred, c, p); return; } - else if (!p.isData && item == null) + else if (!isData && item == null) break; if (c != p && !tryCasSuccessor(pred, c, c = p)) { pred = p; @@ -907,7 +934,7 @@ public final boolean hasNext() { } public final E next() { - final Node p; + DualNode p; if ((p = nextNode) == null) throw new NoSuchElementException(); E e = nextItem; advance(lastRet = p); @@ -916,28 +943,26 @@ public final E next() { public void forEachRemaining(Consumer action) { Objects.requireNonNull(action); - Node q = null; - for (Node p; (p = nextNode) != null; advance(q = p)) + DualNode q = null; + for (DualNode p; (p = nextNode) != null; advance(q = p)) action.accept(nextItem); if (q != null) lastRet = q; } public final void remove() { - final Node lastRet = this.lastRet; + final DualNode lastRet = this.lastRet; if (lastRet == null) throw new IllegalStateException(); this.lastRet = null; if (lastRet.item == null) // already deleted? return; // Advance ancestor, collapsing intervening dead nodes - Node pred = ancestor; - for (Node p = (pred == null) ? head : pred.next, c = p, q; + DualNode pred = ancestor; + for (DualNode p = (pred == null) ? head : pred.next, c = p, q; p != null; ) { if (p == lastRet) { - final Object item; - if ((item = p.item) != null) - p.tryMatch(item, null); + tryMatchData(p, p.item); if ((q = p.next) == null) q = p; if (c != q) tryCasSuccessor(pred, c, q); ancestor = pred; @@ -962,20 +987,20 @@ else if (p == (p = p.next)) { // leave ancestor at original location to avoid overshoot; // better luck next time! - // assert lastRet.isMatched(); + // assert lastRet.matched(); } } /** A customized variant of Spliterators.IteratorSpliterator */ final class LTQSpliterator implements Spliterator { static final int MAX_BATCH = 1 << 25; // max batch array size; - Node current; // current node; null until initialized + DualNode current; // current node; null until initialized int batch; // batch size for splits boolean exhausted; // true when no more nodes LTQSpliterator() {} public Spliterator trySplit() { - Node p, q; + DualNode p, q; if ((p = current()) == null || (q = p.next) == null) return null; int i = 0, n = batch = Math.min(batch + 1, MAX_BATCH); @@ -1004,7 +1029,7 @@ public Spliterator trySplit() { public void forEachRemaining(Consumer action) { Objects.requireNonNull(action); - final Node p; + final DualNode p; if ((p = current()) != null) { current = null; exhausted = true; @@ -1015,12 +1040,12 @@ public void forEachRemaining(Consumer action) { @SuppressWarnings("unchecked") public boolean tryAdvance(Consumer action) { Objects.requireNonNull(action); - Node p; + DualNode p; if ((p = current()) != null) { E e = null; do { - final Object item = p.item; - final boolean isData = p.isData; + boolean isData = p.isData; + Object item = p.item; if (p == (p = p.next)) p = head; if (isData) { @@ -1041,13 +1066,13 @@ else if (item == null) return false; } - private void setCurrent(Node p) { + private void setCurrent(DualNode p) { if ((current = p) == null) exhausted = true; } - private Node current() { - Node p; + private DualNode current() { + DualNode p; if ((p = current) == null && !exhausted) setCurrent(p = firstDataNode()); return p; @@ -1082,76 +1107,10 @@ public Spliterator spliterator() { return new LTQSpliterator(); } - /* -------------- Removal methods -------------- */ - - /** - * Unsplices (now or later) the given deleted/cancelled node with - * the given predecessor. - * - * @param pred a node that was at one time known to be the - * predecessor of s - * @param s the node to be unspliced - */ - final void unsplice(Node pred, Node s) { - // assert pred != null; - // assert pred != s; - // assert s != null; - // assert s.isMatched(); - // assert (SWEEP_THRESHOLD & (SWEEP_THRESHOLD - 1)) == 0; - s.waiter = null; // disable signals - /* - * See above for rationale. Briefly: if pred still points to - * s, try to unlink s. If s cannot be unlinked, because it is - * trailing node or pred might be unlinked, and neither pred - * nor s are head or offlist, set needSweep; - */ - if (pred != null && pred.next == s) { - Node n = s.next; - if (n == null || - (n != s && pred.casNext(s, n) && pred.isMatched())) { - for (;;) { // check if at, or could be, head - Node h = head; - if (h == pred || h == s) - return; // at head or list empty - if (!h.isMatched()) - break; - Node hn = h.next; - if (hn == null) - return; // now empty - if (hn != h && casHead(h, hn)) - h.selfLink(); // advance head - } - if (pred.next != pred && s.next != s) - needSweep = true; - } - } - } - - /** - * Unlinks matched (typically cancelled) nodes encountered in a - * traversal from head. - */ - private void sweep() { - needSweep = false; - for (Node p = head, s, n; p != null && (s = p.next) != null; ) { - if (!s.isMatched()) - // Unmatched nodes are never self-linked - p = s; - else if ((n = s.next) == null) // trailing node is pinned - break; - else if (s == n) // stale - // No need to also check for p == s, since that implies s == n - p = head; - else - p.casNext(s, n); - } - } - /** * Creates an initially empty {@code LinkedTransferQueue}. */ public LinkedTransferQueue() { - head = tail = new Node(); } /** @@ -1164,16 +1123,15 @@ public LinkedTransferQueue() { * of its elements are null */ public LinkedTransferQueue(Collection c) { - Node h = null, t = null; + DualNode h = null, t = null; for (E e : c) { - Node newNode = new Node(Objects.requireNonNull(e)); - if (h == null) - h = t = newNode; + DualNode newNode = new DualNode(Objects.requireNonNull(e), true); + if (t == null) + h = newNode; else - t.appendRelaxed(t = newNode); + t.next = newNode; + t = newNode; } - if (h == null) - h = t = new Node(); head = h; tail = t; } @@ -1185,7 +1143,8 @@ public LinkedTransferQueue(Collection c) { * @throws NullPointerException if the specified element is null */ public void put(E e) { - xfer(e, true, ASYNC, 0L); + Objects.requireNonNull(e); + xfer(e, -1L); } /** @@ -1198,7 +1157,8 @@ public void put(E e) { * @throws NullPointerException if the specified element is null */ public boolean offer(E e, long timeout, TimeUnit unit) { - xfer(e, true, ASYNC, 0L); + Objects.requireNonNull(e); + xfer(e, -1L); return true; } @@ -1210,7 +1170,8 @@ public boolean offer(E e, long timeout, TimeUnit unit) { * @throws NullPointerException if the specified element is null */ public boolean offer(E e) { - xfer(e, true, ASYNC, 0L); + Objects.requireNonNull(e); + xfer(e, -1L); return true; } @@ -1223,7 +1184,8 @@ public boolean offer(E e) { * @throws NullPointerException if the specified element is null */ public boolean add(E e) { - xfer(e, true, ASYNC, 0L); + Objects.requireNonNull(e); + xfer(e, -1L); return true; } @@ -1238,7 +1200,8 @@ public boolean add(E e) { * @throws NullPointerException if the specified element is null */ public boolean tryTransfer(E e) { - return xfer(e, true, NOW, 0L) == null; + Objects.requireNonNull(e); + return xfer(e, 0L) == null; } /** @@ -1253,10 +1216,13 @@ public boolean tryTransfer(E e) { * @throws NullPointerException if the specified element is null */ public void transfer(E e) throws InterruptedException { - if (xfer(e, true, SYNC, 0L) != null) { + Objects.requireNonNull(e); + if (!Thread.interrupted()) { + if (xfer(e, Long.MAX_VALUE) == null) + return; Thread.interrupted(); // failure possible only due to interrupt - throw new InterruptedException(); } + throw new InterruptedException(); } /** @@ -1275,30 +1241,38 @@ public void transfer(E e) throws InterruptedException { */ public boolean tryTransfer(E e, long timeout, TimeUnit unit) throws InterruptedException { - if (xfer(e, true, TIMED, unit.toNanos(timeout)) == null) + Objects.requireNonNull(e); + long nanos = Math.max(unit.toNanos(timeout), 0L); + if (xfer(e, nanos) == null) return true; if (!Thread.interrupted()) return false; throw new InterruptedException(); } + @SuppressWarnings("unchecked") public E take() throws InterruptedException { - E e = xfer(null, false, SYNC, 0L); - if (e != null) - return e; - Thread.interrupted(); + Object e; + if (!Thread.interrupted()) { + if ((e = xfer(null, Long.MAX_VALUE)) != null) + return (E) e; + Thread.interrupted(); + } throw new InterruptedException(); } + @SuppressWarnings("unchecked") public E poll(long timeout, TimeUnit unit) throws InterruptedException { - E e = xfer(null, false, TIMED, unit.toNanos(timeout)); - if (e != null || !Thread.interrupted()) - return e; + Object e; + long nanos = Math.max(unit.toNanos(timeout), 0L); + if ((e = xfer(null, nanos)) != null || !Thread.interrupted()) + return (E) e; throw new InterruptedException(); } + @SuppressWarnings("unchecked") public E poll() { - return xfer(null, false, NOW, 0L); + return (E) xfer(null, 0L); } /** @@ -1344,7 +1318,7 @@ public Iterator iterator() { public E peek() { restartFromHead: for (;;) { - for (Node p = head; p != null;) { + for (DualNode p = head; p != null;) { Object item = p.item; if (p.isData) { if (item != null) { @@ -1372,7 +1346,7 @@ public boolean isEmpty() { public boolean hasWaitingConsumer() { restartFromHead: for (;;) { - for (Node p = head; p != null;) { + for (DualNode p = head; p != null;) { Object item = p.item; if (p.isData) { if (item != null) @@ -1421,22 +1395,23 @@ public int getWaitingConsumerCount() { public boolean remove(Object o) { if (o == null) return false; restartFromHead: for (;;) { - for (Node p = head, pred = null; p != null; ) { - Node q = p.next; - final Object item; - if ((item = p.item) != null) { - if (p.isData) { - if (o.equals(item) && p.tryMatch(item, null)) { + for (DualNode p = head, pred = null; p != null; ) { + boolean isData = p.isData; + Object item = p.item; + DualNode q = p.next; + if (item != null) { + if (isData) { + if (o.equals(item) && tryMatchData(p, item)) { skipDeadNodes(pred, p, p, q); return true; } pred = p; p = q; continue; } } - else if (!p.isData) + else if (!isData) break; - for (Node c = p;; q = p.next) { - if (q == null || !q.isMatched()) { + for (DualNode c = p;; q = p.next) { + if (q == null || !q.matched()) { pred = skipDeadNodes(pred, c, p, q); p = q; break; } if (p == (p = q)) continue restartFromHead; @@ -1457,20 +1432,21 @@ else if (!p.isData) public boolean contains(Object o) { if (o == null) return false; restartFromHead: for (;;) { - for (Node p = head, pred = null; p != null; ) { - Node q = p.next; - final Object item; - if ((item = p.item) != null) { - if (p.isData) { + for (DualNode p = head, pred = null; p != null; ) { + boolean isData = p.isData; + Object item = p.item; + DualNode q = p.next; + if (item != null) { + if (isData) { if (o.equals(item)) return true; pred = p; p = q; continue; } } - else if (!p.isData) + else if (!isData) break; - for (Node c = p;; q = p.next) { - if (q == null || !q.isMatched()) { + for (DualNode c = p;; q = p.next) { + if (q == null || !q.matched()) { pred = skipDeadNodes(pred, c, p, q); p = q; break; } if (p == (p = q)) continue restartFromHead; @@ -1519,16 +1495,15 @@ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in elements until trailing null sentinel found - Node h = null, t = null; + DualNode h = null, t = null; for (Object item; (item = s.readObject()) != null; ) { - Node newNode = new Node(item); - if (h == null) - h = t = newNode; + DualNode newNode = new DualNode(item, true); + if (t == null) + h = newNode; else - t.appendRelaxed(t = newNode); + t.next = newNode; + t = newNode; } - if (h == null) - h = t = new Node(); head = h; tail = t; } @@ -1567,6 +1542,7 @@ public void clear() { */ private static final int MAX_HOPS = 8; + /** Implementation of bulk remove methods. */ @SuppressWarnings("unchecked") private boolean bulkRemove(Predicate filter) { @@ -1575,24 +1551,24 @@ private boolean bulkRemove(Predicate filter) { int hops = MAX_HOPS; // c will be CASed to collapse intervening dead nodes between // pred (or head if null) and p. - for (Node p = head, c = p, pred = null, q; p != null; p = q) { + for (DualNode p = head, c = p, pred = null, q; p != null; p = q) { + boolean isData = p.isData, pAlive; + Object item = p.item; q = p.next; - final Object item; boolean pAlive; - if (pAlive = ((item = p.item) != null && p.isData)) { + if (pAlive = (item != null && isData)) { if (filter.test((E) item)) { - if (p.tryMatch(item, null)) + if (tryMatchData(p, item)) removed = true; pAlive = false; } } - else if (!p.isData && item == null) + else if (!isData && item == null) break; if (pAlive || q == null || --hops == 0) { // p might already be self-linked here, but if so: // - CASing head will surely fail // - CASing pred's next will be useless but harmless. - if ((c != p && !tryCasSuccessor(pred, c, c = p)) - || pAlive) { + if ((c != p && !tryCasSuccessor(pred, c, c = p)) || pAlive) { // if CAS failed or alive, abandon old pred hops = MAX_HOPS; pred = p; @@ -1610,20 +1586,21 @@ else if (!p.isData && item == null) * If p is null, the action is not run. */ @SuppressWarnings("unchecked") - void forEachFrom(Consumer action, Node p) { - for (Node pred = null; p != null; ) { - Node q = p.next; - final Object item; - if ((item = p.item) != null) { - if (p.isData) { + void forEachFrom(Consumer action, DualNode p) { + for (DualNode pred = null; p != null; ) { + boolean isData = p.isData; + Object item = p.item; + DualNode q = p.next; + if (item != null) { + if (isData) { action.accept((E) item); pred = p; p = q; continue; } } - else if (!p.isData) + else if (!isData) break; - for (Node c = p;; q = p.next) { - if (q == null || !q.isMatched()) { + for (DualNode c = p;; q = p.next) { + if (q == null || !q.matched()) { pred = skipDeadNodes(pred, c, p, q); p = q; break; } if (p == (p = q)) { pred = null; p = head; break; } @@ -1640,27 +1617,18 @@ public void forEach(Consumer action) { } // VarHandle mechanics - private static final VarHandle HEAD; - private static final VarHandle TAIL; - static final VarHandle ITEM; - static final VarHandle NEXT; - static final VarHandle WAITER; + static final VarHandle HEAD; + static final VarHandle TAIL; + static final VarHandle SWEEPVOTES; static { try { + Class ltq = LinkedTransferQueue.class, tn = DualNode.class; MethodHandles.Lookup l = MethodHandles.lookup(); - HEAD = l.findVarHandle(LinkedTransferQueue.class, "head", - Node.class); - TAIL = l.findVarHandle(LinkedTransferQueue.class, "tail", - Node.class); - ITEM = l.findVarHandle(Node.class, "item", Object.class); - NEXT = l.findVarHandle(Node.class, "next", Node.class); - WAITER = l.findVarHandle(Node.class, "waiter", Thread.class); + HEAD = l.findVarHandle(ltq, "head", tn); + TAIL = l.findVarHandle(ltq, "tail", tn); + SWEEPVOTES = l.findVarHandle(ltq, "sweepVotes", int.class); } catch (ReflectiveOperationException e) { throw new ExceptionInInitializerError(e); } - - // Reduce the risk of rare disastrous classloading in first call to - // LockSupport.park: https://bugs.openjdk.org/browse/JDK-8074773 - Class ensureLoaded = LockSupport.class; } } diff --git a/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java b/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java index c22d9b1d8ae17..32f7840ef043e 100644 --- a/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java @@ -47,6 +47,9 @@ import java.util.Spliterators; import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.ForkJoinWorkerThread; +import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.TransferQueue; /** * A {@linkplain BlockingQueue blocking queue} in which each insert @@ -98,717 +101,137 @@ public class SynchronousQueue extends AbstractQueue * M. L. Scott. 18th Annual Conf. on Distributed Computing, * Oct. 2004 (see also * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/duals.html). - * The (Lifo) stack is used for non-fair mode, and the (Fifo) - * queue for fair mode. The performance of the two is generally - * similar. Fifo usually supports higher throughput under - * contention but Lifo maintains higher thread locality in common - * applications. + * The queue is treated as a Lifo stack in non-fair mode, and a + * Fifo queue in fair mode. In most contexts, transfer performance + * is roughly comparable across them. Lifo is usually faster under + * low contention, but slower under high contention. Performance + * of applications using them also varies. Lifo is generally + * preferable in resource management settings (for example cached + * thread pools) because of better temporal locality, but + * inappropriate for message-passing applications. * - * A dual queue (and similarly stack) is one that at any given - * time either holds "data" -- items provided by put operations, - * or "requests" -- slots representing take operations, or is - * empty. A call to "fulfill" (i.e., a call requesting an item - * from a queue holding data or vice versa) dequeues a - * complementary node. The most interesting feature of these - * queues is that any operation can figure out which mode the - * queue is in, and act accordingly without needing locks. - * - * Both the queue and stack extend abstract class Transferer - * defining the single method transfer that does a put or a - * take. These are unified into a single method because in dual - * data structures, the put and take operations are symmetrical, - * so nearly all code can be combined. The resulting transfer - * methods are on the long side, but are easier to follow than - * they would be if broken up into nearly-duplicated parts. - * - * The queue and stack data structures share many conceptual - * similarities but very few concrete details. For simplicity, - * they are kept distinct so that they can later evolve - * separately. + * A dual queue is one that at any given time either holds "data" + * -- items provided by put operations, or "requests" -- slots + * representing take operations, or is empty. A fulfilling + * operation (i.e., a call requesting an item from a queue holding + * data or vice versa) "matches" the item of and then dequeues a + * complementary node. Any operation can figure out which mode + * the queue is in, and act accordingly without needing locks. So + * put and take operations are symmetrical, and all transfer + * methods invoke a single "xfer" method that does a put or a take + * in either fifo or lifo mode. * * The algorithms here differ from the versions in the above paper - * in extending them for use in synchronous queues, as well as - * dealing with cancellation. The main differences include: - * - * 1. The original algorithms used bit-marked pointers, but - * the ones here use mode bits in nodes, leading to a number - * of further adaptations. - * 2. SynchronousQueues must block threads waiting to become - * fulfilled. - * 3. Support for cancellation via timeout and interrupts, - * including cleaning out cancelled nodes/threads - * from lists to avoid garbage retention and memory depletion. - * - * Blocking is mainly accomplished using LockSupport park/unpark, - * except that nodes that appear to be the next ones to become - * fulfilled first spin a bit (on multiprocessors only). On very - * busy synchronous queues, spinning can dramatically improve - * throughput. And on less busy ones, the amount of spinning is - * small enough not to be noticeable. - * - * Cleaning is done in different ways in queues vs stacks. For - * queues, we can almost always remove a node immediately in O(1) - * time (modulo retries for consistency checks) when it is - * cancelled. But if it may be pinned as the current tail, it must - * wait until some subsequent cancellation. For stacks, we need a - * potentially O(n) traversal to be sure that we can remove the - * node, but this can run concurrently with other threads - * accessing the stack. + * in ways including: * - * While garbage collection takes care of most node reclamation - * issues that otherwise complicate nonblocking algorithms, care - * is taken to "forget" references to data, other nodes, and - * threads that might be held on to long-term by blocked - * threads. In cases where setting to null would otherwise - * conflict with main algorithms, this is done by changing a - * node's link to now point to the node itself. This doesn't arise - * much for Stack nodes (because blocked threads do not hang on to - * old head pointers), but references in Queue nodes must be - * aggressively forgotten to avoid reachability of everything any - * node has ever referred to since arrival. - * - * The above steps improve throughput when many threads produce - * and/or consume data. But they don't help much with - * single-source / single-sink usages in which one side or the - * other is always transiently blocked, and so throughput is - * mainly a function of thread scheduling. This is not usually - * noticeably improved with bounded short spin-waits. Instead both - * forms of transfer try Thread.yield if apparently the sole - * waiter. This works well when there are more tasks that cores, - * which is expected to be the main usage context of this mode. In - * other cases, waiters may help with some bookkeeping, then - * park/unpark. + * * The original algorithms used bit-marked pointers, but the + * ones here use a bit (isData) in nodes, and usually avoid + * creating nodes when fulfilling. They also use the + * compareAndExchange form of CAS for pointer updates to + * reduce memory traffic. + * * Fifo mode is based on LinkedTransferQueue operations, but + * Lifo mode support is added in subclass Transferer. + * * The Fifo version accommodates lazy updates and slack as + * described in LinkedTransferQueue internal documentation. + * * Threads may block when waiting to become fulfilled, + * sometimes preceded by brief spins. + * * Support for cancellation via timeout and interrupts, + * including cleaning out cancelled nodes/threads from lists + * to avoid garbage retention and memory depletion. */ /** - * Shared internal API for dual stacks and queues. + * Extension of LinkedTransferQueue to support Lifo (stack) mode. + * Methods use the "head" field as head (top) of stack (versus + * queue). Note that popped nodes are not self-linked because they + * are not prone to unbounded garbage chains. Also note that + * "async" mode is never used and not supported for synchronous + * transfers. */ - abstract static class Transferer { + @SuppressWarnings("serial") // never serialized + static final class Transferer extends LinkedTransferQueue { + /** - * Performs a put or take. + * Puts or takes an item with lifo ordering. Loops trying: + * * If top (var p) exists and is already matched, pop and continue + * * If top has complementary type, try to fulfill by CASing item, + * On success pop (which will succeed unless already helped), + * otherwise restart. + * * If no possible match, unless immediate mode, push a + * node and wait, later unsplicing if cancelled. * - * @param e if non-null, the item to be handed to a consumer; - * if null, requests that transfer return an item - * offered by producer. - * @param timed if this operation should timeout - * @param nanos the timeout, in nanoseconds - * @return if non-null, the item provided or received; if null, - * the operation failed due to timeout or interrupt -- - * the caller can distinguish which of these occurred - * by checking Thread.interrupted. + * @param e the item or null for take + * @param ns timeout or 0 if immediate, Long.MAX_VALUE if untimed + * @return an item if matched, else e */ - abstract E transfer(E e, boolean timed, long nanos); - } - - /** - * The number of nanoseconds for which it is faster to spin - * rather than to use timed park. A rough estimate suffices. - */ - static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1023L; - - /** Dual stack */ - static final class TransferStack extends Transferer { - /* - * This extends Scherer-Scott dual stack algorithm, differing, - * among other ways, by using "covering" nodes rather than - * bit-marked pointers: Fulfilling operations push on marker - * nodes (with FULFILLING bit set in mode) to reserve a spot - * to match a waiting node. - */ - - /* Modes for SNodes, ORed together in node fields */ - /** Node represents an unfulfilled consumer */ - static final int REQUEST = 0; - /** Node represents an unfulfilled producer */ - static final int DATA = 1; - /** Node is fulfilling another unfulfilled DATA or REQUEST */ - static final int FULFILLING = 2; - - /** Returns true if m has fulfilling bit set. */ - static boolean isFulfilling(int m) { return (m & FULFILLING) != 0; } - - /** Node class for TransferStacks. */ - static final class SNode implements ForkJoinPool.ManagedBlocker { - volatile SNode next; // next node in stack - volatile SNode match; // the node matched to this - volatile Thread waiter; // to control park/unpark - Object item; // data; or null for REQUESTs - int mode; - // Note: item and mode fields don't need to be volatile - // since they are always written before, and read after, - // other volatile/atomic operations. - - SNode(Object item) { - this.item = item; - } - - boolean casNext(SNode cmp, SNode val) { - return cmp == next && - SNEXT.compareAndSet(this, cmp, val); - } - - /** - * Tries to match node s to this node, if so, waking up thread. - * Fulfillers call tryMatch to identify their waiters. - * Waiters block until they have been matched. - * - * @param s the node to match - * @return true if successfully matched to s - */ - boolean tryMatch(SNode s) { - SNode m; Thread w; - if ((m = match) == null) { - if (SMATCH.compareAndSet(this, null, s)) { - if ((w = waiter) != null) - LockSupport.unpark(w); - return true; + final Object xferLifo(Object e, long ns) { + boolean haveData = (e != null); + Object m; // the match or e if none + outer: for (DualNode s = null, p = head;;) { + while (p != null) { + boolean isData; DualNode n, u; // help collapse + if ((isData = p.isData) != ((m = p.item) != null)) + p = (p == (u = cmpExHead(p, (n = p.next)))) ? n : u; + else if (isData == haveData) // same mode; push below + break; + else if (p.cmpExItem(m, e) != m) + p = head; // missed; restart + else { // matched complementary node + Thread w = p.waiter; + cmpExHead(p, p.next); + LockSupport.unpark(w); + break outer; } - else - m = match; - } - return m == s; - } - - /** - * Tries to cancel a wait by matching node to itself. - */ - boolean tryCancel() { - return SMATCH.compareAndSet(this, null, this); - } - - boolean isCancelled() { - return match == this; - } - - public final boolean isReleasable() { - return match != null || Thread.currentThread().isInterrupted(); - } - - public final boolean block() { - while (!isReleasable()) LockSupport.park(); - return true; - } - - void forgetWaiter() { - SWAITER.setOpaque(this, null); - } - - // VarHandle mechanics - private static final VarHandle SMATCH; - private static final VarHandle SNEXT; - private static final VarHandle SWAITER; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - SMATCH = l.findVarHandle(SNode.class, "match", SNode.class); - SNEXT = l.findVarHandle(SNode.class, "next", SNode.class); - SWAITER = l.findVarHandle(SNode.class, "waiter", Thread.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); } - } - } - - /** The head (top) of the stack */ - volatile SNode head; - - boolean casHead(SNode h, SNode nh) { - return h == head && - SHEAD.compareAndSet(this, h, nh); - } - - /** - * Creates or resets fields of a node. Called only from transfer - * where the node to push on stack is lazily created and - * reused when possible to help reduce intervals between reads - * and CASes of head and to avoid surges of garbage when CASes - * to push nodes fail due to contention. - */ - static SNode snode(SNode s, Object e, SNode next, int mode) { - if (s == null) s = new SNode(e); - s.mode = mode; - s.next = next; - return s; - } - - /** - * Puts or takes an item. - */ - @SuppressWarnings("unchecked") - E transfer(E e, boolean timed, long nanos) { - /* - * Basic algorithm is to loop trying one of three actions: - * - * 1. If apparently empty or already containing nodes of same - * mode, try to push node on stack and wait for a match, - * returning it, or null if cancelled. - * - * 2. If apparently containing node of complementary mode, - * try to push a fulfilling node on to stack, match - * with corresponding waiting node, pop both from - * stack, and return matched item. The matching or - * unlinking might not actually be necessary because of - * other threads performing action 3: - * - * 3. If top of stack already holds another fulfilling node, - * help it out by doing its match and/or pop - * operations, and then continue. The code for helping - * is essentially the same as for fulfilling, except - * that it doesn't return the item. - */ - - SNode s = null; // constructed/reused as needed - int mode = (e == null) ? REQUEST : DATA; - - for (;;) { - SNode h = head; - if (h == null || h.mode == mode) { // empty or same-mode - if (timed && nanos <= 0L) { // can't wait - if (h != null && h.isCancelled()) - casHead(h, h.next); // pop cancelled node - else - return null; - } else if (casHead(h, s = snode(s, e, h, mode))) { - long deadline = timed ? System.nanoTime() + nanos : 0L; - Thread w = Thread.currentThread(); - int stat = -1; // -1: may yield, +1: park, else 0 - SNode m; // await fulfill or cancel - while ((m = s.match) == null) { - if ((timed && - (nanos = deadline - System.nanoTime()) <= 0) || - w.isInterrupted()) { - if (s.tryCancel()) { - clean(s); // wait cancelled - return null; - } - } else if ((m = s.match) != null) { - break; // recheck - } else if (stat <= 0) { - if (stat < 0 && h == null && head == s) { - stat = 0; // yield once if was empty - Thread.yield(); - } else { - stat = 1; - s.waiter = w; // enable signal - } - } else if (!timed) { - LockSupport.setCurrentBlocker(this); - try { - ForkJoinPool.managedBlock(s); - } catch (InterruptedException cannotHappen) { } - LockSupport.setCurrentBlocker(null); - } else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD) - LockSupport.parkNanos(this, nanos); - } - if (stat == 1) - s.forgetWaiter(); - Object result = (mode == REQUEST) ? m.item : s.item; - if (h != null && h.next == s) - casHead(h, s.next); // help fulfiller - return (E) result; - } - } else if (!isFulfilling(h.mode)) { // try to fulfill - if (h.isCancelled()) // already cancelled - casHead(h, h.next); // pop and retry - else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) { - for (;;) { // loop until matched or waiters disappear - SNode m = s.next; // m is s's match - if (m == null) { // all waiters are gone - casHead(s, null); // pop fulfill node - s = null; // use new node next time - break; // restart main loop - } - SNode mn = m.next; - if (m.tryMatch(s)) { - casHead(s, mn); // pop both s and m - return (E) ((mode == REQUEST) ? m.item : s.item); - } else // lost match - s.casNext(m, mn); // help unlink - } - } - } else { // help a fulfiller - SNode m = h.next; // m is h's match - if (m == null) // waiter is gone - casHead(h, null); // pop fulfilling node - else { - SNode mn = m.next; - if (m.tryMatch(h)) // help match - casHead(h, mn); // pop both h and m - else // lost match - h.casNext(m, mn); // help unlink - } + if (ns == 0L) { // no match, no wait + m = e; + break; } - } - } - - /** - * Unlinks s from the stack. - */ - void clean(SNode s) { - s.item = null; // forget item - s.forgetWaiter(); - - /* - * At worst we may need to traverse entire stack to unlink - * s. If there are multiple concurrent calls to clean, we - * might not see s if another thread has already removed - * it. But we can stop when we see any node known to - * follow s. We use s.next unless it too is cancelled, in - * which case we try the node one past. We don't check any - * further because we don't want to doubly traverse just to - * find sentinel. - */ - - SNode past = s.next; - if (past != null && past.isCancelled()) - past = past.next; - - // Absorb cancelled nodes at head - SNode p; - while ((p = head) != null && p != past && p.isCancelled()) - casHead(p, p.next); - - // Unsplice embedded nodes - while (p != null && p != past) { - SNode n = p.next; - if (n != null && n.isCancelled()) - p.casNext(n, n.next); - else - p = n; - } - } - - // VarHandle mechanics - private static final VarHandle SHEAD; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - SHEAD = l.findVarHandle(TransferStack.class, "head", SNode.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } - } - } - - /** Dual Queue */ - static final class TransferQueue extends Transferer { - /* - * This extends Scherer-Scott dual queue algorithm, differing, - * among other ways, by using modes within nodes rather than - * marked pointers. The algorithm is a little simpler than - * that for stacks because fulfillers do not need explicit - * nodes, and matching is done by CAS'ing QNode.item field - * from non-null to null (for put) or vice versa (for take). - */ - - /** Node class for TransferQueue. */ - static final class QNode implements ForkJoinPool.ManagedBlocker { - volatile QNode next; // next node in queue - volatile Object item; // CAS'ed to or from null - volatile Thread waiter; // to control park/unpark - final boolean isData; - - QNode(Object item, boolean isData) { - this.item = item; - this.isData = isData; - } - - boolean casNext(QNode cmp, QNode val) { - return next == cmp && - QNEXT.compareAndSet(this, cmp, val); - } - - boolean casItem(Object cmp, Object val) { - return item == cmp && - QITEM.compareAndSet(this, cmp, val); - } - - /** - * Tries to cancel by CAS'ing ref to this as item. - */ - boolean tryCancel(Object cmp) { - return QITEM.compareAndSet(this, cmp, this); - } - - boolean isCancelled() { - return item == this; - } - - /** - * Returns true if this node is known to be off the queue - * because its next pointer has been forgotten due to - * an advanceHead operation. - */ - boolean isOffList() { - return next == this; - } - - void forgetWaiter() { - QWAITER.setOpaque(this, null); - } - - boolean isFulfilled() { - Object x; - return isData == ((x = item) == null) || x == this; - } - - public final boolean isReleasable() { - Object x; - return isData == ((x = item) == null) || x == this || - Thread.currentThread().isInterrupted(); - } - - public final boolean block() { - while (!isReleasable()) LockSupport.park(); - return true; - } - - // VarHandle mechanics - private static final VarHandle QITEM; - private static final VarHandle QNEXT; - private static final VarHandle QWAITER; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - QITEM = l.findVarHandle(QNode.class, "item", Object.class); - QNEXT = l.findVarHandle(QNode.class, "next", QNode.class); - QWAITER = l.findVarHandle(QNode.class, "waiter", Thread.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); + if (s == null) // try to push node and wait + s = new DualNode(e, haveData); + s.next = p; + if (p == (p = cmpExHead(p, s))) { + if ((m = s.await(e, ns, this, // spin if (nearly) empty + p == null || p.waiter == null)) == e) + unspliceLifo(s); // cancelled + break; } } - } - - /** Head of queue */ - transient volatile QNode head; - /** Tail of queue */ - transient volatile QNode tail; - /** - * Reference to a cancelled node that might not yet have been - * unlinked from queue because it was the last inserted node - * when it was cancelled. - */ - transient volatile QNode cleanMe; - - TransferQueue() { - QNode h = new QNode(null, false); // initialize to dummy node. - head = h; - tail = h; - } - - /** - * Tries to cas nh as new head; if successful, unlink - * old head's next node to avoid garbage retention. - */ - void advanceHead(QNode h, QNode nh) { - if (h == head && - QHEAD.compareAndSet(this, h, nh)) - h.next = h; // forget old next + return m; } /** - * Tries to cas nt as new tail. + * Unlinks node s. Same idea as Fifo version. */ - void advanceTail(QNode t, QNode nt) { - if (tail == t) - QTAIL.compareAndSet(this, t, nt); - } - - /** - * Tries to CAS cleanMe slot. - */ - boolean casCleanMe(QNode cmp, QNode val) { - return cleanMe == cmp && - QCLEANME.compareAndSet(this, cmp, val); - } - - /** - * Puts or takes an item. - */ - @SuppressWarnings("unchecked") - E transfer(E e, boolean timed, long nanos) { - /* Basic algorithm is to loop trying to take either of - * two actions: - * - * 1. If queue apparently empty or holding same-mode nodes, - * try to add node to queue of waiters, wait to be - * fulfilled (or cancelled) and return matching item. - * - * 2. If queue apparently contains waiting items, and this - * call is of complementary mode, try to fulfill by CAS'ing - * item field of waiting node and dequeuing it, and then - * returning matching item. - * - * In each case, along the way, check for and try to help - * advance head and tail on behalf of other stalled/slow - * threads. - * - * The loop starts off with a null check guarding against - * seeing uninitialized head or tail values. This never - * happens in current SynchronousQueue, but could if - * callers held non-volatile/final ref to the - * transferer. The check is here anyway because it places - * null checks at top of loop, which is usually faster - * than having them implicitly interspersed. - */ - - QNode s = null; // constructed/reused as needed - boolean isData = (e != null); - for (;;) { - QNode t = tail, h = head, m, tn; // m is node to fulfill - if (t == null || h == null) - ; // inconsistent - else if (h == t || t.isData == isData) { // empty or same-mode - if (t != tail) // inconsistent - ; - else if ((tn = t.next) != null) // lagging tail - advanceTail(t, tn); - else if (timed && nanos <= 0L) // can't wait - return null; - else if (t.casNext(null, (s != null) ? s : - (s = new QNode(e, isData)))) { - advanceTail(t, s); - long deadline = timed ? System.nanoTime() + nanos : 0L; - Thread w = Thread.currentThread(); - int stat = -1; // same idea as TransferStack - Object item; - while ((item = s.item) == e) { - if ((timed && - (nanos = deadline - System.nanoTime()) <= 0) || - w.isInterrupted()) { - if (s.tryCancel(e)) { - clean(t, s); - return null; - } - } else if ((item = s.item) != e) { - break; // recheck - } else if (stat <= 0) { - if (t.next == s) { - if (stat < 0 && t.isFulfilled()) { - stat = 0; // yield once if first - Thread.yield(); - } - else { - stat = 1; - s.waiter = w; - } - } - } else if (!timed) { - LockSupport.setCurrentBlocker(this); - try { - ForkJoinPool.managedBlock(s); - } catch (InterruptedException cannotHappen) { } - LockSupport.setCurrentBlocker(null); - } - else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD) - LockSupport.parkNanos(this, nanos); - } - if (stat == 1) - s.forgetWaiter(); - if (!s.isOffList()) { // not already unlinked - advanceHead(t, s); // unlink if head - if (item != null) // and forget fields - s.item = s; - } - return (item != null) ? (E)item : e; - } - - } else if ((m = h.next) != null && t == tail && h == head) { - Thread waiter; - Object x = m.item; - boolean fulfilled = ((isData == (x == null)) && - x != m && m.casItem(x, e)); - advanceHead(h, m); // (help) dequeue - if (fulfilled) { - if ((waiter = m.waiter) != null) - LockSupport.unpark(waiter); - return (x != null) ? (E)x : e; - } - } + private void unspliceLifo(DualNode s) { + boolean seen = false; // try removing by collapsing head + DualNode p = head; + for (DualNode f, u; p != null && p.matched();) { + if (p == s) + seen = true; + p = (p == (u = cmpExHead(p, (f = p.next)))) ? f : u; } - } - - /** - * Gets rid of cancelled node s with original predecessor pred. - */ - void clean(QNode pred, QNode s) { - s.forgetWaiter(); - /* - * At any given time, exactly one node on list cannot be - * deleted -- the last inserted node. To accommodate this, - * if we cannot delete s, we save its predecessor as - * "cleanMe", deleting the previously saved version - * first. At least one of node s or the node previously - * saved can always be deleted, so this always terminates. - */ - while (pred.next == s) { // Return early if already unlinked - QNode h = head; - QNode hn = h.next; // Absorb cancelled first node as head - if (hn != null && hn.isCancelled()) { - advanceHead(h, hn); - continue; + if (p != null && !seen && sweepNow()) { // occasionally sweep + for (DualNode f, n, u; p != null && (f = p.next) != null; ) { + p = (!f.matched() ? f : + f == (u = p.cmpExNext(f, n = f.next)) ? n : u); } - QNode t = tail; // Ensure consistent read for tail - if (t == h) - return; - QNode tn = t.next; - if (t != tail) - continue; - if (tn != null) { - advanceTail(t, tn); - continue; - } - if (s != t) { // If not tail, try to unsplice - QNode sn = s.next; - if (sn == s || pred.casNext(s, sn)) - return; - } - QNode dp = cleanMe; - if (dp != null) { // Try unlinking previous cancelled node - QNode d = dp.next; - QNode dn; - if (d == null || // d is gone or - d == dp || // d is off list or - !d.isCancelled() || // d not cancelled or - (d != t && // d not tail and - (dn = d.next) != null && // has successor - dn != d && // that is on list - dp.casNext(d, dn))) // d unspliced - casCleanMe(dp, null); - if (dp == pred) - return; // s is already saved node - } else if (casCleanMe(null, pred)) - return; // Postpone cleaning s - } - } - - // VarHandle mechanics - private static final VarHandle QHEAD; - private static final VarHandle QTAIL; - private static final VarHandle QCLEANME; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - QHEAD = l.findVarHandle(TransferQueue.class, "head", - QNode.class); - QTAIL = l.findVarHandle(TransferQueue.class, "tail", - QNode.class); - QCLEANME = l.findVarHandle(TransferQueue.class, "cleanMe", - QNode.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); } } } /** - * The transferer. Set only in constructor, but cannot be declared - * as final without further complicating serialization. Since - * this is accessed only at most once per public method, there - * isn't a noticeable performance penalty for using volatile - * instead of final here. + * The transferer. (See below about serialization.) */ - private transient volatile Transferer transferer; + private final transient Transferer transferer; + + private final transient boolean fair; + + /** Invokes fair or lifo transfer */ + private Object xfer(Object e, long nanos) { + Transferer x = transferer; + return (fair) ? x.xfer(e, nanos) : x.xferLifo(e, nanos); + } /** * Creates a {@code SynchronousQueue} with nonfair access policy. @@ -824,7 +247,8 @@ public SynchronousQueue() { * access; otherwise the order is unspecified. */ public SynchronousQueue(boolean fair) { - transferer = fair ? new TransferQueue() : new TransferStack(); + this.fair = fair; + transferer = new Transferer(); } /** @@ -835,11 +259,13 @@ public SynchronousQueue(boolean fair) { * @throws NullPointerException {@inheritDoc} */ public void put(E e) throws InterruptedException { - if (e == null) throw new NullPointerException(); - if (transferer.transfer(e, false, 0) == null) { - Thread.interrupted(); - throw new InterruptedException(); + Objects.requireNonNull(e); + if (!Thread.interrupted()) { + if (xfer(e, Long.MAX_VALUE) == null) + return; + Thread.interrupted(); // failure possible only due to interrupt } + throw new InterruptedException(); } /** @@ -853,8 +279,9 @@ public void put(E e) throws InterruptedException { */ public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException { - if (e == null) throw new NullPointerException(); - if (transferer.transfer(e, true, unit.toNanos(timeout)) != null) + Objects.requireNonNull(e); + long nanos = Math.max(unit.toNanos(timeout), 0L); + if (xfer(e, nanos) == null) return true; if (!Thread.interrupted()) return false; @@ -871,8 +298,8 @@ public boolean offer(E e, long timeout, TimeUnit unit) * @throws NullPointerException if the specified element is null */ public boolean offer(E e) { - if (e == null) throw new NullPointerException(); - return transferer.transfer(e, true, 0) != null; + Objects.requireNonNull(e); + return xfer(e, 0L) == null; } /** @@ -882,11 +309,14 @@ public boolean offer(E e) { * @return the head of this queue * @throws InterruptedException {@inheritDoc} */ + @SuppressWarnings("unchecked") public E take() throws InterruptedException { - E e = transferer.transfer(null, false, 0); - if (e != null) - return e; - Thread.interrupted(); + Object e; + if (!Thread.interrupted()) { + if ((e = xfer(null, Long.MAX_VALUE)) != null) + return (E) e; + Thread.interrupted(); + } throw new InterruptedException(); } @@ -899,10 +329,12 @@ public E take() throws InterruptedException { * specified waiting time elapses before an element is present * @throws InterruptedException {@inheritDoc} */ + @SuppressWarnings("unchecked") public E poll(long timeout, TimeUnit unit) throws InterruptedException { - E e = transferer.transfer(null, true, unit.toNanos(timeout)); - if (e != null || !Thread.interrupted()) - return e; + Object e; + long nanos = Math.max(unit.toNanos(timeout), 0L); + if ((e = xfer(null, nanos)) != null || !Thread.interrupted()) + return (E) e; throw new InterruptedException(); } @@ -913,8 +345,9 @@ public E poll(long timeout, TimeUnit unit) throws InterruptedException { * @return the head of this queue, or {@code null} if no * element is available */ + @SuppressWarnings("unchecked") public E poll() { - return transferer.transfer(null, true, 0); + return (E) xfer(null, 0L); } /** @@ -1104,11 +537,13 @@ public int drainTo(Collection c, int maxElements) { } /* - * To cope with serialization strategy in the 1.5 version of - * SynchronousQueue, we declare some unused classes and fields - * that exist solely to enable serializability across versions. - * These fields are never used, so are initialized only if this - * object is ever serialized or deserialized. + * To cope with serialization across multiple implementation + * overhauls, we declare some unused classes and fields that exist + * solely to enable serializability across versions. These fields + * are never used, so are initialized only if this object is ever + * serialized. We use readResolve to replace a deserialized queue + * with a fresh one. Note that no queue elements are serialized, + * since any existing ones are only transient. */ @SuppressWarnings("serial") @@ -1130,7 +565,6 @@ static class FifoWaitQueue extends WaitQueue { */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { - boolean fair = transferer instanceof TransferQueue; if (fair) { qlock = new ReentrantLock(true); waitingProducers = new FifoWaitQueue(); @@ -1145,24 +579,10 @@ private void writeObject(java.io.ObjectOutputStream s) } /** - * Reconstitutes this queue from a stream (that is, deserializes it). - * @param s the stream - * @throws ClassNotFoundException if the class of a serialized object - * could not be found - * @throws java.io.IOException if an I/O error occurs + * Replaces a deserialized SynchronousQueue with a fresh one with + * the associated fairness */ - private void readObject(java.io.ObjectInputStream s) - throws java.io.IOException, ClassNotFoundException { - s.defaultReadObject(); - if (waitingProducers instanceof FifoWaitQueue) - transferer = new TransferQueue(); - else - transferer = new TransferStack(); - } - - static { - // Reduce the risk of rare disastrous classloading in first call to - // LockSupport.park: https://bugs.openjdk.org/browse/JDK-8074773 - Class ensureLoaded = LockSupport.class; + private Object readResolve() { + return new SynchronousQueue(waitingProducers instanceof FifoWaitQueue); } } diff --git a/src/java.base/share/classes/java/util/jar/JarFile.java b/src/java.base/share/classes/java/util/jar/JarFile.java index c8fcac4bda0ce..ca8c726129e58 100644 --- a/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/src/java.base/share/classes/java/util/jar/JarFile.java @@ -802,7 +802,9 @@ private byte[] getBytes(ZipEntry ze) throws IOException { throw new IOException("Unsupported size: " + uncompressedSize + " for JarEntry " + ze.getName() + ". Allowed max size: " + - SignatureFileVerifier.MAX_SIG_FILE_SIZE + " bytes"); + SignatureFileVerifier.MAX_SIG_FILE_SIZE + " bytes. " + + "You can use the jdk.jar.maxSignatureFileSize " + + "system property to increase the default value."); } int len = (int)uncompressedSize; int bytesRead; diff --git a/src/java.base/share/classes/java/util/regex/Matcher.java b/src/java.base/share/classes/java/util/regex/Matcher.java index 54fe63c4f4ba4..8bc07ba0347ff 100644 --- a/src/java.base/share/classes/java/util/regex/Matcher.java +++ b/src/java.base/share/classes/java/util/regex/Matcher.java @@ -274,13 +274,40 @@ public Pattern pattern() { * @since 1.5 */ public MatchResult toMatchResult() { - String capturedText = hasMatch() - ? text.subSequence(first, last).toString() - : null; + int minStart; + String capturedText; + if (hasMatch()) { + minStart = minStart(); + capturedText = text.subSequence(minStart, maxEnd()).toString(); + } else { + minStart = -1; + capturedText = null; + } return new ImmutableMatchResult(first, last, groupCount(), groups.clone(), capturedText, - namedGroups() - ); + namedGroups(), minStart); + } + + private int minStart() { + int r = text.length(); + for (int group = 0; group <= groupCount(); ++group) { + int start = groups[group * 2]; + if (start >= 0) { + r = Math.min(r, start); + } + } + return r; + } + + private int maxEnd() { + int r = 0; + for (int group = 0; group <= groupCount(); ++group) { + int end = groups[group * 2 + 1]; + if (end >= 0) { + r = Math.max(r, end); + } + } + return r; } private static class ImmutableMatchResult implements MatchResult { @@ -290,16 +317,18 @@ private static class ImmutableMatchResult implements MatchResult { private final int[] groups; private final String text; private final Map namedGroups; + private final int minStart; ImmutableMatchResult(int first, int last, int groupCount, int[] groups, String text, - Map namedGroups) { + Map namedGroups, int minStart) { this.first = first; this.last = last; this.groupCount = groupCount; this.groups = groups; this.text = text; this.namedGroups = namedGroups; + this.minStart = minStart; } @Override @@ -345,7 +374,7 @@ public String group(int group) { checkGroup(group); if ((groups[group * 2] == -1) || (groups[group * 2 + 1] == -1)) return null; - return text.substring(groups[group * 2] - first, groups[group * 2 + 1] - first); + return text.substring(groups[group * 2] - minStart, groups[group * 2 + 1] - minStart); } @Override 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 52d975005e05f..cb9070fc885d3 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -69,7 +69,7 @@ import jdk.internal.vm.annotation.Stable; import sun.nio.cs.UTF_8; import sun.nio.fs.DefaultFileSystemProvider; -import sun.security.action.GetBooleanAction; +import sun.security.action.GetPropertyAction; import sun.security.util.SignatureFileVerifier; import static java.util.zip.ZipConstants64.*; @@ -123,11 +123,12 @@ public class ZipFile implements ZipConstants, Closeable { public static final int OPEN_DELETE = 0x4; /** - * Flag which specifies whether the validation of the Zip64 extra - * fields should be disabled + * Flag to specify whether the Extra ZIP64 validation should be + * disabled. */ - private static final boolean disableZip64ExtraFieldValidation = - GetBooleanAction.privilegedGetProperty("jdk.util.zip.disableZip64ExtraFieldValidation"); + private static final boolean DISABLE_ZIP64_EXTRA_VALIDATION = + getDisableZip64ExtraFieldValidation(); + /** * Opens a zip file for reading. * @@ -1092,6 +1093,22 @@ private int[] getMetaInfVersions() { } } + /** + * Returns the value of the System property which indicates whether the + * Extra ZIP64 validation should be disabled. + */ + static boolean getDisableZip64ExtraFieldValidation() { + boolean result; + String value = GetPropertyAction.privilegedGetProperty( + "jdk.util.zip.disableZip64ExtraFieldValidation"); + if (value == null) { + result = false; + } else { + result = value.isEmpty() || value.equalsIgnoreCase("true"); + } + return result; + } + static { SharedSecrets.setJavaUtilZipFileAccess( new JavaUtilZipFileAccess() { @@ -1208,7 +1225,7 @@ private int checkAndAddEntry(int pos, int index) } int elen = CENEXT(cen, pos); - if (elen > 0 && !disableZip64ExtraFieldValidation) { + if (elen > 0 && !DISABLE_ZIP64_EXTRA_VALIDATION) { long extraStartingOffset = pos + CENHDR + nlen; if ((int)extraStartingOffset != extraStartingOffset) { zerror("invalid CEN header (bad extra offset)"); @@ -1260,25 +1277,32 @@ private void checkExtraFields(int cenPos, int startingOffset, zerror("Invalid CEN header (extra data field size too long)"); } int currentOffset = startingOffset; - while (currentOffset < extraEndOffset) { + // Walk through each Extra Header. Each Extra Header Must consist of: + // Header ID - 2 bytes + // Data Size - 2 bytes: + while (currentOffset + Integer.BYTES <= extraEndOffset) { int tag = get16(cen, currentOffset); currentOffset += Short.BYTES; int tagBlockSize = get16(cen, currentOffset); + currentOffset += Short.BYTES; int tagBlockEndingOffset = currentOffset + tagBlockSize; // The ending offset for this tag block should not go past the // offset for the end of the extra field if (tagBlockEndingOffset > extraEndOffset) { - zerror("Invalid CEN header (invalid zip64 extra data field size)"); + zerror(String.format( + "Invalid CEN header (invalid extra data field size for " + + "tag: 0x%04x at %d)", + tag, cenPos)); } - currentOffset += Short.BYTES; if (tag == ZIP64_EXTID) { // Get the compressed size; long csize = CENSIZ(cen, cenPos); // Get the uncompressed size; long size = CENLEN(cen, cenPos); + checkZip64ExtraFieldValues(currentOffset, tagBlockSize, csize, size); } @@ -1302,6 +1326,16 @@ private void checkZip64ExtraFieldValues(int off, int blockSize, long csize, long size) throws ZipException { byte[] cen = this.cen; + // if ZIP64_EXTID blocksize == 0, which may occur with some older + // versions of Apache Ant and Commons Compress, validate csize and size + // to make sure neither field == ZIP64_MAGICVAL + if (blockSize == 0) { + if (csize == ZIP64_MAGICVAL || size == ZIP64_MAGICVAL) { + zerror("Invalid CEN header (invalid zip64 extra data field size)"); + } + // Only validate the ZIP64_EXTID data if the block size > 0 + return; + } // Validate the Zip64 Extended Information Extra Field (0x0001) // length. if (!isZip64ExtBlockSizeValid(blockSize)) { diff --git a/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java b/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java index 5517d88157d94..e5cac698e65f1 100644 --- a/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,9 @@ import jdk.internal.access.SharedSecrets; import javax.crypto.SecretKey; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; import java.security.MessageDigest; import java.security.spec.KeySpec; import java.util.Arrays; @@ -60,7 +63,7 @@ public class SecretKeySpec implements KeySpec, SecretKey { * * @serial */ - private final byte[] key; + private byte[] key; /** * The name of the algorithm associated with this key. @@ -252,4 +255,26 @@ public boolean equals(Object obj) { void clear() { Arrays.fill(key, (byte)0); } + + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + + if (key == null || algorithm == null) { + throw new InvalidObjectException("Missing argument"); + } + + this.key = key.clone(); + if (key.length == 0) { + throw new InvalidObjectException("Invalid key length"); + } + } } diff --git a/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java b/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java index dd6072f5db8a0..c005b4ea02b0b 100644 --- a/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java +++ b/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,10 @@ package javax.security.auth.callback; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; + /** *

Underlying security services instantiate and pass a * {@code ChoiceCallback} to the {@code handle} @@ -48,7 +52,7 @@ public class ChoiceCallback implements Callback, java.io.Serializable { * @serial the list of choices * @since 1.4 */ - private final String[] choices; + private String[] choices; /** * @serial the choice to be used as the default choice * @since 1.4 @@ -72,7 +76,6 @@ public class ChoiceCallback implements Callback, java.io.Serializable { * a list of choices, a default choice, and a boolean specifying * whether multiple selections from the list of choices are allowed. * - * * @param prompt the prompt used to describe the list of choices. * * @param choices the list of choices. The array is cloned to protect @@ -104,15 +107,15 @@ public ChoiceCallback(String prompt, String[] choices, defaultChoice < 0 || defaultChoice >= choices.length) throw new IllegalArgumentException(); + this.prompt = prompt; + this.defaultChoice = defaultChoice; + this.multipleSelectionsAllowed = multipleSelectionsAllowed; + + this.choices = choices.clone(); for (int i = 0; i < choices.length; i++) { if (choices[i] == null || choices[i].isEmpty()) throw new IllegalArgumentException(); } - - this.prompt = prompt; - this.choices = choices.clone(); - this.defaultChoice = defaultChoice; - this.multipleSelectionsAllowed = multipleSelectionsAllowed; } /** @@ -196,4 +199,38 @@ public void setSelectedIndexes(int[] selections) { public int[] getSelectedIndexes() { return selections == null ? null : selections.clone(); } + + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + + if ((prompt == null) || prompt.isEmpty() || + (choices == null) || (choices.length == 0) || + (defaultChoice < 0) || (defaultChoice >= choices.length)) { + throw new InvalidObjectException( + "Missing/invalid prompt/choices"); + } + + choices = choices.clone(); + for (int i = 0; i < choices.length; i++) { + if ((choices[i] == null) || choices[i].isEmpty()) + throw new InvalidObjectException("Null/empty choices"); + } + + if (selections != null) { + selections = selections.clone(); + if (!multipleSelectionsAllowed && (selections.length != 1)) { + throw new InvalidObjectException( + "Multiple selections not allowed"); + } + } + } } diff --git a/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java b/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java index 926a3d889e2d5..437ce7041a7d7 100644 --- a/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java +++ b/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,9 @@ package javax.security.auth.callback; +import java.io.IOException; +import java.io.ObjectInputStream; + /** *

Underlying security services instantiate and pass a * {@code ConfirmationCallback} to the {@code handle} @@ -147,7 +150,7 @@ public class ConfirmationCallback implements Callback, java.io.Serializable { * @serial * @since 1.4 */ - private final String[] options; + private String[] options; /** * @serial * @since 1.4 @@ -252,16 +255,16 @@ public ConfirmationCallback(int messageType, defaultOption < 0 || defaultOption >= options.length) throw new IllegalArgumentException(); - for (int i = 0; i < options.length; i++) { - if (options[i] == null || options[i].isEmpty()) - throw new IllegalArgumentException(); - } - this.prompt = null; this.messageType = messageType; this.optionType = UNSPECIFIED_OPTION; - this.options = options.clone(); this.defaultOption = defaultOption; + + this.options = options.clone(); + for (int i = 0; i < options.length; i++) { + if (options[i] == null || options[i].isEmpty()) + throw new IllegalArgumentException(); + } } /** @@ -372,16 +375,16 @@ public ConfirmationCallback(String prompt, int messageType, defaultOption < 0 || defaultOption >= options.length) throw new IllegalArgumentException(); - for (int i = 0; i < options.length; i++) { - if (options[i] == null || options[i].isEmpty()) - throw new IllegalArgumentException(); - } - this.prompt = prompt; this.messageType = messageType; this.optionType = UNSPECIFIED_OPTION; - this.options = options.clone(); this.defaultOption = defaultOption; + + this.options = options.clone(); + for (int i = 0; i < options.length; i++) { + if (options[i] == null || options[i].isEmpty()) + throw new IllegalArgumentException(); + } } /** @@ -487,4 +490,20 @@ public void setSelectedIndex(int selection) { public int getSelectedIndex() { return selection; } + + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + if (options != null) { + options = options.clone(); + } + } } diff --git a/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java b/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java index b0758c012b237..bbe7ab882a6a1 100644 --- a/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java +++ b/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,9 @@ package javax.security.auth.callback; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; import java.lang.ref.Cleaner; import java.util.Arrays; @@ -157,4 +160,27 @@ public void clearPassword() { private static Runnable cleanerFor(char[] password) { return () -> Arrays.fill(password, ' '); } + + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + + if (prompt == null || prompt.isEmpty()) { + throw new InvalidObjectException("Missing prompt"); + } + + if (inputPassword != null) { + inputPassword = inputPassword.clone(); + cleanable = CleanerFactory.cleaner().register( + this, cleanerFor(inputPassword)); + } + } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/components/ClassRemapper.java b/src/java.base/share/classes/jdk/internal/classfile/components/ClassRemapper.java index ff65d9aedcd06..cd3cc48a9b46a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/components/ClassRemapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/components/ClassRemapper.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.base/share/classes/jdk/internal/classfile/components/CodeLocalsShifter.java b/src/java.base/share/classes/jdk/internal/classfile/components/CodeLocalsShifter.java index 9fe1d31515bbc..eeb72793d8dd5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/components/CodeLocalsShifter.java +++ b/src/java.base/share/classes/jdk/internal/classfile/components/CodeLocalsShifter.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.base/share/classes/jdk/internal/classfile/components/CodeRelabeler.java b/src/java.base/share/classes/jdk/internal/classfile/components/CodeRelabeler.java index a62aa0958f671..58a35d80abc10 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/components/CodeRelabeler.java +++ b/src/java.base/share/classes/jdk/internal/classfile/components/CodeRelabeler.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.base/share/classes/jdk/internal/classfile/components/CodeStackTracker.java b/src/java.base/share/classes/jdk/internal/classfile/components/CodeStackTracker.java index a1dac8286e305..db102881d7782 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/components/CodeStackTracker.java +++ b/src/java.base/share/classes/jdk/internal/classfile/components/CodeStackTracker.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java index 5069f8bbc08ea..9107eab0cb756 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java index 12ea318684c42..f64e08abf3ef3 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeLocalsShifterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeLocalsShifterImpl.java index 66d170e517899..6aa1482b6d2ec 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeLocalsShifterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeLocalsShifterImpl.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java index 47fce6e3429f9..7c3a723292696 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeStackTrackerImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeStackTrackerImpl.java index c382c559a2eac..e4f167052421b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeStackTrackerImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeStackTrackerImpl.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java index e753580afbd18..e6e20245c9416 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index 575808d13b0bd..404bce10b5571 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 @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java index 5f3716ab76aac..fa4e7ab6d1dd9 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.base/share/classes/jdk/internal/foreign/CABI.java b/src/java.base/share/classes/jdk/internal/foreign/CABI.java index eee4ae6745790..d376a19633397 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/CABI.java +++ b/src/java.base/share/classes/jdk/internal/foreign/CABI.java @@ -41,6 +41,7 @@ public enum CABI { WIN_AARCH_64, LINUX_PPC_64_LE, LINUX_RISCV_64, + LINUX_S390, FALLBACK, UNSUPPORTED; @@ -81,7 +82,11 @@ private static CABI computeCurrent() { if (OperatingSystem.isLinux()) { return LINUX_RISCV_64; } - } + } else if (arch.equals("s390x")) { + if (OperatingSystem.isLinux()) { + return LINUX_S390; + } + } } else if (FallbackLinker.isSupported()) { return FALLBACK; // fallback linker } 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 b5eb1029ff5ef..8a322cdcf7a89 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 @@ -32,6 +32,7 @@ import jdk.internal.foreign.abi.fallback.FallbackLinker; import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64leLinker; import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker; +import jdk.internal.foreign.abi.s390.linux.LinuxS390Linker; import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker; import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker; import jdk.internal.foreign.layout.AbstractLayout; @@ -60,7 +61,8 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch64Linker, MacOsAArch64Linker, SysVx64Linker, WindowsAArch64Linker, Windowsx64Linker, LinuxPPC64leLinker, - LinuxRISCV64Linker, FallbackLinker { + LinuxRISCV64Linker, LinuxS390Linker, + FallbackLinker { public interface UpcallStubFactory { MemorySegment makeStub(MethodHandle target, Arena arena); 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 1e41724554346..92d10a1dbdfec 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 @@ -35,6 +35,7 @@ import jdk.internal.foreign.abi.fallback.FallbackLinker; import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64leLinker; import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker; +import jdk.internal.foreign.abi.s390.linux.LinuxS390Linker; import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker; import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker; import jdk.internal.vm.annotation.ForceInline; @@ -242,6 +243,7 @@ public static Linker getSystemLinker() { case WIN_AARCH_64 -> WindowsAArch64Linker.getInstance(); case LINUX_PPC_64_LE -> LinuxPPC64leLinker.getInstance(); case LINUX_RISCV_64 -> LinuxRISCV64Linker.getInstance(); + case LINUX_S390 -> LinuxS390Linker.getInstance(); case FALLBACK -> FallbackLinker.getInstance(); case UNSUPPORTED -> throw new UnsupportedOperationException("Platform does not support native linker"); }; diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java index 6ba81263d5c33..aa0d6151f8b22 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java @@ -36,14 +36,23 @@ private LibFallback() {} static final boolean SUPPORTED = tryLoadLibrary(); + @SuppressWarnings("removal") private static boolean tryLoadLibrary() { - try { - System.loadLibrary("fallbackLinker"); - } catch (UnsatisfiedLinkError ule) { - return false; - } - init(); - return true; + return java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction<>() { + public Boolean run() { + try { + System.loadLibrary("fallbackLinker"); + } catch (UnsatisfiedLinkError ule) { + return false; + } + if (!init()) { + // library failed to initialize. Do not silently mark as unsupported + throw new ExceptionInInitializerError("Fallback library failed to initialize"); + } + return true; + } + }); } static int defaultABI() { return NativeConstants.DEFAULT_ABI; } @@ -189,7 +198,7 @@ private static void checkStatus(int code) { } } - private static native void init(); + private static native boolean init(); private static native long sizeofCif(); diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/s390/S390Architecture.java b/src/java.base/share/classes/jdk/internal/foreign/abi/s390/S390Architecture.java new file mode 100644 index 0000000000000..bbafef2f3dc76 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/s390/S390Architecture.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023 IBM Corp. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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.abi.s390; + +import jdk.internal.foreign.abi.ABIDescriptor; +import jdk.internal.foreign.abi.Architecture; +import jdk.internal.foreign.abi.StubLocations; +import jdk.internal.foreign.abi.VMStorage; + +public final class S390Architecture implements Architecture { + public static final Architecture INSTANCE = new S390Architecture(); + + // Needs to be consistent with vmstorage_s390.hpp. + public static final short REG32_MASK = 0b0000_0000_0000_0001; + public static final short REG64_MASK = 0b0000_0000_0000_0011; + + private static final int INTEGER_REG_SIZE = 8; + private static final int FLOAT_REG_SIZE = 8; + private static final int STACK_SLOT_SIZE = 8; + + // Suppresses default constructor, ensuring non-instantiability. + private S390Architecture() { + } + + @Override + public boolean isStackType(int cls) { + return cls == StorageType.STACK; + } + + @Override + public int typeSize(int cls) { + switch (cls) { + case StorageType.INTEGER: + return INTEGER_REG_SIZE; + case StorageType.FLOAT: + return FLOAT_REG_SIZE; + // STACK is deliberately omitted + } + + throw new IllegalArgumentException("Invalid Storage Class: " + cls); + } + + public interface StorageType { + byte INTEGER = 0; + byte FLOAT = 1; + byte STACK = 2; + byte PLACEHOLDER = 3; + } + + public static class Regs { // break circular dependency + public static final VMStorage r0 = integerRegister(0); + public static final VMStorage r1 = integerRegister(1); + public static final VMStorage r2 = integerRegister(2); + public static final VMStorage r3 = integerRegister(3); + public static final VMStorage r4 = integerRegister(4); + public static final VMStorage r5 = integerRegister(5); + public static final VMStorage r6 = integerRegister(6); + public static final VMStorage r7 = integerRegister(7); + public static final VMStorage r8 = integerRegister(8); + public static final VMStorage r9 = integerRegister(9); + public static final VMStorage r10 = integerRegister(10); + public static final VMStorage r11 = integerRegister(11); + public static final VMStorage r12 = integerRegister(12); + public static final VMStorage r13 = integerRegister(13); + public static final VMStorage r14 = integerRegister(14); + public static final VMStorage r15 = integerRegister(15); + + public static final VMStorage f0 = floatRegister(0); + public static final VMStorage f1 = floatRegister(1); + public static final VMStorage f2 = floatRegister(2); + public static final VMStorage f3 = floatRegister(3); + public static final VMStorage f4 = floatRegister(4); + public static final VMStorage f5 = floatRegister(5); + public static final VMStorage f6 = floatRegister(6); + public static final VMStorage f7 = floatRegister(7); + public static final VMStorage f8 = floatRegister(8); + public static final VMStorage f9 = floatRegister(9); + public static final VMStorage f10 = floatRegister(10); + public static final VMStorage f11 = floatRegister(11); + public static final VMStorage f12 = floatRegister(12); + public static final VMStorage f13 = floatRegister(13); + public static final VMStorage f14 = floatRegister(14); + public static final VMStorage f15 = floatRegister(15); + } + + private static VMStorage integerRegister(int index) { + return new VMStorage(StorageType.INTEGER, REG64_MASK, index, "r" + index); + } + + private static VMStorage floatRegister(int index) { + return new VMStorage(StorageType.FLOAT, REG64_MASK, index, "f" + index); + } + + public static VMStorage stackStorage(short size, int byteOffset) { + return new VMStorage(StorageType.STACK, size, byteOffset); + } + + public static ABIDescriptor abiFor(VMStorage[] inputIntRegs, + VMStorage[] inputFloatRegs, + VMStorage[] outputIntRegs, + VMStorage[] outputFloatRegs, + VMStorage[] volatileIntRegs, + VMStorage[] volatileFloatRegs, + int stackAlignment, + int shadowSpace, + VMStorage scratch1, VMStorage scratch2) { + return new ABIDescriptor( + INSTANCE, + new VMStorage[][] { + inputIntRegs, + inputFloatRegs, + }, + new VMStorage[][] { + outputIntRegs, + outputFloatRegs, + }, + new VMStorage[][] { + volatileIntRegs, + volatileFloatRegs, + }, + stackAlignment, + shadowSpace, + scratch1, scratch2, + StubLocations.TARGET_ADDRESS.storage(StorageType.PLACEHOLDER), + StubLocations.RETURN_BUFFER.storage(StorageType.PLACEHOLDER), + StubLocations.CAPTURED_STATE_BUFFER.storage(StorageType.PLACEHOLDER)); + } +} diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger.java new file mode 100644 index 0000000000000..84392e4508991 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger.java @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023 IBM Corp. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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.abi.s390.linux; + +import java.lang.foreign.AddressLayout; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import jdk.internal.foreign.abi.ABIDescriptor; +import jdk.internal.foreign.abi.AbstractLinker.UpcallStubFactory; +import jdk.internal.foreign.abi.Binding; +import jdk.internal.foreign.abi.CallingSequence; +import jdk.internal.foreign.abi.CallingSequenceBuilder; +import jdk.internal.foreign.abi.DowncallLinker; +import jdk.internal.foreign.abi.LinkerOptions; +import jdk.internal.foreign.abi.UpcallLinker; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.foreign.abi.VMStorage; +import jdk.internal.foreign.Utils; + +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static jdk.internal.foreign.abi.s390.linux.TypeClass.*; +import static jdk.internal.foreign.abi.s390.S390Architecture.*; +import static jdk.internal.foreign.abi.s390.S390Architecture.Regs.*; + +/** + * For the S390 C ABI specifically, this class uses CallingSequenceBuilder + * to translate a C FunctionDescriptor into a CallingSequence, which can then be turned into a MethodHandle. + * + * This includes taking care of synthetic arguments like pointers to return buffers for 'in-memory' returns. + */ +public class LinuxS390CallArranger { + + private static final int STACK_SLOT_SIZE = 8; + public static final int MAX_REGISTER_ARGUMENTS = 5; + public static final int MAX_FLOAT_REGISTER_ARGUMENTS = 4; + + private static final ABIDescriptor CLinux = abiFor( + new VMStorage[] { r2, r3, r4, r5, r6, }, // GP input + new VMStorage[] { f0, f2, f4, f6 }, // FP input + new VMStorage[] { r2, }, // GP output + new VMStorage[] { f0, }, // FP output + new VMStorage[] { r0, r1, r2, r3, r4, r5, r14 }, // volatile GP + new VMStorage[] { f1, f3, f5, f7 }, // volatile FP (excluding argument registers) + 8, // Stack is always 8 byte aligned on S390 + 160, // ABI header + r0, r1 // scratch reg r0 & r1 + ); + + public record Bindings(CallingSequence callingSequence, boolean isInMemoryReturn) {} + + public static Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) { + return getBindings(mt, cDesc, forUpcall, LinkerOptions.empty()); + } + + public static Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall, LinkerOptions options) { + CallingSequenceBuilder csb = new CallingSequenceBuilder(CLinux, forUpcall, options); + + BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true); + BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false) : new BoxBindingCalculator(false); + + boolean returnInMemory = isInMemoryReturn(cDesc.returnLayout()); + if (returnInMemory) { + Class carrier = MemorySegment.class; + MemoryLayout layout =SharedUtils.C_POINTER; + csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout)); + } else if (cDesc.returnLayout().isPresent()) { + Class carrier = mt.returnType(); + MemoryLayout layout = cDesc.returnLayout().get(); + csb.setReturnBindings(carrier, layout, retCalc.getBindings(carrier, layout)); + } + + for (int i = 0; i < mt.parameterCount(); i++) { + Class carrier = mt.parameterType(i); + MemoryLayout layout = cDesc.argumentLayouts().get(i); + csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout)); + } + + return new Bindings(csb.build(), returnInMemory); + } + + public static MethodHandle arrangeDowncall(MethodType mt, FunctionDescriptor cDesc, LinkerOptions options) { + Bindings bindings = getBindings(mt, cDesc, false, options); + + MethodHandle handle = new DowncallLinker(CLinux, bindings.callingSequence).getBoundMethodHandle(); + + if (bindings.isInMemoryReturn) { + handle = SharedUtils.adaptDowncallForIMR(handle, cDesc, bindings.callingSequence); + } + + return handle; + } + + public static UpcallStubFactory arrangeUpcall(MethodType mt, FunctionDescriptor cDesc, LinkerOptions options) { + Bindings bindings = getBindings(mt, cDesc, true, options); + + final boolean dropReturn = true; /* drop return, since we don't have bindings for it */ + return SharedUtils.arrangeUpcallHelper(mt, bindings.isInMemoryReturn, dropReturn, CLinux, + bindings.callingSequence); + } + + private static boolean isInMemoryReturn(Optional returnLayout) { + return returnLayout + .filter(layout -> layout instanceof GroupLayout) + .isPresent(); + } + + static class StorageCalculator { + private final boolean forArguments; + + private final int[] nRegs = new int[] { 0, 0 }; + private long stackOffset = 0; + + public StorageCalculator(boolean forArguments) { + this.forArguments = forArguments; + } + + VMStorage stackAlloc(long size, long alignment) { + long alignedStackOffset = Utils.alignUp(stackOffset, alignment); + + short encodedSize = (short) size; + assert (encodedSize & 0xFFFF) == size; + + VMStorage storage = stackStorage(encodedSize, (int) alignedStackOffset); + stackOffset = alignedStackOffset + size; + return storage; + } + + VMStorage regAlloc(int type) { + int gpRegCnt = (type == StorageType.INTEGER) ? 1 : 0; + int fpRegCnt = (type == StorageType.FLOAT) ? 1 : 0; + + // Use stack if not enough registers available. + if ((type == StorageType.FLOAT && (nRegs[StorageType.FLOAT] + fpRegCnt) > MAX_FLOAT_REGISTER_ARGUMENTS) + || (type == StorageType.INTEGER && (nRegs[StorageType.INTEGER] + gpRegCnt) > MAX_REGISTER_ARGUMENTS)) return null; + + VMStorage[] source = (forArguments ? CLinux.inputStorage : CLinux.outputStorage)[type]; + VMStorage result = source[nRegs[type]]; + + nRegs[StorageType.INTEGER] += gpRegCnt; + nRegs[StorageType.FLOAT] += fpRegCnt; + return result; + + } + VMStorage getStorage(int type, boolean is32Bit) { + VMStorage reg = regAlloc(type); + if (reg != null) { + if (is32Bit) { + reg = new VMStorage(reg.type(), REG32_MASK, reg.indexOrOffset()); + } + return reg; + } + VMStorage stack; + if (is32Bit) { + stackAlloc(4, STACK_SLOT_SIZE); // Skip first half of stack slot. + stack = stackAlloc(4, 4); + } else + stack = stackAlloc(8, STACK_SLOT_SIZE); + + return stack; + } + } + + abstract static class BindingCalculator { + protected final StorageCalculator storageCalculator; + + protected BindingCalculator(boolean forArguments) { + this.storageCalculator = new LinuxS390CallArranger.StorageCalculator(forArguments); + } + + abstract List getBindings(Class carrier, MemoryLayout layout); + } + + // Compute recipe for transferring arguments / return values to C from Java. + static class UnboxBindingCalculator extends BindingCalculator { + UnboxBindingCalculator(boolean forArguments) { + super(forArguments); + } + + @Override + List getBindings(Class carrier, MemoryLayout layout) { + TypeClass argumentClass = TypeClass.classifyLayout(layout); + Binding.Builder bindings = Binding.builder(); + switch (argumentClass) { + case STRUCT_REGISTER -> { + assert carrier == MemorySegment.class; + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + Class type = SharedUtils.primitiveCarrierForSize(layout.byteSize(), false); + bindings.bufferLoad(0, type) + .vmStore(storage, type); + } + case STRUCT_SFA -> { + assert carrier == MemorySegment.class; + VMStorage storage = storageCalculator.getStorage(StorageType.FLOAT, layout.byteSize() == 4); + Class type = SharedUtils.primitiveCarrierForSize(layout.byteSize(), true); + bindings.bufferLoad(0, type) + .vmStore(storage, type); + } + case STRUCT_REFERENCE -> { + assert carrier == MemorySegment.class; + bindings.copy(layout) + .unboxAddress(); + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + bindings.vmStore(storage, long.class); + } + case POINTER -> { + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + bindings.unboxAddress() + .vmStore(storage, long.class); + } + case INTEGER -> { + // ABI requires all int types to get extended to 64 bit. + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + bindings.vmStore(storage, carrier); + } + case FLOAT -> { + VMStorage storage = storageCalculator.getStorage(StorageType.FLOAT, carrier == float.class); + bindings.vmStore(storage, carrier); + } + default -> throw new UnsupportedOperationException("Unhandled class " + argumentClass); + } + return bindings.build(); + } + } + + // Compute recipe for transferring arguments / return values from C to Java. + static class BoxBindingCalculator extends BindingCalculator { + BoxBindingCalculator(boolean forArguments) { + super(forArguments); + } + + @Override + List getBindings(Class carrier, MemoryLayout layout) { + TypeClass argumentClass = TypeClass.classifyLayout(layout); + Binding.Builder bindings = Binding.builder(); + switch (argumentClass) { + case STRUCT_REGISTER -> { + assert carrier == MemorySegment.class; + bindings.allocate(layout) + .dup(); + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + Class type = SharedUtils.primitiveCarrierForSize(layout.byteSize(), false); + bindings.vmLoad(storage, type) + .bufferStore(0, type); + } + case STRUCT_SFA -> { + assert carrier == MemorySegment.class; + bindings.allocate(layout) + .dup(); + VMStorage storage = storageCalculator.getStorage(StorageType.FLOAT, layout.byteSize() == 4); + Class type = SharedUtils.primitiveCarrierForSize(layout.byteSize(), true); + bindings.vmLoad(storage, type) + .bufferStore(0, type); + } + case STRUCT_REFERENCE -> { + assert carrier == MemorySegment.class; + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + bindings.vmLoad(storage, long.class) + .boxAddress(layout); + } + case POINTER -> { + AddressLayout addressLayout = (AddressLayout) layout; + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + bindings.vmLoad(storage, long.class) + .boxAddressRaw(Utils.pointeeByteSize(addressLayout), Utils.pointeeByteAlign(addressLayout)); + } + case INTEGER -> { + // We could use carrier != long.class for BoxBindingCalculator, but C always uses 64 bit slots. + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + bindings.vmLoad(storage, carrier); + } + case FLOAT -> { + VMStorage storage = storageCalculator.getStorage(StorageType.FLOAT, carrier == float.class); + bindings.vmLoad(storage, carrier); + } + default -> throw new UnsupportedOperationException("Unhandled class " + argumentClass); + } + return bindings.build(); + } + } +} diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/LinuxS390Linker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/LinuxS390Linker.java new file mode 100644 index 0000000000000..ac004b9e1e0eb --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/LinuxS390Linker.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023 IBM Corp. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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.abi.s390.linux; + +import jdk.internal.foreign.abi.AbstractLinker; +import jdk.internal.foreign.abi.LinkerOptions; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.nio.ByteOrder; + +public final class LinuxS390Linker extends AbstractLinker { + + public static LinuxS390Linker getInstance() { + final class Holder { + private static final LinuxS390Linker INSTANCE = new LinuxS390Linker(); + } + + return Holder.INSTANCE; + } + + private LinuxS390Linker() { + // Ensure there is only one instance + } + + @Override + protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) { + return LinuxS390CallArranger.arrangeDowncall(inferredMethodType, function, options); + } + + @Override + protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) { + return LinuxS390CallArranger.arrangeUpcall(targetType, function, options); + } + + @Override + protected ByteOrder linkerByteOrder() { + return ByteOrder.BIG_ENDIAN; + } +} diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/TypeClass.java b/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/TypeClass.java new file mode 100644 index 0000000000000..095cb2c08a8e1 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/TypeClass.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023 IBM Corp. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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.abi.s390.linux; + +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.ValueLayout; +import java.util.List; +import java.util.ArrayList; + +public enum TypeClass { + STRUCT_REGISTER, + STRUCT_SFA, // Single Float Aggregate + STRUCT_REFERENCE, + POINTER, + INTEGER, + FLOAT; + + private static TypeClass classifyValueType(ValueLayout type) { + Class carrier = type.carrier(); + if (carrier == boolean.class || carrier == byte.class || carrier == char.class || + carrier == short.class || carrier == int.class || carrier == long.class) { + return INTEGER; + } else if (carrier == float.class || carrier == double.class) { + return FLOAT; + } else if (carrier == MemorySegment.class) { + return POINTER; + } else { + throw new IllegalStateException("Cannot get here: " + carrier.getName()); + } + } + + private static boolean isRegisterAggregate(MemoryLayout type) { + long byteSize = type.byteSize(); + if (byteSize > 8 || byteSize == 3 || byteSize == 5 || byteSize == 6 || byteSize == 7) + return false; + return true; + } + + static List scalarLayouts(GroupLayout gl) { + List out = new ArrayList<>(); + scalarLayoutsInternal(out, gl); + return out; + } + + private static void scalarLayoutsInternal(List out, GroupLayout gl) { + for (MemoryLayout member : gl.memberLayouts()) { + if (member instanceof GroupLayout memberGl) { + scalarLayoutsInternal(out, memberGl); + } else if (member instanceof SequenceLayout memberSl) { + for (long i = 0; i < memberSl.elementCount(); i++) { + out.add(memberSl.elementLayout()); + } + } else { + // padding or value layouts + out.add(member); + } + } + } + + static boolean isSingleFloatAggregate(MemoryLayout type) { + List scalarLayouts = scalarLayouts((GroupLayout) type); + + final int numElements = scalarLayouts.size(); + if (numElements > 1 || numElements == 0) + return false; + + MemoryLayout baseType = scalarLayouts.get(0); + + if (!(baseType instanceof ValueLayout)) + return false; + + TypeClass baseArgClass = classifyValueType((ValueLayout) baseType); + if (baseArgClass != FLOAT) + return false; + + return true; + } + + private static TypeClass classifyStructType(MemoryLayout layout) { + + if (!isRegisterAggregate(layout)) { + return TypeClass.STRUCT_REFERENCE; + } + + if (isSingleFloatAggregate(layout)) { + return TypeClass.STRUCT_SFA; + } + return TypeClass.STRUCT_REGISTER; + } + + public static TypeClass classifyLayout(MemoryLayout type) { + if (type instanceof ValueLayout) { + return classifyValueType((ValueLayout) type); + } else if (type instanceof GroupLayout) { + return classifyStructType(type); + } else { + throw new IllegalArgumentException("Unsupported layout: " + type); + } + } +} diff --git a/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java b/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java index 1161e9c846497..cdfdef9fbf90e 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java @@ -4595,7 +4595,7 @@ public static void reorderVisually(byte[] levels, objectStart + " is out of range 0 to " + (objects.length-1)); } - if (0 > count || objects.length < (objectStart+count)) { + if (0 > count || objects.length - count < objectStart) { throw new IllegalArgumentException("Value count " + count + " is less than zero, or objectStart + count" + " is beyond objects length " + objects.length); 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 65d9177dddb31..a75ff58208558 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, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -119,8 +119,17 @@ public char[] readPassword(String fmt, Object ... args) { else ioe.addSuppressed(x); } - if (ioe != null) + if (ioe != null) { + Arrays.fill(passwd, ' '); + try { + if (reader instanceof LineReader lr) { + lr.zeroOut(); + } + } catch (IOException x) { + // ignore + } throw ioe; + } } pw.println(); } @@ -195,6 +204,9 @@ else if (rcb[len-1] == '\n') { System.arraycopy(rcb, 0, b, 0, len); if (zeroOut) { Arrays.fill(rcb, 0, len, ' '); + if (reader instanceof LineReader lr) { + lr.zeroOut(); + } } } return b; @@ -228,6 +240,11 @@ class LineReader extends Reader { nextChar = nChars = 0; leftoverLF = false; } + public void zeroOut() throws IOException { + if (in instanceof StreamDecoder sd) { + sd.fillZeroToPosition(); + } + } public void close () {} public boolean ready() throws IOException { //in.ready synchronizes on readLock already diff --git a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java index 2dc6b001e1b3c..bf123511f5814 100644 --- a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java +++ b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java @@ -53,11 +53,9 @@ import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.NoSuchElementException; import java.util.Properties; -import java.util.Set; import java.util.StringTokenizer; import java.util.jar.JarFile; import java.util.zip.CRC32; @@ -209,7 +207,9 @@ public URLClassPath(URL[] urls, @SuppressWarnings("removal") AccessControlContex this.unopenedUrls = unopenedUrls; this.path = path; - this.jarHandler = null; + // the application class loader uses the built-in protocol handler to avoid protocol + // handler lookup when opening JAR files on the class path. + this.jarHandler = new sun.net.www.protocol.jar.Handler(); this.acc = null; } diff --git a/src/java.base/share/classes/jdk/internal/logger/BootstrapLogger.java b/src/java.base/share/classes/jdk/internal/logger/BootstrapLogger.java index 3c99d832b0afe..f351b52968d8b 100644 --- a/src/java.base/share/classes/jdk/internal/logger/BootstrapLogger.java +++ b/src/java.base/share/classes/jdk/internal/logger/BootstrapLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,6 @@ import java.util.function.Supplier; import java.lang.System.LoggerFinder; import java.lang.System.Logger; -import java.lang.System.Logger.Level; import java.lang.ref.WeakReference; import java.util.Objects; import java.util.concurrent.ExecutionException; @@ -227,9 +226,19 @@ static void flush() { // The accessor in which this logger is temporarily set. final LazyLoggerAccessor holder; + // tests whether the logger is invoked by the loading thread before + // the LoggerFinder is loaded; can be null; + final BooleanSupplier isLoadingThread; + + // returns true if the logger is invoked by the loading thread before the + // LoggerFinder service is loaded + boolean isLoadingThread() { + return isLoadingThread != null && isLoadingThread.getAsBoolean(); + } - BootstrapLogger(LazyLoggerAccessor holder) { + BootstrapLogger(LazyLoggerAccessor holder, BooleanSupplier isLoadingThread) { this.holder = holder; + this.isLoadingThread = isLoadingThread; } // Temporary data object storing log events @@ -505,14 +514,15 @@ static LogEvent valueOf(BootstrapLogger bootstrap, PlatformLogger.Level level, static void log(LogEvent log, PlatformLogger.Bridge logger) { final SecurityManager sm = System.getSecurityManager(); if (sm == null || log.acc == null) { - log.log(logger); + BootstrapExecutors.submit(() -> log.log(logger)); } else { // not sure we can actually use lambda here. We may need to create // an anonymous class. Although if we reach here, then it means // the VM is booted. - AccessController.doPrivileged((PrivilegedAction) () -> { - log.log(logger); return null; - }, log.acc); + BootstrapExecutors.submit(() -> + AccessController.doPrivileged((PrivilegedAction) () -> { + log.log(logger); return null; + }, log.acc)); } } @@ -559,8 +569,9 @@ public String getName() { * @return true if the VM is still bootstrapping. */ boolean checkBootstrapping() { - if (isBooted()) { + if (isBooted() && !isLoadingThread()) { BootstrapExecutors.flush(); + holder.getConcreteLogger(this); return false; } return true; @@ -935,10 +946,16 @@ private static boolean useSurrogateLoggers() { // - the logging backend is a custom backend // - the logging backend is JUL, there is no custom config, // and the LogManager has not been initialized yet. - public static synchronized boolean useLazyLoggers() { - return !BootstrapLogger.isBooted() - || DetectBackend.detectedBackend == LoggingBackend.CUSTOM - || useSurrogateLoggers(); + public static boolean useLazyLoggers() { + // Note: avoid triggering the initialization of the DetectBackend class + // while holding the BootstrapLogger class monitor + if (!BootstrapLogger.isBooted() || + DetectBackend.detectedBackend == LoggingBackend.CUSTOM) { + return true; + } + synchronized (BootstrapLogger.class) { + return useSurrogateLoggers(); + } } // Called by LazyLoggerAccessor. This method will determine whether @@ -946,9 +963,9 @@ public static synchronized boolean useLazyLoggers() { // a SurrogateLogger (if JUL is the default backend and there // is no custom JUL configuration and LogManager is not yet initialized), // or a logger returned by the loaded LoggerFinder (all other cases). - static Logger getLogger(LazyLoggerAccessor accessor) { - if (!BootstrapLogger.isBooted()) { - return new BootstrapLogger(accessor); + static Logger getLogger(LazyLoggerAccessor accessor, BooleanSupplier isLoading) { + if (!BootstrapLogger.isBooted() || isLoading != null && isLoading.getAsBoolean()) { + return new BootstrapLogger(accessor, isLoading); } else { if (useSurrogateLoggers()) { // JUL is the default backend, there is no custom configuration, @@ -964,6 +981,12 @@ static Logger getLogger(LazyLoggerAccessor accessor) { } } + // trigger class initialization outside of holding lock + static void ensureBackendDetected() { + assert VM.isBooted() : "VM is not booted"; + // triggers detection of the backend + var backend = DetectBackend.detectedBackend; + } // If the backend is JUL, and there is no custom configuration, and // nobody has attempted to call LogManager.getLogManager() yet, then diff --git a/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java b/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java index c7f24a70b5962..2c62496287668 100644 --- a/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java +++ b/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,9 @@ import java.lang.System.Logger; import java.lang.ref.WeakReference; import java.util.Objects; +import java.util.function.BooleanSupplier; + +import jdk.internal.logger.LoggerFinderLoader.TemporaryLoggerFinder; import jdk.internal.misc.VM; import sun.util.logging.PlatformLogger; @@ -110,6 +113,9 @@ static final class LazyLoggerAccessor implements LoggerAccessor { // We need to pass the actual caller module when creating the logger. private final WeakReference moduleRef; + // whether this is the loading thread, can be null + private final BooleanSupplier isLoadingThread; + // The name of the logger that will be created lazyly final String name; // The plain logger SPI object - null until it is accessed for the @@ -122,16 +128,24 @@ static final class LazyLoggerAccessor implements LoggerAccessor { private LazyLoggerAccessor(String name, LazyLoggerFactories factories, Module module) { + this(name, factories, module, null); + } + + private LazyLoggerAccessor(String name, + LazyLoggerFactories factories, + Module module, BooleanSupplier isLoading) { + this(Objects.requireNonNull(name), Objects.requireNonNull(factories), - Objects.requireNonNull(module), null); + Objects.requireNonNull(module), isLoading, null); } private LazyLoggerAccessor(String name, LazyLoggerFactories factories, - Module module, Void unused) { + Module module, BooleanSupplier isLoading, Void unused) { this.name = name; this.factories = factories; this.moduleRef = new WeakReference<>(module); + this.isLoadingThread = isLoading; } /** @@ -162,7 +176,7 @@ public Logger wrapped() { // BootstrapLogger has the logic to decide whether to invoke the // SPI or use a temporary (BootstrapLogger or SimpleConsoleLogger) // logger. - wrapped = BootstrapLogger.getLogger(this); + wrapped = BootstrapLogger.getLogger(this, isLoadingThread); synchronized(this) { // if w has already been in between, simply drop 'wrapped'. setWrappedIfNotSet(wrapped); @@ -194,7 +208,7 @@ public PlatformLogger.Bridge platform() { // BootstrapLogger has the logic to decide whether to invoke the // SPI or use a temporary (BootstrapLogger or SimpleConsoleLogger) // logger. - final Logger wrapped = BootstrapLogger.getLogger(this); + final Logger wrapped = BootstrapLogger.getLogger(this, isLoadingThread); synchronized(this) { // if w has already been set, simply drop 'wrapped'. setWrappedIfNotSet(wrapped); @@ -282,10 +296,10 @@ Logger createLogger() { * Creates a new lazy logger accessor for the named logger. The given * factories will be use when it becomes necessary to actually create * the logger. - * @param An interface that extends {@link Logger}. * @param name The logger name. * @param factories The factories that should be used to create the * wrapped logger. + * @param module The module for which the logger is being created * @return A new LazyLoggerAccessor. */ public static LazyLoggerAccessor makeAccessor(String name, @@ -340,6 +354,7 @@ private static LoggerFinder accessLoggerFinder() { prov = sm == null ? LoggerFinder.getLoggerFinder() : AccessController.doPrivileged( (PrivilegedAction)LoggerFinder::getLoggerFinder); + if (prov instanceof TemporaryLoggerFinder) return prov; provider = prov; } return prov; @@ -359,7 +374,6 @@ public Logger apply(String name, Module module) { new LazyLoggerFactories<>(loggerSupplier); - // A concrete implementation of Logger that delegates to a System.Logger, // but only creates the System.Logger instance lazily when it's used for // the first time. @@ -377,6 +391,11 @@ private JdkLazyLogger(LazyLoggerAccessor holder, Void unused) { } } + static Logger makeLazyLogger(String name, Module module, BooleanSupplier isLoading) { + final LazyLoggerAccessor holder = new LazyLoggerAccessor(name, factories, module, isLoading); + return new JdkLazyLogger(holder, null); + } + /** * Gets a logger from the LoggerFinder. Creates the actual concrete * logger. diff --git a/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java b/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java index 89ab26b8974d3..932de4ef55463 100644 --- a/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java +++ b/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package jdk.internal.logger; import java.io.FilePermission; +import java.lang.System.Logger; +import java.lang.System.LoggerFinder; import java.security.AccessController; import java.security.Permission; import java.security.PrivilegedAction; @@ -32,6 +34,9 @@ import java.util.Locale; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; +import java.util.function.BooleanSupplier; + +import jdk.internal.vm.annotation.Stable; import sun.security.util.SecurityConstants; import sun.security.action.GetBooleanAction; import sun.security.action.GetPropertyAction; @@ -65,13 +70,28 @@ private LoggerFinderLoader() { throw new InternalError("LoggerFinderLoader cannot be instantiated"); } - + // record the loadingThread while loading the backend + static volatile Thread loadingThread; // Return the loaded LoggerFinder, or load it if not already loaded. private static System.LoggerFinder service() { if (service != null) return service; + // ensure backend is detected before attempting to load the finder + BootstrapLogger.ensureBackendDetected(); synchronized(lock) { if (service != null) return service; - service = loadLoggerFinder(); + Thread currentThread = Thread.currentThread(); + if (loadingThread == currentThread) { + // recursive attempt to load the backend while loading the backend + // use a temporary logger finder that returns special BootstrapLogger + // which will wait until loading is finished + return TemporaryLoggerFinder.INSTANCE; + } + loadingThread = currentThread; + try { + service = loadLoggerFinder(); + } finally { + loadingThread = null; + } } // Since the LoggerFinder is already loaded - we can stop using // temporary loggers. @@ -79,6 +99,12 @@ private static System.LoggerFinder service() { return service; } + // returns true if called by the thread that loads the LoggerFinder, while + // loading the LoggerFinder. + static boolean isLoadingThread() { + return loadingThread != null && loadingThread == Thread.currentThread(); + } + // Get configuration error policy private static ErrorPolicy configurationErrorPolicy() { String errorPolicy = @@ -117,6 +143,34 @@ private static Iterator findLoggerFinderProviders() { return iterator; } + public static final class TemporaryLoggerFinder extends LoggerFinder { + private TemporaryLoggerFinder() {} + @Stable + private LoggerFinder loadedService; + + private static final BooleanSupplier isLoadingThread = new BooleanSupplier() { + @Override + public boolean getAsBoolean() { + return LoggerFinderLoader.isLoadingThread(); + } + }; + private static final TemporaryLoggerFinder INSTANCE = new TemporaryLoggerFinder(); + + @Override + public Logger getLogger(String name, Module module) { + if (loadedService == null) { + loadedService = service; + if (loadedService == null) { + return LazyLoggers.makeLazyLogger(name, module, isLoadingThread); + } + } + assert loadedService != null; + assert !LoggerFinderLoader.isLoadingThread(); + assert loadedService != this; + return LazyLoggers.getLogger(name, module); + } + } + // Loads the LoggerFinder using ServiceLoader. If no LoggerFinder // is found returns the default (possibly JUL based) implementation private static System.LoggerFinder loadLoggerFinder() { diff --git a/src/java.base/share/classes/jdk/internal/util/Architecture.java b/src/java.base/share/classes/jdk/internal/util/Architecture.java index 3d68426ce3dc3..5c86190274378 100644 --- a/src/java.base/share/classes/jdk/internal/util/Architecture.java +++ b/src/java.base/share/classes/jdk/internal/util/Architecture.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -23,6 +25,8 @@ package jdk.internal.util; import jdk.internal.vm.annotation.ForceInline; + +import java.nio.ByteOrder; import java.util.Locale; /** @@ -33,19 +37,83 @@ * architecture values. */ public enum Architecture { - OTHER, // An unknown architecture not specifically named - X64, // Represents AMD64 and X86_64 - X86, - AARCH64, - ARM, - RISCV64, - LOONGARCH64, - S390, - PPC64, - MIPSEL, - MIPS64EL + /* + * An unknown architecture not specifically named. + * The addrSize and ByteOrder values are those of the current architecture. + */ + AARCH64(64, ByteOrder.LITTLE_ENDIAN), + ARM(32, ByteOrder.LITTLE_ENDIAN), + LOONGARCH64(64, ByteOrder.LITTLE_ENDIAN), + MIPSEL(32, ByteOrder.LITTLE_ENDIAN), + MIPS64EL(64, ByteOrder.LITTLE_ENDIAN), + OTHER(is64bit() ? 64 : 32, ByteOrder.nativeOrder()), + PPC(32, ByteOrder.BIG_ENDIAN), + PPC64(64, ByteOrder.BIG_ENDIAN), + PPC64LE(64, ByteOrder.LITTLE_ENDIAN), + RISCV64(64, ByteOrder.LITTLE_ENDIAN), + S390(64, ByteOrder.BIG_ENDIAN), + SPARCV9(64, ByteOrder.BIG_ENDIAN), + X86(32, ByteOrder.LITTLE_ENDIAN), + X64(64, ByteOrder.LITTLE_ENDIAN), // Represents AMD64 and X86_64 ; + private final int addrSize; + private final ByteOrder byteOrder; + + /** + * Construct an Architecture with number of address bits and byte order. + * @param addrSize number of address bits, typically 64 or 32 + * @param byteOrder the byte order, big-endian or little-endian + */ + Architecture(int addrSize, ByteOrder byteOrder) { + this.addrSize = addrSize; + this.byteOrder = byteOrder; + } + + /** + * {@return the number of address bits, typically 64 or 32} + */ + public int addressSize() { + return addrSize; + } + + /** + * {@return the byte order, {@link ByteOrder#BIG_ENDIAN} or {@link ByteOrder#LITTLE_ENDIAN}} + */ + public ByteOrder byteOrder() { + return byteOrder; + } + + /** + * {@return the Architecture by name or an alias for the architecture} + * The names are mapped to upper case before mapping to an Architecture. + * @param archName an Architecture name or alias for the architecture. + * @throws IllegalArgumentException if the name is not an alias or an Architecture name + */ + public static Architecture lookupByName(String archName) { + archName = archName.toUpperCase(Locale.ROOT); // normalize to uppercase + return switch (archName) { + case "X86_64", "AMD64" -> X64; + case "I386" -> X86; + case "S390X" -> S390; + default -> Architecture.valueOf(archName); + }; + } + + /** + * Returns the Architecture of the built architecture. + * Build time names are mapped to respective uppercase enum values. + * Names not recognized are mapped to Architecture.OTHER. + */ + private static Architecture initArch(String archName) { + try { + return lookupByName(archName); + } catch (IllegalArgumentException ile) { + return Architecture.OTHER; + } + } + + // Initialize the architecture by mapping aliases and names to the enum values. private static Architecture CURRENT_ARCH = initArch(PlatformProps.CURRENT_ARCH_STRING); /** @@ -89,14 +157,29 @@ public static boolean isS390() { } /** - * {@return {@code true} if the current architecture is PPC64} - * Use {@link #isLittleEndian()} to determine big or little endian. + * {@return {@code true} if the current architecture is PPC, big-endian} + */ + @ForceInline + public static boolean isPPC() { + return PlatformProps.TARGET_ARCH_IS_PPC; + } + + /** + * {@return {@code true} if the current architecture is PPC64, big-endian} */ @ForceInline public static boolean isPPC64() { return PlatformProps.TARGET_ARCH_IS_PPC64; } + /** + * {@return {@code true} if the current architecture is PPC64, little-endian} + */ + @ForceInline + public static boolean isPPC64LE() { + return PlatformProps.TARGET_ARCH_IS_PPC64LE; + } + /** * {@return {@code true} if the current architecture is ARM} */ @@ -129,6 +212,14 @@ public static boolean isMIPS64EL() { return PlatformProps.TARGET_ARCH_IS_MIPS64EL; } + /** + * {@return {@code true} if the current architecture is SPARCV9} + */ + @ForceInline + public static boolean isSPARCV9() { + return PlatformProps.TARGET_ARCH_IS_SPARCV9; + } + /** * {@return the current architecture} */ @@ -151,18 +242,4 @@ public static boolean is64bit() { public static boolean isLittleEndian() { return PlatformProps.TARGET_ARCH_LITTLE_ENDIAN; } - - - /** - * Returns the Architecture of the built architecture. - * Build time names are mapped to respective uppercase enum values. - * Names not recognized are mapped to Architecture.OTHER. - */ - private static Architecture initArch(String archName) { - try { - return Architecture.valueOf(archName.toUpperCase(Locale.ROOT)); - } catch (IllegalArgumentException ile) { - return Architecture.OTHER; - } - } } diff --git a/src/java.base/share/classes/jdk/internal/util/OSVersion.java b/src/java.base/share/classes/jdk/internal/util/OSVersion.java index da82de0240e24..0f4abd8996422 100644 --- a/src/java.base/share/classes/jdk/internal/util/OSVersion.java +++ b/src/java.base/share/classes/jdk/internal/util/OSVersion.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java b/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java index 72b11269c082a..927ab682c3e83 100644 --- a/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java +++ b/src/java.base/share/classes/jdk/internal/util/OperatingSystem.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template b/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template index cd615e600dd83..9c2a2c84511fc 100644 --- a/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template +++ b/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -50,14 +52,18 @@ class PlatformProps { // Precomputed booleans for each Architecture, shared with jdk.internal.util.Architecture // The variables are named to match the Architecture value names, and // the values chosen to match the build values. - static final boolean TARGET_ARCH_IS_X64 = "@@OPENJDK_TARGET_CPU@@" == "x64"; - static final boolean TARGET_ARCH_IS_X86 = "@@OPENJDK_TARGET_CPU@@" == "x86"; static final boolean TARGET_ARCH_IS_AARCH64 = "@@OPENJDK_TARGET_CPU@@" == "aarch64"; static final boolean TARGET_ARCH_IS_ARM = "@@OPENJDK_TARGET_CPU@@" == "arm"; - static final boolean TARGET_ARCH_IS_RISCV64 = "@@OPENJDK_TARGET_CPU@@" == "riscv64"; static final boolean TARGET_ARCH_IS_LOONGARCH64 = "@@OPENJDK_TARGET_CPU@@" == "loongarch64"; - static final boolean TARGET_ARCH_IS_S390 = "@@OPENJDK_TARGET_CPU@@" == "s390"; - static final boolean TARGET_ARCH_IS_PPC64 = "@@OPENJDK_TARGET_CPU@@" == "ppc64"; static final boolean TARGET_ARCH_IS_MIPSEL = "@@OPENJDK_TARGET_CPU@@" == "mipsel"; static final boolean TARGET_ARCH_IS_MIPS64EL= "@@OPENJDK_TARGET_CPU@@" == "mips64el"; + static final boolean TARGET_ARCH_IS_PPC = "@@OPENJDK_TARGET_CPU@@" == "ppc"; + static final boolean TARGET_ARCH_IS_PPC64 = "@@OPENJDK_TARGET_CPU@@" == "ppc64"; + static final boolean TARGET_ARCH_IS_PPC64LE = "@@OPENJDK_TARGET_CPU@@" == "ppc64le"; + static final boolean TARGET_ARCH_IS_RISCV64 = "@@OPENJDK_TARGET_CPU@@" == "riscv64"; + static final boolean TARGET_ARCH_IS_S390 = "@@OPENJDK_TARGET_CPU@@" == "s390"; + static final boolean TARGET_ARCH_IS_SPARCV9 = "@@OPENJDK_TARGET_CPU@@" == "sparcv9"; + static final boolean TARGET_ARCH_IS_X86 = "@@OPENJDK_TARGET_CPU@@" == "x86"; + static final boolean TARGET_ARCH_IS_X64 = "@@OPENJDK_TARGET_CPU@@" == "x64"; + } 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 53a3e3694f1ef..d0705bc245761 100644 --- a/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java +++ b/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java @@ -24,6 +24,7 @@ */ package jdk.internal.vm; +import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -110,7 +111,8 @@ private static byte[] dumpThreadsToFile(String file, boolean okayToOverwrite, bo : new OpenOption[] { StandardOpenOption.CREATE_NEW }; String reply; try (OutputStream out = Files.newOutputStream(path, options); - PrintStream ps = new PrintStream(out, true, StandardCharsets.UTF_8)) { + BufferedOutputStream bos = new BufferedOutputStream(out); + PrintStream ps = new PrintStream(bos, false, StandardCharsets.UTF_8)) { if (json) { dumpThreadsToJson(ps); } else { @@ -132,11 +134,12 @@ private static byte[] dumpThreadsToFile(String file, boolean okayToOverwrite, bo * This method is invoked by HotSpotDiagnosticMXBean.dumpThreads. */ public static void dumpThreads(OutputStream out) { - PrintStream ps = new PrintStream(out, true, StandardCharsets.UTF_8); + BufferedOutputStream bos = new BufferedOutputStream(out); + PrintStream ps = new PrintStream(bos, false, StandardCharsets.UTF_8); try { dumpThreads(ps); } finally { - ps.flush(); + ps.flush(); // flushes underlying stream } } @@ -158,9 +161,10 @@ private static void dumpThreads(ThreadContainer container, PrintStream ps) { private static void dumpThread(Thread thread, PrintStream ps) { String suffix = thread.isVirtual() ? " virtual" : ""; - ps.format("#%d \"%s\"%s%n", thread.threadId(), thread.getName(), suffix); + ps.println("#" + thread.threadId() + " \"" + thread.getName() + "\"" + suffix); for (StackTraceElement ste : thread.getStackTrace()) { - ps.format(" %s%n", ste); + ps.print(" "); + ps.println(ste); } ps.println(); } @@ -171,11 +175,12 @@ private static void dumpThread(Thread thread, PrintStream ps) { * This method is invoked by HotSpotDiagnosticMXBean.dumpThreads. */ public static void dumpThreadsToJson(OutputStream out) { - PrintStream ps = new PrintStream(out, true, StandardCharsets.UTF_8); + BufferedOutputStream bos = new BufferedOutputStream(out); + PrintStream ps = new PrintStream(bos, false, StandardCharsets.UTF_8); try { dumpThreadsToJson(ps); } finally { - ps.flush(); + ps.flush(); // flushes underlying stream } } @@ -257,13 +262,16 @@ private static void dumpThreadsToJson(ThreadContainer container, */ private static void dumpThreadToJson(Thread thread, PrintStream out, boolean more) { out.println(" {"); - out.format(" \"tid\": \"%d\",%n", thread.threadId()); - out.format(" \"name\": \"%s\",%n", escape(thread.getName())); - out.format(" \"stack\": [%n"); + 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.format(" \"%s\"", escape(stackTrace[i].toString())); + out.print(" \""); + out.print(escape(stackTrace[i].toString())); + out.print("\""); i++; if (i < stackTrace.length) { out.println(","); diff --git a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java index 17e9c54fe94b4..af8f0b987e979 100644 --- a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -33,6 +33,7 @@ import java.lang.invoke.VarHandle; import java.lang.ref.Cleaner.Cleanable; import java.lang.reflect.Method; +import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.Inet4Address; import java.net.Inet6Address; @@ -650,114 +651,130 @@ private SocketAddress untrustedReceive(ByteBuffer dst) throws IOException { } /** - * Receives a datagram into the given buffer. + * Receives a datagram. * - * @apiNote This method is for use by the socket adaptor. The buffer is - * assumed to be trusted, meaning it is not accessible to user code. + * @apiNote This method is for use by the socket adaptor. * * @throws IllegalBlockingModeException if the channel is non-blocking * @throws SocketTimeoutException if the timeout elapses */ - SocketAddress blockingReceive(ByteBuffer dst, long nanos) throws IOException { + void blockingReceive(DatagramPacket p, long nanos) throws IOException { + Objects.requireNonNull(p); + assert nanos >= 0; + readLock.lock(); try { ensureOpen(); if (!isBlocking()) throw new IllegalBlockingModeException(); - @SuppressWarnings("removal") - SecurityManager sm = System.getSecurityManager(); - boolean connected = isConnected(); - SocketAddress sender; - do { - if (nanos > 0) { - sender = trustedBlockingReceive(dst, nanos); - } else { - sender = trustedBlockingReceive(dst); - } - // check sender when security manager set and not connected - if (sm != null && !connected) { - InetSocketAddress isa = (InetSocketAddress) sender; - try { - sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort()); - } catch (SecurityException e) { - sender = null; - } - } - } while (sender == null); - return sender; - } finally { - readLock.unlock(); - } - } - /** - * Receives a datagram into given buffer. This method is used to support - * the socket adaptor. The buffer is assumed to be trusted. - * @throws SocketTimeoutException if the timeout elapses - */ - private SocketAddress trustedBlockingReceive(ByteBuffer dst) - throws IOException - { - assert readLock.isHeldByCurrentThread() && isBlocking(); - SocketAddress sender = null; - try { - SocketAddress remote = beginRead(true, false); - configureSocketNonBlockingIfVirtualThread(); - boolean connected = (remote != null); - int n = receive(dst, connected); - while (IOStatus.okayToRetry(n) && isOpen()) { - park(Net.POLLIN); - n = receive(dst, connected); + // underlying socket needs to be non-blocking if timed receive or virtual thread + if (nanos > 0) { + configureSocketNonBlocking(); + } else { + configureSocketNonBlockingIfVirtualThread(); + nanos = Long.MAX_VALUE; } - if (n > 0 || (n == 0 && isOpen())) { - // sender address is in socket address buffer - sender = sourceSocketAddress(); + + // p.bufLength is the maximum size of the datagram that can be received + int bufLength; + synchronized (p) { + bufLength = DatagramPackets.getBufLength(p); + } + + long startNanos = System.nanoTime(); + SocketAddress sender = null; + try { + SocketAddress remote = beginRead(true, false); + boolean connected = (remote != null); + do { + long remainingNanos = nanos - (System.nanoTime() - startNanos); + ByteBuffer dst = tryBlockingReceive(connected, bufLength, remainingNanos); + + // if datagram received then get sender and copy to DatagramPacket + if (dst != null) { + try { + // sender address is in socket address buffer + sender = sourceSocketAddress(); + + // check sender when security manager set and not connected + @SuppressWarnings("removal") + SecurityManager sm = System.getSecurityManager(); + if (sm != null && !connected) { + InetSocketAddress isa = (InetSocketAddress) sender; + try { + sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort()); + } catch (SecurityException e) { + sender = null; + } + } + + // copy bytes to the DatagramPacket, and set length and sender + if (sender != null) { + synchronized (p) { + // re-read p.bufLength in case DatagramPacket changed + int len = Math.min(dst.limit(), DatagramPackets.getBufLength(p)); + dst.get(p.getData(), p.getOffset(), len); + DatagramPackets.setLength(p, len); + p.setSocketAddress(sender); + } + } + } finally { + Util.offerFirstTemporaryDirectBuffer(dst); + } + } + } while (sender == null && isOpen()); + } finally { + endRead(true, (sender != null)); } - return sender; } finally { - endRead(true, (sender != null)); + readLock.unlock(); } } /** - * Receives a datagram into given buffer with a timeout. This method is - * used to support the socket adaptor. The buffer is assumed to be trusted. + * Attempt to receive a datagram. + * + * @param connected if the channel's socket is connected + * @param len the maximum size of the datagram to receive + * @param nanos the timeout, should be Long.MAX_VALUE for untimed + * @return a direct buffer containing the datagram or null if channel is closed * @throws SocketTimeoutException if the timeout elapses */ - private SocketAddress trustedBlockingReceive(ByteBuffer dst, long nanos) + private ByteBuffer tryBlockingReceive(boolean connected, int len, long nanos) throws IOException { - assert readLock.isHeldByCurrentThread() && isBlocking(); - SocketAddress sender = null; + long startNanos = System.nanoTime(); + ByteBuffer dst = Util.getTemporaryDirectBuffer(len); + int n = -1; try { - SocketAddress remote = beginRead(true, false); - boolean connected = (remote != null); - - // change socket to non-blocking - lockedConfigureBlocking(false); - try { - long startNanos = System.nanoTime(); - int n = receive(dst, connected); - while (n == IOStatus.UNAVAILABLE && isOpen()) { - long remainingNanos = nanos - (System.nanoTime() - startNanos); - if (remainingNanos <= 0) { - throw new SocketTimeoutException("Receive timed out"); - } - park(Net.POLLIN, remainingNanos); - n = receive(dst, connected); + n = receive(dst, connected); + while (n == IOStatus.UNAVAILABLE && isOpen()) { + // virtual thread needs to release temporary direct buffer before parking + if (Thread.currentThread().isVirtual()) { + Util.offerFirstTemporaryDirectBuffer(dst); + dst = null; } - if (n > 0 || (n == 0 && isOpen())) { - // sender address is in socket address buffer - sender = sourceSocketAddress(); + long remainingNanos = nanos - (System.nanoTime() - startNanos); + if (remainingNanos <= 0) { + throw new SocketTimeoutException("Receive timed out"); } - return sender; - } finally { - // restore socket to blocking mode (if channel is open) - tryLockedConfigureBlocking(true); + park(Net.POLLIN, remainingNanos); + // virtual thread needs to re-allocate temporary direct buffer after parking + if (Thread.currentThread().isVirtual()) { + dst = Util.getTemporaryDirectBuffer(len); + } + n = receive(dst, connected); } + dst.flip(); } finally { - endRead(true, (sender != null)); + // release buffer if no datagram received + if (dst != null && (n < 0 || (n == 0 && !isOpen()))) { + Util.offerFirstTemporaryDirectBuffer(dst); + dst = null; + } } + return dst; } /** @@ -889,19 +906,54 @@ public int send(ByteBuffer src, SocketAddress target) } /** - * Sends a datagram from the bytes in given buffer. + * Sends a datagram. * * @apiNote This method is for use by the socket adaptor. * + * @throws IllegalArgumentException if not connected and target address not set * @throws IllegalBlockingModeException if the channel is non-blocking */ - void blockingSend(ByteBuffer src, SocketAddress target) throws IOException { + void blockingSend(DatagramPacket p) throws IOException { + Objects.requireNonNull(p); + writeLock.lock(); try { ensureOpen(); if (!isBlocking()) throw new IllegalBlockingModeException(); - send(src, target); + + ByteBuffer src = null; + try { + InetSocketAddress target; + synchronized (p) { + int len = p.getLength(); + src = Util.getTemporaryDirectBuffer(len); + + // copy bytes to temporary direct buffer + src.put(p.getData(), p.getOffset(), len); + src.flip(); + + // target address + if (p.getAddress() == null) { + InetSocketAddress remote = remoteAddress(); + if (remote == null) { + throw new IllegalArgumentException("Address not set"); + } + // set address/port to be compatible with long standing behavior + p.setAddress(remote.getAddress()); + p.setPort(remote.getPort()); + target = remote; + } else { + target = (InetSocketAddress) p.getSocketAddress(); + } + } + + // send the datagram (does not block) + send(src, target); + + } finally { + if (src != null) Util.offerFirstTemporaryDirectBuffer(src); + } } finally { writeLock.unlock(); } @@ -1198,12 +1250,12 @@ private boolean tryLockedConfigureBlocking(boolean block) throws IOException { } /** - * Ensures that the socket is configured non-blocking when on a virtual thread. + * Ensures that the socket is configured non-blocking. * @throws IOException if there is an I/O error changing the blocking mode */ - private void configureSocketNonBlockingIfVirtualThread() throws IOException { + private void configureSocketNonBlocking() throws IOException { assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread(); - if (!forcedNonBlocking && Thread.currentThread().isVirtual()) { + if (!forcedNonBlocking) { synchronized (stateLock) { ensureOpen(); IOUtil.configureBlocking(fd, false); @@ -1212,6 +1264,16 @@ private void configureSocketNonBlockingIfVirtualThread() throws IOException { } } + /** + * Ensures that the socket is configured non-blocking when on a virtual thread. + * @throws IOException if there is an I/O error changing the blocking mode + */ + private void configureSocketNonBlockingIfVirtualThread() throws IOException { + if (Thread.currentThread().isVirtual()) { + configureSocketNonBlocking(); + } + } + InetSocketAddress localAddress() { synchronized (stateLock) { return localAddress; @@ -1952,6 +2014,44 @@ private static Runnable releaserFor(FileDescriptor fd, NativeSocketAddress... so }; } + /** + * Defines static methods to get/set DatagramPacket fields and workaround + * DatagramPacket deficiencies. + */ + private static class DatagramPackets { + private static final VarHandle LENGTH; + private static final VarHandle BUF_LENGTH; + static { + try { + PrivilegedExceptionAction pa = () -> + MethodHandles.privateLookupIn(DatagramPacket.class, MethodHandles.lookup()); + @SuppressWarnings("removal") + MethodHandles.Lookup l = AccessController.doPrivileged(pa); + LENGTH = l.findVarHandle(DatagramPacket.class, "length", int.class); + BUF_LENGTH = l.findVarHandle(DatagramPacket.class, "bufLength", int.class); + } catch (Exception e) { + throw new ExceptionInInitializerError(e); + } + } + + /** + * Sets the DatagramPacket.length field. DatagramPacket.setLength cannot be + * used at this time because it sets both the length and bufLength fields. + */ + static void setLength(DatagramPacket p, int value) { + assert Thread.holdsLock(p); + LENGTH.set(p, value); + } + + /** + * Returns the value of the DatagramPacket.bufLength field. + */ + static int getBufLength(DatagramPacket p) { + assert Thread.holdsLock(p); + return (int) BUF_LENGTH.get(p); + } + } + // -- Native methods -- private static native void disconnect0(FileDescriptor fd, boolean isIPv6) 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 d59a4dc4b92f1..8826cc3c188db 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,6 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; -import java.lang.invoke.VarHandle; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; @@ -44,7 +43,6 @@ import java.net.SocketOption; import java.net.SocketTimeoutException; import java.net.StandardSocketOptions; -import java.nio.ByteBuffer; import java.nio.channels.AlreadyConnectedException; import java.nio.channels.ClosedChannelException; import java.nio.channels.ClosedByInterruptException; @@ -56,7 +54,6 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; -import jdk.internal.misc.Blocker; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -192,79 +189,30 @@ public SocketAddress getLocalSocketAddress() { @Override public void send(DatagramPacket p) throws IOException { - synchronized (p) { - int len = p.getLength(); - ByteBuffer bb = Util.getTemporaryDirectBuffer(len); - try { - // copy bytes to temporary direct buffer - bb.put(p.getData(), p.getOffset(), len); - bb.flip(); - - // target address - InetSocketAddress target; - if (p.getAddress() == null) { - InetSocketAddress remote = dc.remoteAddress(); - if (remote == null) { - // not specified by DatagramSocket - throw new IllegalArgumentException("Address not set"); - } - // set address/port to maintain compatibility with DatagramSocket - p.setAddress(remote.getAddress()); - p.setPort(remote.getPort()); - target = remote; - } else { - target = (InetSocketAddress) p.getSocketAddress(); - } - - // send datagram - dc.blockingSend(bb, target); - } catch (AlreadyConnectedException e) { - throw new IllegalArgumentException("Connected and packet address differ"); - } catch (ClosedChannelException e) { - throw new SocketException("Socket closed", e); - } finally { - Util.offerFirstTemporaryDirectBuffer(bb); - } + try { + dc.blockingSend(p); + } catch (AlreadyConnectedException e) { + throw new IllegalArgumentException("Connected and packet address differ"); + } catch (ClosedChannelException e) { + throw new SocketException("Socket closed", e); } } @Override public void receive(DatagramPacket p) throws IOException { - synchronized (p) { - // get temporary direct buffer with a capacity of p.bufLength - int bufLength = DatagramPackets.getBufLength(p); - ByteBuffer bb = Util.getTemporaryDirectBuffer(bufLength); - try { - SocketAddress sender; - long comp = Blocker.begin(); - try { - sender = dc.blockingReceive(bb, MILLISECONDS.toNanos(timeout)); - } finally { - Blocker.end(comp); - } - bb.flip(); - - // copy bytes to the DatagramPacket and set length - int len = Math.min(bb.limit(), DatagramPackets.getBufLength(p)); - bb.get(p.getData(), p.getOffset(), len); - DatagramPackets.setLength(p, len); - - // sender address - p.setSocketAddress(sender); - } catch (SocketTimeoutException | ClosedByInterruptException e) { - throw e; - } catch (InterruptedIOException e) { - Thread thread = Thread.currentThread(); - if (thread.isVirtual() && thread.isInterrupted()) { - close(); - throw new SocketException("Closed by interrupt"); - } - throw e; - } catch (ClosedChannelException e) { - throw new SocketException("Socket closed", e); - } finally { - Util.offerFirstTemporaryDirectBuffer(bb); + try { + dc.blockingReceive(p, MILLISECONDS.toNanos(timeout)); + } catch (SocketTimeoutException | ClosedByInterruptException e) { + throw e; + } catch (InterruptedIOException e) { + Thread thread = Thread.currentThread(); + if (thread.isVirtual() && thread.isInterrupted()) { + close(); + throw new SocketException("Closed by interrupt"); } + throw e; + } catch (ClosedChannelException e) { + throw new SocketException("Socket closed", e); } } @@ -704,44 +652,6 @@ private InetAddress anyInetAddress() { return new InetSocketAddress(0).getAddress(); } - /** - * Defines static methods to get/set DatagramPacket fields and workaround - * DatagramPacket deficiencies. - */ - private static class DatagramPackets { - private static final VarHandle LENGTH; - private static final VarHandle BUF_LENGTH; - static { - try { - PrivilegedExceptionAction pa = () -> - MethodHandles.privateLookupIn(DatagramPacket.class, MethodHandles.lookup()); - @SuppressWarnings("removal") - MethodHandles.Lookup l = AccessController.doPrivileged(pa); - LENGTH = l.findVarHandle(DatagramPacket.class, "length", int.class); - BUF_LENGTH = l.findVarHandle(DatagramPacket.class, "bufLength", int.class); - } catch (Exception e) { - throw new ExceptionInInitializerError(e); - } - } - - /** - * Sets the DatagramPacket.length field. DatagramPacket.setLength cannot be - * used at this time because it sets both the length and bufLength fields. - */ - static void setLength(DatagramPacket p, int value) { - assert Thread.holdsLock(p); - LENGTH.set(p, value); - } - - /** - * Returns the value of the DatagramPacket.bufLength field. - */ - static int getBufLength(DatagramPacket p) { - assert Thread.holdsLock(p); - return (int) BUF_LENGTH.get(p); - } - } - /** * Defines static methods to invoke non-public NetworkInterface methods. */ 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 82909d9cf662f..abd1447e995fe 100644 --- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java @@ -1041,10 +1041,10 @@ private int writeInternal(ByteBuffer src, long position) throws IOException { // -- Memory-mapped buffers -- - private abstract static class Unmapper + private sealed abstract static class Unmapper implements Runnable, UnmapperProxy { - private volatile long address; + private final long address; protected final long size; protected final long cap; private final FileDescriptor fd; @@ -1081,10 +1081,7 @@ public long capacity() { } public void unmap() { - if (address == 0) - return; nd.unmap(address, size); - address = 0; // if this mapping has a valid file descriptor then we close it if (fd.valid()) { @@ -1101,7 +1098,7 @@ public void unmap() { protected abstract void decrementStats(); } - private static class DefaultUnmapper extends Unmapper { + private static final class DefaultUnmapper extends Unmapper { // keep track of non-sync mapped buffer usage static volatile int count; @@ -1134,7 +1131,7 @@ public boolean isSync() { } } - private static class SyncUnmapper extends Unmapper { + private static final class SyncUnmapper extends Unmapper { // keep track of mapped buffer usage static volatile int count; diff --git a/src/java.base/share/classes/sun/nio/cs/StreamDecoder.java b/src/java.base/share/classes/sun/nio/cs/StreamDecoder.java index 340349a40fef1..a2026744f04b5 100644 --- a/src/java.base/share/classes/sun/nio/cs/StreamDecoder.java +++ b/src/java.base/share/classes/sun/nio/cs/StreamDecoder.java @@ -42,6 +42,8 @@ import java.nio.charset.CodingErrorAction; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; +import java.util.Arrays; + import jdk.internal.misc.InternalLock; public class StreamDecoder extends Reader { @@ -271,6 +273,25 @@ private boolean isOpen() { return !closed; } + public void fillZeroToPosition() throws IOException { + Object lock = this.lock; + if (lock instanceof InternalLock locker) { + locker.lock(); + try { + lockedFillZeroToPosition(); + } finally { + locker.unlock(); + } + } else { + synchronized (lock) { + lockedFillZeroToPosition(); + } + } + } + + private void lockedFillZeroToPosition() { + Arrays.fill(bb.array(), bb.arrayOffset(), bb.arrayOffset() + bb.position(), (byte)0); + } // -- Charset-based stream decoder impl -- diff --git a/src/java.base/share/classes/sun/security/pkcs/PKCS7.java b/src/java.base/share/classes/sun/security/pkcs/PKCS7.java index cb27840209465..302b5922bbc79 100644 --- a/src/java.base/share/classes/sun/security/pkcs/PKCS7.java +++ b/src/java.base/share/classes/sun/security/pkcs/PKCS7.java @@ -152,6 +152,10 @@ private void parse(DerInputStream derin, boolean oldStyle) ObjectIdentifier contentType = block.contentType; DerValue content = block.getContent(); + if (content == null) { + throw new ParsingException("content is null"); + } + if (contentType.equals(ContentInfo.SIGNED_DATA_OID)) { parseSignedData(content); } else if (contentType.equals(ContentInfo.OLD_SIGNED_DATA_OID)) { diff --git a/src/java.base/share/classes/sun/security/provider/DSA.java b/src/java.base/share/classes/sun/security/provider/DSA.java index 4f3348196e198..40f95e737ac7b 100644 --- a/src/java.base/share/classes/sun/security/provider/DSA.java +++ b/src/java.base/share/classes/sun/security/provider/DSA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -158,6 +158,7 @@ protected void engineInitSign(PrivateKey privateKey) checkKey(params, md.getDigestLength()*8, md.getAlgorithm()); } + this.signingRandom = null; this.params = params; this.presetX = priv.getX(); this.presetY = null; diff --git a/src/java.base/share/classes/sun/security/provider/DSAPublicKeyImpl.java b/src/java.base/share/classes/sun/security/provider/DSAPublicKeyImpl.java index 2c402ef28637f..ca84d202c1464 100644 --- a/src/java.base/share/classes/sun/security/provider/DSAPublicKeyImpl.java +++ b/src/java.base/share/classes/sun/security/provider/DSAPublicKeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,17 +25,20 @@ package sun.security.provider; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; import java.math.BigInteger; import java.security.KeyRep; import java.security.InvalidKeyException; /** * An X.509 public key for the Digital Signature Algorithm. - * + *

* The difference between DSAPublicKeyImpl and DSAPublicKey is that * DSAPublicKeyImpl calls writeReplace with KeyRep, and DSAPublicKey * calls writeObject. - * + *

* See the comments in DSAKeyFactory, 4532506, and 6232513. * */ @@ -72,10 +75,26 @@ public DSAPublicKeyImpl(byte[] encoded) throws InvalidKeyException { } @java.io.Serial - protected Object writeReplace() throws java.io.ObjectStreamException { + private Object writeReplace() throws java.io.ObjectStreamException { return new KeyRep(KeyRep.Type.PUBLIC, getAlgorithm(), getFormat(), getEncoded()); } + + /** + * Restores the state of this object from the stream. + *

+ * Deserialization of this object is not supported. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "DSAPublicKeyImpl keys are not directly deserializable"); + } } diff --git a/src/java.base/share/classes/sun/security/provider/PolicyFile.java b/src/java.base/share/classes/sun/security/provider/PolicyFile.java index f69f513dc9fcf..bc2c86539de42 100644 --- a/src/java.base/share/classes/sun/security/provider/PolicyFile.java +++ b/src/java.base/share/classes/sun/security/provider/PolicyFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2098,8 +2098,17 @@ public SelfPermission(String type, String name, String actions, this.actions.equals(that.actions))) return false; - if (this.certs.length != that.certs.length) + if ((this.certs == null) && (that.certs == null)) { + return true; + } + + if ((this.certs == null) || (that.certs == null)) { + return false; + } + + if (this.certs.length != that.certs.length) { return false; + } int i,j; boolean match; @@ -2169,7 +2178,7 @@ public String getSelfActions() { } public Certificate[] getCerts() { - return certs; + return (certs == null ? null : certs.clone()); } /** @@ -2182,6 +2191,22 @@ public Certificate[] getCerts() { @Override public String toString() { return "(SelfPermission " + type + " " + name + " " + actions + ")"; } + + /** + * Restores the state of this object from the stream. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + if (certs != null) { + this.certs = certs.clone(); + } + } } /** diff --git a/src/java.base/share/classes/sun/security/provider/SecureRandom.java b/src/java.base/share/classes/sun/security/provider/SecureRandom.java index 5df3adf6ea83e..a8d82b649b02f 100644 --- a/src/java.base/share/classes/sun/security/provider/SecureRandom.java +++ b/src/java.base/share/classes/sun/security/provider/SecureRandom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package sun.security.provider; import java.io.IOException; +import java.io.InvalidObjectException; import java.security.MessageDigest; import java.security.SecureRandomSpi; import java.security.NoSuchAlgorithmException; @@ -192,7 +193,7 @@ private static void updateState(byte[] state, byte[] output) { /** * This static object will be seeded by SeedGenerator, and used * to seed future instances of SHA1PRNG SecureRandoms. - * + *

* Bloch, Effective Java Second Edition: Item 71 */ private static class SeederHolder { @@ -265,18 +266,24 @@ public synchronized void engineNextBytes(byte[] result) { } /* - * readObject is called to restore the state of the random object from - * a stream. We have to create a new instance of MessageDigest, because + * This method is called to restore the state of the random object from + * a stream. + *

+ * We have to create a new instance of {@code MessageDigest}, because * it is not included in the stream (it is marked "transient"). - * - * Note that the engineNextBytes() method invoked on the restored random - * object will yield the exact same (random) bytes as the original. + *

+ * Note that the {@code engineNextBytes()} method invoked on the restored + * random object will yield the exact same (random) bytes as the original. * If you do not want this behaviour, you should re-seed the restored - * random object, using engineSetSeed(). + * random object, using {@code engineSetSeed()}. + * + * @param s the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded */ @java.io.Serial private void readObject(java.io.ObjectInputStream s) - throws IOException, ClassNotFoundException { + throws IOException, ClassNotFoundException { s.defaultReadObject (); @@ -295,5 +302,34 @@ private void readObject(java.io.ObjectInputStream s) "internal error: SHA-1 not available.", exc); } } + + // Various consistency checks + if ((remainder == null) && (remCount > 0)) { + throw new InvalidObjectException( + "Remainder indicated, but no data available"); + } + + // Not yet allocated state + if (state == null) { + if (remainder == null) { + return; + } else { + throw new InvalidObjectException( + "Inconsistent buffer allocations"); + } + } + + // Sanity check on sizes/pointer + if ((state.length != DIGEST_SIZE) || + ((remainder != null) && (remainder.length != DIGEST_SIZE)) || + (remCount < 0 ) || (remCount >= DIGEST_SIZE)) { + throw new InvalidObjectException( + "Inconsistent buffer sizes/state"); + } + + state = state.clone(); + if (remainder != null) { + remainder = remainder.clone(); + } } } diff --git a/src/java.base/share/classes/sun/security/provider/certpath/CertPathHelper.java b/src/java.base/share/classes/sun/security/provider/certpath/CertPathHelper.java index 3675209e03d5d..203b92ce30aaa 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/CertPathHelper.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/CertPathHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,14 +26,10 @@ package sun.security.provider.certpath; import java.util.Date; -import java.util.Set; import java.security.cert.TrustAnchor; -import java.security.cert.X509CertSelector; import java.security.cert.X509CRLSelector; -import sun.security.x509.GeneralNameInterface; - /** * Helper class that allows access to JDK specific known-public methods in the * java.security.cert package. It relies on a subclass in the @@ -55,18 +51,10 @@ protected CertPathHelper() { // empty } - protected abstract void implSetPathToNames(X509CertSelector sel, - Set names); - protected abstract void implSetDateAndTime(X509CRLSelector sel, Date date, long skew); protected abstract boolean implIsJdkCA(TrustAnchor anchor); - static void setPathToNames(X509CertSelector sel, - Set names) { - instance.implSetPathToNames(sel, names); - } - public static void setDateAndTime(X509CRLSelector sel, Date date, long skew) { instance.implSetDateAndTime(sel, date, skew); } diff --git a/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java b/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java index 26f97efc3d9bc..b946607434396 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java @@ -41,13 +41,13 @@ import java.util.*; import javax.security.auth.x500.X500Principal; +import jdk.internal.misc.ThreadTracker; import sun.security.provider.certpath.PKIX.BuilderParams; import sun.security.util.Debug; import sun.security.x509.AccessDescription; import sun.security.x509.AuthorityInfoAccessExtension; import sun.security.x509.AuthorityKeyIdentifierExtension; import static sun.security.x509.PKIXExtensions.*; -import sun.security.x509.SubjectAlternativeNameExtension; import sun.security.x509.X500Name; import sun.security.x509.X509CertImpl; @@ -72,6 +72,10 @@ final class ForwardBuilder extends Builder { TrustAnchor trustAnchor; private final boolean searchAllCertStores; + private static class ThreadTrackerHolder { + static final ThreadTracker AIA_TRACKER = new ThreadTracker(); + } + /** * Initialize the builder with the input parameters. * @@ -257,14 +261,6 @@ private void getMatchingCACerts(ForwardState currentState, */ caSelector.setSubject(currentState.issuerDN); - /* - * Match on subjectNamesTraversed (both DNs and AltNames) - * (checks that current cert's name constraints permit it - * to certify all the DNs and AltNames that have been traversed) - */ - CertPathHelper.setPathToNames - (caSelector, currentState.subjectNamesTraversed); - /* * check the validity period */ @@ -345,7 +341,7 @@ private void getMatchingCACerts(ForwardState currentState, } /** - * Download Certificates from the given AIA and add them to the + * Download certificates from the given AIA and add them to the * specified Collection. */ // cs.getCertificates(caSelector) returns a collection of X509Certificate's @@ -357,32 +353,47 @@ private boolean getCerts(AuthorityInfoAccessExtension aiaExt, if (!Builder.USE_AIA) { return false; } + List adList = aiaExt.getAccessDescriptions(); if (adList == null || adList.isEmpty()) { return false; } - boolean add = false; - for (AccessDescription ad : adList) { - CertStore cs = URICertStore.getInstance(ad); - if (cs != null) { - try { - if (certs.addAll((Collection) - cs.getCertificates(caSelector))) { - add = true; - if (!searchAllCertStores) { - return true; + Object key = ThreadTrackerHolder.AIA_TRACKER.tryBegin(); + if (key == null) { + // Avoid recursive fetching of certificates + if (debug != null) { + debug.println("Recursive fetching of certs via the AIA " + + "extension detected"); + } + return false; + } + + try { + boolean add = false; + for (AccessDescription ad : adList) { + CertStore cs = URICertStore.getInstance(ad); + if (cs != null) { + try { + if (certs.addAll((Collection) + cs.getCertificates(caSelector))) { + add = true; + if (!searchAllCertStores) { + return true; + } + } + } catch (CertStoreException cse) { + if (debug != null) { + debug.println("exception getting certs from CertStore:"); + cse.printStackTrace(); } - } - } catch (CertStoreException cse) { - if (debug != null) { - debug.println("exception getting certs from CertStore:"); - cse.printStackTrace(); } } } + return add; + } finally { + ThreadTrackerHolder.AIA_TRACKER.end(key); } - return add; } /** @@ -697,19 +708,6 @@ void verifyCert(X509Certificate cert, State currentState, // Don't bother to verify untrusted certificate more. currState.untrustedChecker.check(cert, Collections.emptySet()); - /* - * Abort if we encounter the same certificate or a certificate with - * the same public key, subject DN, and subjectAltNames as a cert - * that is already in path. - */ - for (X509Certificate cpListCert : certPathList) { - if (repeated(cpListCert, cert)) { - throw new CertPathValidatorException( - "cert with repeated subject, public key, and " + - "subjectAltNames detected"); - } - } - /* check if trusted cert */ boolean isTrustedCert = trustedCerts.contains(cert); @@ -787,49 +785,6 @@ void verifyCert(X509Certificate cert, State currentState, } } - /** - * Return true if two certificates are equal or have the same subject, - * public key, and subject alternative names. - */ - private static boolean repeated( - X509Certificate currCert, X509Certificate nextCert) { - if (currCert.equals(nextCert)) { - return true; - } - return (currCert.getSubjectX500Principal().equals( - nextCert.getSubjectX500Principal()) && - currCert.getPublicKey().equals(nextCert.getPublicKey()) && - altNamesEqual(currCert, nextCert)); - } - - /** - * Return true if two certificates have the same subject alternative names. - */ - private static boolean altNamesEqual( - X509Certificate currCert, X509Certificate nextCert) { - X509CertImpl curr, next; - try { - curr = X509CertImpl.toImpl(currCert); - next = X509CertImpl.toImpl(nextCert); - } catch (CertificateException ce) { - return false; - } - - SubjectAlternativeNameExtension currAltNameExt = - curr.getSubjectAlternativeNameExtension(); - SubjectAlternativeNameExtension nextAltNameExt = - next.getSubjectAlternativeNameExtension(); - if (currAltNameExt != null) { - if (nextAltNameExt == null) { - return false; - } - return Arrays.equals(currAltNameExt.getExtensionValue(), - nextAltNameExt.getExtensionValue()); - } else { - return (nextAltNameExt == null); - } - } - /** * Verifies whether the input certificate completes the path. * First checks the cert against each trust anchor that was specified, diff --git a/src/java.base/share/classes/sun/security/provider/certpath/ForwardState.java b/src/java.base/share/classes/sun/security/provider/certpath/ForwardState.java index c93f0bcb3a054..537b6b8266f80 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/ForwardState.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/ForwardState.java @@ -31,17 +31,11 @@ import java.security.cert.PKIXCertPathChecker; import java.security.cert.X509Certificate; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.ListIterator; import javax.security.auth.x500.X500Principal; import sun.security.util.Debug; -import sun.security.x509.SubjectAlternativeNameExtension; -import sun.security.x509.GeneralNames; -import sun.security.x509.GeneralName; -import sun.security.x509.GeneralNameInterface; -import sun.security.x509.X500Name; import sun.security.x509.X509CertImpl; /** @@ -61,9 +55,6 @@ class ForwardState implements State { /* The last cert in the path */ X509CertImpl cert; - /* The set of subjectDNs and subjectAltNames of all certs in the path */ - HashSet subjectNamesTraversed; - /* * The number of intermediate CA certs which have been traversed so * far in the path @@ -73,7 +64,6 @@ class ForwardState implements State { /* Flag indicating if state is initial (path is just starting) */ private boolean init = true; - /* the untrusted certificates checker */ UntrustedChecker untrustedChecker; @@ -103,8 +93,6 @@ public String toString() { "\n issuerDN of last cert: " + issuerDN + "\n traversedCACerts: " + traversedCACerts + "\n init: " + init + - "\n subjectNamesTraversed: \n" + - subjectNamesTraversed + "\n selfIssued: " + selfIssued + "\n" + "]\n"; } @@ -117,7 +105,6 @@ public String toString() { public void initState(List certPathCheckers) throws CertPathValidatorException { - subjectNamesTraversed = new HashSet<>(); traversedCACerts = 0; /* @@ -167,22 +154,6 @@ public void updateState(X509Certificate cert) } } - /* update subjectNamesTraversed only if this is the EE cert or if - this cert is not self-issued */ - if (init || !selfIssued) { - X500Principal subjName = cert.getSubjectX500Principal(); - subjectNamesTraversed.add(X500Name.asX500Name(subjName)); - - SubjectAlternativeNameExtension subjAltNameExt - = icert.getSubjectAlternativeNameExtension(); - if (subjAltNameExt != null) { - GeneralNames gNames = subjAltNameExt.getNames(); - for (GeneralName gName : gNames.names()) { - subjectNamesTraversed.add(gName.getName()); - } - } - } - init = false; } @@ -190,10 +161,6 @@ public void updateState(X509Certificate cert) * Clone current state. The state is cloned as each cert is * added to the path. This is necessary if backtracking occurs, * and a prior state needs to be restored. - * - * Note that this is a SMART clone. Not all fields are fully copied, - * because some of them will - * not have their contents modified by subsequent calls to updateState. */ @Override @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly @@ -213,13 +180,6 @@ public Object clone() { } } - /* - * Shallow copy traversed names. There is no need to - * deep copy contents, since the elements of the Set - * are never modified by subsequent calls to updateState(). - */ - clonedState.subjectNamesTraversed - = (HashSet)subjectNamesTraversed.clone(); return clonedState; } catch (CloneNotSupportedException e) { throw new InternalError(e.toString(), e); diff --git a/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java b/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java index 8c9081b3d9f6d..c4e31cf794731 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java @@ -33,6 +33,7 @@ import java.security.cert.CertPathValidatorException.BasicReason; import java.security.cert.PKIXReason; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -42,6 +43,7 @@ import sun.security.provider.certpath.PKIX.BuilderParams; import static sun.security.x509.PKIXExtensions.*; +import sun.security.x509.SubjectAlternativeNameExtension; import sun.security.x509.X509CertImpl; import sun.security.util.Debug; @@ -265,7 +267,7 @@ private void depthFirstSearchForward(X500Principal dN, */ Collection certs = builder.getMatchingCerts(currentState, buildParams.certStores()); - List vertices = addVertices(certs, adjList); + List vertices = addVertices(certs, adjList, cpList); if (debug != null) { debug.println("SunCertPathBuilder.depthFirstSearchForward(): " + "certs.size=" + vertices.size()); @@ -325,17 +327,32 @@ private void depthFirstSearchForward(X500Principal dN, * cert (which is signed by the trusted public key), but * don't add it yet to the cpList */ + PublicKey rootKey = cert.getPublicKey(); if (builder.trustAnchor.getTrustedCert() == null) { appendedCerts.add(0, cert); + rootKey = builder.trustAnchor.getCAPublicKey(); + if (debug != null) + debug.println( + "SunCertPathBuilder.depthFirstSearchForward " + + "using buildParams public key: " + + rootKey.toString()); } + TrustAnchor anchor = new TrustAnchor + (cert.getSubjectX500Principal(), rootKey, null); + // add the basic checker + List checkers = new ArrayList<>(); + BasicChecker basicChecker = new BasicChecker(anchor, + buildParams.date(), + buildParams.sigProvider(), + true); + checkers.add(basicChecker); Set initExpPolSet = Collections.singleton(PolicyChecker.ANY_POLICY); PolicyNodeImpl rootNode = new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, false, initExpPolSet, false); - List checkers = new ArrayList<>(); PolicyChecker policyChecker = new PolicyChecker(buildParams.initialPolicies(), appendedCerts.size(), @@ -346,28 +363,13 @@ private void depthFirstSearchForward(X500Principal dN, rootNode); checkers.add(policyChecker); + // add the constraints checker + checkers.add(new ConstraintsChecker(appendedCerts.size())); + // add the algorithm checker checkers.add(new AlgorithmChecker(builder.trustAnchor, buildParams.timestamp(), buildParams.variant())); - PublicKey rootKey = cert.getPublicKey(); - if (builder.trustAnchor.getTrustedCert() == null) { - rootKey = builder.trustAnchor.getCAPublicKey(); - if (debug != null) - debug.println( - "SunCertPathBuilder.depthFirstSearchForward " + - "using buildParams public key: " + - rootKey.toString()); - } - TrustAnchor anchor = new TrustAnchor - (cert.getSubjectX500Principal(), rootKey, null); - - // add the basic checker - BasicChecker basicChecker = new BasicChecker(anchor, - buildParams.date(), - buildParams.sigProvider(), - true); - checkers.add(basicChecker); buildParams.setCertPath(cf.generateCertPath(appendedCerts)); @@ -563,18 +565,79 @@ private void depthFirstSearchForward(X500Principal dN, * adjacency list. */ private static List addVertices(Collection certs, - List> adjList) + List> adjList, + List cpList) { List l = adjList.get(adjList.size() - 1); for (X509Certificate cert : certs) { - Vertex v = new Vertex(cert); - l.add(v); + boolean repeated = false; + for (X509Certificate cpListCert : cpList) { + /* + * Ignore if we encounter the same certificate or a + * certificate with the same public key, subject DN, and + * subjectAltNames as a cert that is already in path. + */ + if (repeated(cpListCert, cert)) { + if (debug != null) { + debug.println("cert with repeated subject, " + + "public key, and subjectAltNames detected"); + } + repeated = true; + break; + } + } + if (!repeated) { + l.add(new Vertex(cert)); + } } return l; } + /** + * Return true if two certificates are equal or have the same subject, + * public key, and subject alternative names. + */ + private static boolean repeated( + X509Certificate currCert, X509Certificate nextCert) { + if (currCert.equals(nextCert)) { + return true; + } + return (currCert.getSubjectX500Principal().equals( + nextCert.getSubjectX500Principal()) && + currCert.getPublicKey().equals(nextCert.getPublicKey()) && + altNamesEqual(currCert, nextCert)); + } + + /** + * Return true if two certificates have the same subject alternative names. + */ + private static boolean altNamesEqual( + X509Certificate currCert, X509Certificate nextCert) { + X509CertImpl curr, next; + try { + curr = X509CertImpl.toImpl(currCert); + next = X509CertImpl.toImpl(nextCert); + } catch (CertificateException ce) { + return false; + } + + SubjectAlternativeNameExtension currAltNameExt = + curr.getSubjectAlternativeNameExtension(); + SubjectAlternativeNameExtension nextAltNameExt = + next.getSubjectAlternativeNameExtension(); + if (currAltNameExt != null) { + if (nextAltNameExt == null) { + return false; + } + return Arrays.equals(currAltNameExt.getExtensionValue(), + nextAltNameExt.getExtensionValue()); + } else { + return (nextAltNameExt == null); + } + } + /** * Returns true if trust anchor certificate matches specified * certificate constraints. diff --git a/src/java.base/share/classes/sun/security/provider/certpath/X509CertPath.java b/src/java.base/share/classes/sun/security/provider/certpath/X509CertPath.java index 41da617e4e420..1a9ba8914e29b 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/X509CertPath.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/X509CertPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,7 @@ package sun.security.provider.certpath; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.security.cert.CertificateEncodingException; import java.security.cert.Certificate; import java.security.cert.CertificateException; @@ -379,4 +377,20 @@ public Iterator getEncodings() { public List getCertificates() { return certs; } + + /** + * Restores the state of this object from the stream. + *

+ * Deserialization of this object is not supported. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "X509CertPaths are not directly deserializable"); + } } diff --git a/src/java.base/share/classes/sun/security/rsa/RSAPadding.java b/src/java.base/share/classes/sun/security/rsa/RSAPadding.java index c429473b5343f..8379545e192e5 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAPadding.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAPadding.java @@ -30,7 +30,6 @@ import java.security.*; import java.security.spec.*; -import javax.crypto.BadPaddingException; import javax.crypto.spec.PSource; import javax.crypto.spec.OAEPParameterSpec; @@ -236,24 +235,22 @@ public int getMaxDataSize() { } /** - * Pad the data and return the padded block. + * Pad the data and return the result or null if error occurred. */ - public byte[] pad(byte[] data) throws BadPaddingException { + public byte[] pad(byte[] data) { return pad(data, 0, data.length); } /** - * Pad the data and return the padded block. + * Pad the data and return the result or null if error occurred. */ - public byte[] pad(byte[] data, int ofs, int len) - throws BadPaddingException { + public byte[] pad(byte[] data, int ofs, int len) { if (len > maxDataSize) { - throw new BadPaddingException("Data must be shorter than " - + (maxDataSize + 1) + " bytes but received " - + len + " bytes."); + return null; } switch (type) { case PAD_NONE: + // assert len == paddedSize and data.length - ofs > len? return RSACore.convert(data, ofs, len); case PAD_BLOCKTYPE_1: case PAD_BLOCKTYPE_2: @@ -266,24 +263,18 @@ public byte[] pad(byte[] data, int ofs, int len) } /** - * Unpad the padded block and return the data. + * Unpad the padded block and return the result or null if error occurred. */ - public byte[] unpad(byte[] padded) throws BadPaddingException { - if (padded.length != paddedSize) { - throw new BadPaddingException("Decryption error. " + - "The padded array length (" + padded.length + - ") is not the specified padded size (" + paddedSize + ")"); - } - switch (type) { - case PAD_NONE: - return padded; - case PAD_BLOCKTYPE_1: - case PAD_BLOCKTYPE_2: - return unpadV15(padded); - case PAD_OAEP_MGF1: - return unpadOAEP(padded); - default: - throw new AssertionError(); + public byte[] unpad(byte[] padded) { + if (padded.length == paddedSize) { + return switch(type) { + case PAD_NONE -> padded; + case PAD_BLOCKTYPE_1, PAD_BLOCKTYPE_2 -> unpadV15(padded); + case PAD_OAEP_MGF1 -> unpadOAEP(padded); + default -> throw new AssertionError(); + }; + } else { + return null; } } @@ -327,10 +318,10 @@ private byte[] padV15(byte[] data, int ofs, int len) { /** * PKCS#1 v1.5 unpadding (blocktype 1 (signature) and 2 (encryption)). - * + * Return the result or null if error occurred. * Note that we want to make it a constant-time operation */ - private byte[] unpadV15(byte[] padded) throws BadPaddingException { + private byte[] unpadV15(byte[] padded) { int k = 0; boolean bp = false; @@ -366,10 +357,8 @@ private byte[] unpadV15(byte[] padded) throws BadPaddingException { byte[] data = new byte[n]; System.arraycopy(padded, p, data, 0, n); - BadPaddingException bpe = new BadPaddingException("Decryption error"); - if (bp) { - throw bpe; + return null; } else { return data; } @@ -378,6 +367,7 @@ private byte[] unpadV15(byte[] padded) throws BadPaddingException { /** * PKCS#1 v2.0 OAEP padding (MGF1). * Paragraph references refer to PKCS#1 v2.1 (June 14, 2002) + * Return the result or null if error occurred. */ private byte[] padOAEP(byte[] M, int ofs, int len) { if (random == null) { @@ -428,8 +418,9 @@ private byte[] padOAEP(byte[] M, int ofs, int len) { /** * PKCS#1 v2.1 OAEP unpadding (MGF1). + * Return the result or null if error occurred. */ - private byte[] unpadOAEP(byte[] padded) throws BadPaddingException { + private byte[] unpadOAEP(byte[] padded) { byte[] EM = padded; boolean bp = false; int hLen = lHash.length; @@ -485,12 +476,6 @@ private byte[] unpadOAEP(byte[] padded) throws BadPaddingException { byte [] m = new byte[EM.length - mStart]; System.arraycopy(EM, mStart, m, 0, m.length); - BadPaddingException bpe = new BadPaddingException("Decryption error"); - - if (bp) { - throw bpe; - } else { - return m; - } + return (bp? null : m); } } 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 86e063f95cd91..99365640ec722 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,8 @@ package sun.security.rsa; import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; import java.math.BigInteger; import java.security.*; @@ -43,7 +45,7 @@ * RSA private key implementation for "RSA", "RSASSA-PSS" algorithms in CRT form. * For non-CRT private keys, see RSAPrivateKeyImpl. We need separate classes * to ensure correct behavior in instanceof checks, etc. - * + *

* Note: RSA keys must be at least 512 bits long * * @see RSAPrivateKeyImpl @@ -356,4 +358,20 @@ private void parseKeyBits() throws InvalidKeyException { throw new InvalidKeyException("Invalid RSA private key", e); } } + + /** + * Restores the state of this object from the stream. + *

+ * Deserialization of this object is not supported. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "RSAPrivateCrtKeyImpl keys are not directly deserializable"); + } } 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 7285fce33a2a2..da5474cb26a20 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,9 @@ package sun.security.rsa; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; import java.math.BigInteger; import java.security.*; @@ -39,10 +42,11 @@ /** * RSA private key implementation for "RSA", "RSASSA-PSS" algorithms in non-CRT - * form (modulus, private exponent only). For CRT private keys, see - * RSAPrivateCrtKeyImpl. We need separate classes to ensure correct behavior - * in instanceof checks, etc. - * + * form (modulus, private exponent only). + *

+ * For CRT private keys, see RSAPrivateCrtKeyImpl. We need separate classes + * to ensure correct behavior in instanceof checks, etc. + *

* Note: RSA keys must be at least 512 bits long * * @see RSAPrivateCrtKeyImpl @@ -141,4 +145,20 @@ public String toString() { + " bits" + "\n params: " + keyParams + "\n modulus: " + n + "\n private exponent: " + d; } + + /** + * Restores the state of this object from the stream. + *

+ * Deserialization of this object is not supported. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "RSAPrivateKeyImpl keys are not directly deserializable"); + } } 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 0cff2f6768cee..5a0745604d2d6 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,8 @@ package sun.security.rsa; import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; import java.math.BigInteger; import java.security.*; @@ -39,7 +41,7 @@ /** * RSA public key implementation for "RSA", "RSASSA-PSS" algorithms. - * + *

* Note: RSA keys must be at least 512 bits long * * @see RSAPrivateCrtKeyImpl @@ -233,10 +235,26 @@ public String toString() { } @java.io.Serial - protected Object writeReplace() throws java.io.ObjectStreamException { + private Object writeReplace() throws java.io.ObjectStreamException { return new KeyRep(KeyRep.Type.PUBLIC, getAlgorithm(), getFormat(), getEncoded()); } + + /** + * Restores the state of this object from the stream. + *

+ * Deserialization of this object is not supported. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "RSAPublicKeyImpl keys are not directly deserializable"); + } } diff --git a/src/java.base/share/classes/sun/security/rsa/RSASignature.java b/src/java.base/share/classes/sun/security/rsa/RSASignature.java index b5ef404325758..d8380343fff05 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSASignature.java +++ b/src/java.base/share/classes/sun/security/rsa/RSASignature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package sun.security.rsa; -import java.io.IOException; import java.nio.ByteBuffer; import java.security.*; @@ -190,10 +189,13 @@ protected byte[] engineSign() throws SignatureException { try { byte[] encoded = RSAUtil.encodeSignature(digestOID, digest); byte[] padded = padding.pad(encoded); - return RSACore.rsa(padded, privateKey, true); + if (padded != null) { + return RSACore.rsa(padded, privateKey, true); + } } catch (GeneralSecurityException e) { throw new SignatureException("Could not sign data", e); } + throw new SignatureException("Could not sign data"); } // verify the data and return the result. See JCA doc @@ -205,27 +207,30 @@ protected boolean engineVerify(byte[] sigBytes) throws SignatureException { } try { if (sigBytes.length != RSACore.getByteLength(publicKey)) { - throw new SignatureException("Signature length not correct: got " + + throw new SignatureException("Bad signature length: got " + sigBytes.length + " but was expecting " + RSACore.getByteLength(publicKey)); } - byte[] digest = getDigestValue(); - byte[] decrypted = RSACore.rsa(sigBytes, publicKey); - byte[] unpadded = padding.unpad(decrypted); + // https://www.rfc-editor.org/rfc/rfc8017.html#section-8.2.2 - // Step 4 suggests comparing the encoded message instead of the - // decoded, but some vendors might omit the NULL params in - // digest algorithm identifier. - byte[] decodedDigest = RSAUtil.decodeSignature(digestOID, unpadded); - return MessageDigest.isEqual(digest, decodedDigest); + // Step 4 suggests comparing the encoded message + byte[] decrypted = RSACore.rsa(sigBytes, publicKey); + + byte[] digest = getDigestValue(); + + byte[] encoded = RSAUtil.encodeSignature(digestOID, digest); + byte[] padded = padding.pad(encoded); + if (MessageDigest.isEqual(padded, decrypted)) { + return true; + } + + // Some vendors might omit the NULL params in digest algorithm + // identifier. Try again. + encoded = RSAUtil.encodeSignatureWithoutNULL(digestOID, digest); + padded = padding.pad(encoded); + return MessageDigest.isEqual(padded, decrypted); } catch (javax.crypto.BadPaddingException e) { - // occurs if the app has used the wrong RSA public key - // or if sigBytes is invalid - // return false rather than propagating the exception for - // compatibility/ease of use return false; - } catch (IOException e) { - throw new SignatureException("Signature encoding error", e); } finally { resetDigest(); } diff --git a/src/java.base/share/classes/sun/security/rsa/RSAUtil.java b/src/java.base/share/classes/sun/security/rsa/RSAUtil.java index 93f5d2f215e5b..080703ae5553b 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAUtil.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -180,28 +180,15 @@ public static byte[] encodeSignature(ObjectIdentifier oid, byte[] digest) { } /** - * Decode the signature data. Verify that the object identifier matches - * and return the message digest. + * Encode the digest without the NULL params, return the to-be-signed data. + * This is only used by SunRsaSign. */ - public static byte[] decodeSignature(ObjectIdentifier oid, byte[] sig) - throws IOException { - // Enforce strict DER checking for signatures - DerInputStream in = new DerInputStream(sig, 0, sig.length, false); - DerValue[] values = in.getSequence(2); - if ((values.length != 2) || (in.available() != 0)) { - throw new IOException("SEQUENCE length error"); - } - AlgorithmId algId = AlgorithmId.parse(values[0]); - if (!algId.getOID().equals(oid)) { - throw new IOException("ObjectIdentifier mismatch: " - + algId.getOID()); - } - if (algId.getEncodedParams() != null) { - throw new IOException("Unexpected AlgorithmId parameters"); - } - if (values[1].isConstructed()) { - throw new IOException("Unexpected constructed digest value"); - } - return values[1].getOctetString(); + static byte[] encodeSignatureWithoutNULL(ObjectIdentifier oid, byte[] digest) { + DerOutputStream out = new DerOutputStream(); + out.write(DerValue.tag_Sequence, new DerOutputStream().putOID(oid)); + out.putOctetString(digest); + DerValue result = + new DerValue(DerValue.tag_Sequence, out.toByteArray()); + return result.toByteArray(); } } diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java index 5c96bfcd5d63e..4c3822593efad 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java @@ -128,7 +128,7 @@ private static String[] getKeyTypes(byte[] ids) { ArrayList keyTypes = new ArrayList<>(3); for (byte id : ids) { ClientCertificateType cct = ClientCertificateType.valueOf(id); - if (cct.isAvailable) { + if (cct != null && cct.isAvailable) { cct.keyAlgorithm.forEach(key -> { if (!keyTypes.contains(key)) { keyTypes.add(key); diff --git a/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java b/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java index e4e1ba9f4ec46..4c931c93feacf 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -443,7 +443,7 @@ public byte[] produce(ConnectionContext context, private HandshakeProducer getHandshakeProducer( ConnectionContext context) { - if (handshakeConsumers.length == 0) { + if (handshakeProducers.length == 0) { return null; } diff --git a/src/java.base/share/classes/sun/security/ssl/SunJSSE.java b/src/java.base/share/classes/sun/security/ssl/SunJSSE.java index 894e26dfad855..dce2aad8400a3 100644 --- a/src/java.base/share/classes/sun/security/ssl/SunJSSE.java +++ b/src/java.base/share/classes/sun/security/ssl/SunJSSE.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,25 +31,6 @@ /** * The JSSE provider. - * - * SunJSSE now supports an experimental FIPS compliant mode when used with an - * appropriate FIPS certified crypto provider. In FIPS mode, we: - * . allow only TLS 1.0 or later - * . allow only FIPS approved ciphersuites - * . perform all crypto in the FIPS crypto provider - * - * It is currently not possible to use both FIPS compliant SunJSSE and - * standard JSSE at the same time because of the various static data structures - * we use. - * - * However, we do want to allow FIPS mode to be enabled at runtime and without - * editing the java.security file. That means we need to allow - * Security.removeProvider("SunJSSE") to work, which creates an instance of - * this class in non-FIPS mode. That is why we delay the selection of the mode - * as long as possible. This is until we open an SSL/TLS connection and the - * data structures need to be initialized or until SunJSSE is initialized in - * FIPS mode. - * */ public class SunJSSE extends java.security.Provider { 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 bff273c6548a2..e5a6b288ff84d 100644 --- a/src/java.base/share/classes/sun/security/util/Debug.java +++ b/src/java.base/share/classes/sun/security/util/Debug.java @@ -81,6 +81,7 @@ public static void Help() System.err.println("logincontext login context results"); System.err.println("jca JCA engine class debugging"); System.err.println("keystore KeyStore debugging"); + System.err.println("pcsc Smartcard library debugging"); System.err.println("policy loading and granting"); System.err.println("provider security provider debugging"); System.err.println("pkcs11 PKCS11 session manager debugging"); 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 5f74703c5503a..8f81d0035c056 100644 --- a/src/java.base/share/classes/sun/security/util/KeyUtil.java +++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -128,17 +128,19 @@ public static int getKeySize(Key key) { */ public static final int getKeySize(AlgorithmParameters parameters) { - String algorithm = parameters.getAlgorithm(); - switch (algorithm) { + switch (parameters.getAlgorithm()) { case "EC": - try { - ECKeySizeParameterSpec ps = parameters.getParameterSpec( + // ECKeySizeParameterSpec is SunEC internal only + if (parameters.getProvider().getName().equals("SunEC")) { + try { + ECKeySizeParameterSpec ps = parameters.getParameterSpec( ECKeySizeParameterSpec.class); - if (ps != null) { - return ps.getKeySize(); + if (ps != null) { + return ps.getKeySize(); + } + } catch (InvalidParameterSpecException ipse) { + // ignore } - } catch (InvalidParameterSpecException ipse) { - // ignore } try { @@ -291,13 +293,14 @@ public static final boolean isOracleJCEProvider(String providerName) { * contains the lower of that suggested by the client in the client * hello and the highest supported by the server. * @param encoded the encoded key in its "RAW" encoding format - * @param isFailOver whether the previous decryption of the - * encrypted PreMasterSecret message run into problem + * @param failure true if encoded is incorrect according to previous checks * @return the polished PreMasterSecret key in its "RAW" encoding format */ public static byte[] checkTlsPreMasterSecretKey( int clientVersion, int serverVersion, SecureRandom random, - byte[] encoded, boolean isFailOver) { + byte[] encoded, boolean failure) { + + byte[] tmp; if (random == null) { random = JCAUtil.getSecureRandom(); @@ -305,30 +308,38 @@ public static byte[] checkTlsPreMasterSecretKey( byte[] replacer = new byte[48]; random.nextBytes(replacer); - if (!isFailOver && (encoded != null)) { - // check the length - if (encoded.length != 48) { - // private, don't need to clone the byte array. - return replacer; - } - - int encodedVersion = - ((encoded[0] & 0xFF) << 8) | (encoded[1] & 0xFF); - if (clientVersion != encodedVersion) { - if (clientVersion > 0x0301 || // 0x0301: TLSv1 - serverVersion != encodedVersion) { - encoded = replacer; - } // Otherwise, For compatibility, we maintain the behavior - // that the version in pre_master_secret can be the - // negotiated version for TLS v1.0 and SSL v3.0. - } + if (failure) { + tmp = replacer; + } else { + tmp = encoded; + } + if (tmp == null) { + encoded = replacer; + } else { + encoded = tmp; + } + // check the length + if (encoded.length != 48) { // private, don't need to clone the byte array. - return encoded; + tmp = replacer; + } else { + tmp = encoded; } - // private, don't need to clone the byte array. - return replacer; + int encodedVersion = + ((tmp[0] & 0xFF) << 8) | (tmp[1] & 0xFF); + int check1 = 0; + int check2 = 0; + int check3 = 0; + if (clientVersion != encodedVersion) check1 = 1; + if (clientVersion > 0x0301) check2 = 1; + if (serverVersion != encodedVersion) check3 = 1; + if ((check1 & (check2 | check3)) == 1) { + return replacer; + } else { + return tmp; + } } /** diff --git a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java index b1da218666017..e16ae803b962b 100644 --- a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java +++ b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java @@ -847,16 +847,16 @@ private static int initializeMaxSigFileSize() { * the maximum allowed number of bytes for the signature-related files * in a JAR file. */ - Integer tmp = GetIntegerAction.privilegedGetProperty( - "jdk.jar.maxSignatureFileSize", 8000000); + int tmp = GetIntegerAction.privilegedGetProperty( + "jdk.jar.maxSignatureFileSize", 16000000); if (tmp < 0 || tmp > MAX_ARRAY_SIZE) { if (debug != null) { - debug.println("Default signature file size 8000000 bytes " + - "is used as the specified size for the " + - "jdk.jar.maxSignatureFileSize system property " + + debug.println("The default signature file size of 16000000 bytes " + + "will be used for the jdk.jar.maxSignatureFileSize " + + "system property since the specified value " + "is out of range: " + tmp); } - tmp = 8000000; + tmp = 16000000; } return tmp; } diff --git a/src/java.base/share/classes/sun/security/x509/X509CertImpl.java b/src/java.base/share/classes/sun/security/x509/X509CertImpl.java index e2e3c2541e724..656e4c168fbc9 100644 --- a/src/java.base/share/classes/sun/security/x509/X509CertImpl.java +++ b/src/java.base/share/classes/sun/security/x509/X509CertImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -536,7 +536,7 @@ public void checkValidity(Date date) /** * Return the requested attribute from the certificate. - * + *

* Note that the X509CertInfo is not cloned for performance reasons. * Callers must ensure that they do not modify it. All other * attributes are cloned. @@ -1218,7 +1218,7 @@ private static Collection> makeAltNames(GeneralNames names) { for (GeneralName gname : names.names()) { GeneralNameInterface name = gname.getName(); List nameEntry = new ArrayList<>(2); - nameEntry.add(Integer.valueOf(name.getType())); + nameEntry.add(name.getType()); switch (name.getType()) { case GeneralNameInterface.NAME_RFC822: nameEntry.add(((RFC822Name) name).getName()); @@ -1631,4 +1631,20 @@ public static String getFingerprint(String algorithm, } } } + + /** + * Restores the state of this object from the stream. + *

+ * Deserialization of this object is not supported. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + @java.io.Serial + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "X509CertImpls are not directly deserializable"); + } } 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 b9e9098023e4e..5daf1e07336a7 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, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -269,6 +269,7 @@ XBB=XBB XBC=XBC XBD=XBD XCD=XCD +XCG=XCG XDR=XDR XFO=XFO XFU=XFU @@ -494,6 +495,7 @@ xbb=European Monetary Unit xbc=European Unit of Account (XBC) xbd=European Unit of Account (XBD) xcd=East Caribbean Dollar +xcg=Caribbean Guilder xdr=Special Drawing Rights xfo=French Gold Franc xfu=French UIC-Franc diff --git a/src/java.base/share/data/cacerts/certainlyroote1 b/src/java.base/share/data/cacerts/certainlyroote1 new file mode 100644 index 0000000000000..3f0d0face0eb7 --- /dev/null +++ b/src/java.base/share/data/cacerts/certainlyroote1 @@ -0,0 +1,20 @@ +Owner: CN=Certainly Root E1, O=Certainly, C=US +Issuer: CN=Certainly Root E1, O=Certainly, C=US +Serial number: 62533b1470333275cf98d9ab9bfccf8 +Valid from: Thu Apr 01 00:00:00 GMT 2021 until: Sun Apr 01 00:00:00 GMT 2046 +Signature algorithm name: SHA384withECDSA +Subject Public Key Algorithm: 384-bit EC (secp384r1) key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw +CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu +bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ +BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s +eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK ++IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2 +QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4 +hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm +ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG +BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/certainlyrootr1 b/src/java.base/share/data/cacerts/certainlyrootr1 new file mode 100644 index 0000000000000..dbb99fad32c8c --- /dev/null +++ b/src/java.base/share/data/cacerts/certainlyrootr1 @@ -0,0 +1,38 @@ +Owner: CN=Certainly Root R1, O=Certainly, C=US +Issuer: CN=Certainly Root R1, O=Certainly, C=US +Serial number: 8e0ff94b907168653354f4d44439b7e0 +Valid from: Thu Apr 01 00:00:00 GMT 2021 until: Sun Apr 01 00:00:00 GMT 2046 +Signature algorithm name: SHA256withRSA +Subject Public Key Algorithm: 4096-bit RSA key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw +PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy +dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9 +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0 +YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2 +1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT +vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed +aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0 +1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5 +r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5 +cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ +wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ +6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA +2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH +Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR +eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB +/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u +d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr +PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d +8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi +1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd +rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di +taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7 +lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj +yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn +Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy +yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n +wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6 +OV+KmalBWQewLK8= +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/certignarootca b/src/java.base/share/data/cacerts/certignarootca new file mode 100644 index 0000000000000..b79092d0cb5a7 --- /dev/null +++ b/src/java.base/share/data/cacerts/certignarootca @@ -0,0 +1,43 @@ +Owner: CN=Certigna Root CA, OU=0002 48146308100036, O=Dhimyotis, C=FR +Issuer: CN=Certigna Root CA, OU=0002 48146308100036, O=Dhimyotis, C=FR +Serial number: cae91b89f155030da3e6416dc4e3a6e1 +Valid from: Tue Oct 01 08:32:27 GMT 2013 until: Sat Oct 01 08:32:27 GMT 2033 +Signature algorithm name: SHA256withRSA +Subject Public Key Algorithm: 4096-bit RSA key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw +WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw +MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x +MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD +VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX +BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO +ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M +CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu +I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm +TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh +C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf +ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz +IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT +Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k +JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 +hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB +GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov +L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo +dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr +aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq +hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L +6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG +HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 +0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB +lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi +o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 +gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v +faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 +Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh +jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw +3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/digicertcseccrootg5 b/src/java.base/share/data/cacerts/digicertcseccrootg5 new file mode 100644 index 0000000000000..04e1eb1be688e --- /dev/null +++ b/src/java.base/share/data/cacerts/digicertcseccrootg5 @@ -0,0 +1,21 @@ +Owner: CN=DigiCert CS ECC P384 Root G5, O="DigiCert, Inc.", C=US +Issuer: CN=DigiCert CS ECC P384 Root G5, O="DigiCert, Inc.", C=US +Serial number: 3698fe712d519f3ced0fdb7b1643011 +Valid from: Fri Jan 15 00:00:00 GMT 2021 until: Sun Jan 14 23:59:59 GMT 2046 +Signature algorithm name: SHA384withECDSA +Subject Public Key Algorithm: 384-bit EC (secp384r1) key +Version: 3 +-----BEGIN CERTIFICATE----- +MIICFjCCAZ2gAwIBAgIQA2mP5xLVGfPO0P23sWQwETAKBggqhkjOPQQDAzBNMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERp +Z2lDZXJ0IENTIEVDQyBQMzg0IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcNNDYw +MTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIElu +Yy4xJTAjBgNVBAMTHERpZ2lDZXJ0IENTIEVDQyBQMzg0IFJvb3QgRzUwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAR/FK2Ftpf9AiE1TWDoOJOTmz0FEG2v0/7v+rv7c5nz +7DISjcdouIveiaKIVHeNuyF+M5VWlgno1YyhBLibbhkAYuhCKKZYN4QZVSZ7Mzdn +8ppyraGurgBCPBx+uHqeIZyjQjBAMB0GA1UdDgQWBBTwjJhxOThlwjobphdmHcjt +Zd6SNjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQD +AwNnADBkAjAjb+EAGSZQ5EYgZYs3p8/rBuHMMskqoewyDXOiHgIcNWEqTmmrOXft +l4jAfWvqid0CMEPx0VijdT6Gm7ZVEYsX9z3+CmnFf07GdRtalMvqERHGCCKI3tB6 +oqV56OMhp80Tsw== +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/digicertcsrsarootg5 b/src/java.base/share/data/cacerts/digicertcsrsarootg5 new file mode 100644 index 0000000000000..fd570aeee8b55 --- /dev/null +++ b/src/java.base/share/data/cacerts/digicertcsrsarootg5 @@ -0,0 +1,38 @@ +Owner: CN=DigiCert CS RSA4096 Root G5, O="DigiCert, Inc.", C=US +Issuer: CN=DigiCert CS RSA4096 Root G5, O="DigiCert, Inc.", C=US +Serial number: 6cee131be6d55c807f7c0c7fb44e620 +Valid from: Fri Jan 15 00:00:00 GMT 2021 until: Sun Jan 14 23:59:59 GMT 2046 +Signature algorithm name: SHA384withRSA +Subject Public Key Algorithm: 4096-bit RSA key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIFZDCCA0ygAwIBAgIQBs7hMb5tVcgH98DH+0TmIDANBgkqhkiG9w0BAQwFADBM +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJDAiBgNVBAMT +G0RpZ2lDZXJ0IENTIFJTQTQwOTYgUm9vdCBHNTAeFw0yMTAxMTUwMDAwMDBaFw00 +NjAxMTQyMzU5NTlaMEwxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg +SW5jLjEkMCIGA1UEAxMbRGlnaUNlcnQgQ1MgUlNBNDA5NiBSb290IEc1MIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtjNzgNhiA3AULBEcOV58rnyDhh3+ +Ji9MJK2L6oNfqbw9W/wLmEwCRzDs4v7s6DRbZl6/O9cspiX/jFmz3+rafCnZRlBy +CB1u0RsK3R/NmYn6Dw9zxOGcHXUyzW+X2ipqlbJsyQnQ6gt7fRcGSZnv1t7gyFPU +rsZ38Ya7Ixy4wN9Z94590e+C5iaLWji1/3XVstlPCfM3iFDaEaSKFBTRUwQAffNq +RBj+UHAyBxyomg46HcUKH24LJmm3PKJXcCyG+kxulalYQ7msEtb/P+3XQxdrTM6e +xJCr//oQUJqjkFfW54wQrp8WGs81HX/Xdu2KnDWnKLinXSH8MDfd3ggZTxXG56ba +kEeO95RTTI5TAr79meXqhtCvAwLTm6qT8asojiAB/0z7zLcpQPWHpBITBR9DbtdR +UJ84tCDtFwkSj8y5Ga+fzb5pEdOvVRBtF4Z5llLGsgCd5a84sDX0iGuPDgQ9fO6v +zdNqEErGzYbKIj2hSlz7Dv+I31xip8C5HtmsbH44N/53kyXChYpPtTcGWgaBFPHO +lJ2ZkeoyWs5nPW4EZq0MTy2jLvee9Xid9wr9fo/jQopVlrzxnzct/J5flf6MGBv8 +jv1LkK/XA2gSY6zik6eiywTlT2TOA/rGFJ/Zi+jM1GKMa+QALBmfGgbGMYFU+1Mk +mq9Vmbqdda64wt0CAwEAAaNCMEAwHQYDVR0OBBYEFGgBk7HSSkBCaZRGLBxaiKkl +tEdPMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +DAUAA4ICAQCS/O64AnkXAlF9IcVJZ6ek8agkOOsMaOpaQmuc9HPBaUotszcFUEKY +kp4GeSwuBpn2798roM2zkgGDtaDLJ7U8IxqYSaLsLZmlWUOs0rGT1lfXHLyT1sZA +4bNvGVW3E9flQzOktavL2sExZA101iztw41u67uvGUdhYS3A9AW5b3jcOvdCQGVT +kb2ZDZOSVKapN1krm8uZxrw99wSE8JQzHQ+CWjnLLkXDKBmjspuYyPwxa2CP9umG +KLzgPH10XRaJW2kkxxCLxEu7Nk/UWT/DsKSRmfgu0UoBnfWIEu+/WhFqWU9Za1pn +84+0Ew/A2C89KHKqGX8RfWpbn5XnX7eUT/E+oVr/Lcyd3yd3jzJzHGcKdvP6XLG/ +vB29DCibsscXZwszD8O9Ntz7ukILq+2Ew2LWhBapsQdrqW7uxs/msEQpwvCzYYAq +i2/SFFwlh1Rk86RMwaH4p2vq/uo6/HnbDo/cxvPJ1Gze6YOhjh0i7Mk6sgB73Dun +Qhp/3IupET2Op8Agb10JXUNE5o9mzKlbB/Hvm3oOs1ThlP0OLMaT11X9cZg1uAlK +/8YpKCz2Ui3bFBiSJ+IWfozK1GG+goeR65g3P79fXXc/NKwbOEOraHKZMh46Ghml +ozhMI9ej58zVKpIXkAtaS70WvfuGauKJmezkoFUYyaMIHxPgMghy0A== +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/digicerttlseccrootg5 b/src/java.base/share/data/cacerts/digicerttlseccrootg5 new file mode 100644 index 0000000000000..9356292ef086c --- /dev/null +++ b/src/java.base/share/data/cacerts/digicerttlseccrootg5 @@ -0,0 +1,21 @@ +Owner: CN=DigiCert TLS ECC P384 Root G5, O="DigiCert, Inc.", C=US +Issuer: CN=DigiCert TLS ECC P384 Root G5, O="DigiCert, Inc.", C=US +Serial number: 9e09365acf7d9c8b93e1c0b042a2ef3 +Valid from: Fri Jan 15 00:00:00 GMT 2021 until: Sun Jan 14 23:59:59 GMT 2046 +Signature algorithm name: SHA384withECDSA +Subject Public Key Algorithm: 384-bit EC (secp384r1) key +Version: 3 +-----BEGIN CERTIFICATE----- +MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp +Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 +MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ +bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS +7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp +0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS +B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 +BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ +LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 +DXZDjC5Ty3zfDBeWUA== +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/digicerttlsrsarootg5 b/src/java.base/share/data/cacerts/digicerttlsrsarootg5 new file mode 100644 index 0000000000000..ac66e174f06ba --- /dev/null +++ b/src/java.base/share/data/cacerts/digicerttlsrsarootg5 @@ -0,0 +1,38 @@ +Owner: CN=DigiCert TLS RSA4096 Root G5, O="DigiCert, Inc.", C=US +Issuer: CN=DigiCert TLS RSA4096 Root G5, O="DigiCert, Inc.", C=US +Serial number: 8f9b478a8fa7eda6a333789de7ccf8a +Valid from: Fri Jan 15 00:00:00 GMT 2021 until: Sun Jan 14 23:59:59 GMT 2046 +Signature algorithm name: SHA384withRSA +Subject Public Key Algorithm: 4096-bit RSA key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT +HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN +NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs +IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+ +ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0 +2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp +wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM +pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD +nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po +sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx +Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd +Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX +KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe +XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL +tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv +TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN +AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw +GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H +PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF +O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ +REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik +AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv +/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+ +p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw +MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF +qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK +ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/emsigneccrootcag3 b/src/java.base/share/data/cacerts/emsigneccrootcag3 new file mode 100644 index 0000000000000..a286f81c2f451 --- /dev/null +++ b/src/java.base/share/data/cacerts/emsigneccrootcag3 @@ -0,0 +1,22 @@ +Owner: CN=emSign ECC Root CA - G3, O=eMudhra Technologies Limited, OU=emSign PKI, C=IN +Issuer: CN=emSign ECC Root CA - G3, O=eMudhra Technologies Limited, OU=emSign PKI, C=IN +Serial number: 3cf607a968700eda8b84 +Valid from: Sun Feb 18 18:30:00 GMT 2018 until: Wed Feb 18 18:30:00 GMT 2043 +Signature algorithm name: SHA384withECDSA +Subject Public Key Algorithm: 384-bit EC (secp384r1) key +Version: 3 +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG +EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo +bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 +WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS +fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB +zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB +CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD ++JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/emsignrootcag1 b/src/java.base/share/data/cacerts/emsignrootcag1 new file mode 100644 index 0000000000000..6b06f6689bc0b --- /dev/null +++ b/src/java.base/share/data/cacerts/emsignrootcag1 @@ -0,0 +1,29 @@ +Owner: CN=emSign Root CA - G1, O=eMudhra Technologies Limited, OU=emSign PKI, C=IN +Issuer: CN=emSign Root CA - G1, O=eMudhra Technologies Limited, OU=emSign PKI, C=IN +Serial number: 31f5e4620c6c58edd6d8 +Valid from: Sun Feb 18 18:30:00 GMT 2018 until: Wed Feb 18 18:30:00 GMT 2043 +Signature algorithm name: SHA256withRSA +Subject Public Key Algorithm: 2048-bit RSA key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/emsignrootcag2 b/src/java.base/share/data/cacerts/emsignrootcag2 new file mode 100644 index 0000000000000..e4e4ddda65a69 --- /dev/null +++ b/src/java.base/share/data/cacerts/emsignrootcag2 @@ -0,0 +1,39 @@ +Owner: CN=emSign Root CA - G2, O=eMudhra Technologies Limited, OU=emSign PKI, C=IN +Issuer: CN=emSign Root CA - G2, O=eMudhra Technologies Limited, OU=emSign PKI, C=IN +Serial number: 864dbf0fe35ed77d8ed8 +Valid from: Sun Feb 18 18:30:00 GMT 2018 until: Wed Feb 18 18:30:00 GMT 2043 +Signature algorithm name: SHA384withRSA +Subject Public Key Algorithm: 4096-bit RSA key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIFlTCCA32gAwIBAgILAIZNvw/jXtd9jtgwDQYJKoZIhvcNAQEMBQAwZzELMAkG +A1UEBhMCSU4xEzARBgNVBAsTCmVtU2lnbiBQS0kxJTAjBgNVBAoTHGVNdWRocmEg +VGVjaG5vbG9naWVzIExpbWl0ZWQxHDAaBgNVBAMTE2VtU2lnbiBSb290IENBIC0g +RzIwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBnMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMjCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMNwGIWW2kHfHK+sXTNwxF07K+IV +ySTuyFM2r1v002wUfcdT+zs5OM5QbMYFFnedXQI6gCFLsjKrcaej48Zt37OyEb3i +aPs7CsP4kAyTwzKH9aZe6gXYHrJq40/ZVMNcQVI2PcIp40B/SAN2gUZ+ZaUtIOvV +jEx26/ebNaXRIsthlkOG/caB+QRwDw1tl7338Zlv0M2oTBUy4B3e7dGP5pgXH71M +jqHPCoNo+xv9f0NTBT+hUDa8h8wUtcGQq9CDeJTpjWcD2bP2AMdVG6oVpMAUeUzo +cCyglvtFdUMjggxBbw4qhau1HXPG8Ot9hwL7ZMi8tkTzrvUIxxb8G9LF/7kKeCE7 +tGZaVzDTnXuifl3msR4ErHsQ4P7lVu2AIjIAhrAXoedDidb7pMcf7TABdrYUT1Jo +G/AiK+J9jO6GTjeADD4LMDSBZhHMuBK/PJ/g0kGBt+/C1L+/HURzQhJkMlRnM6Rv +XoCtfKopSlns5trZmTi971Wjbn88QXP61lGpBCUPwCjs7rpOYvSUJtI+lcbF+37q +kIqOXYkVT3cupDSpw+H89kFtj5GKY+Xny4LxY+3IvDIRiyd6ky1DPj713DI0yqve +EpsIr3A0PdwuyUI7CS1jg0NnGFT6Xxyr0xB+VDt83FJYW8v16k2pbaQ4kVxA3aXd +X9dZYyVR1S59KM75AgMBAAGjQjBAMB0GA1UdDgQWBBTt7E1FYRgo57MjKBEcTaUn +DV7s9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B +AQwFAAOCAgEACFC/ilQg8KTCVBxFJW/sazomkS0kNYbEIZg4B3obqwsJ7SX98z8Z +gfzBpz0nYClwwJjWbFN1R2zY8pCEot6/dgmA8Vbq0GxhwPM5YN/SZquNyRIxO3cU +dlAcwf+vSezdVCf9wOzvSAF3q0a5ljvbdbNJNpfScQVp7UUd5sBsZk8jXO1KQ/go +/Vf/GDPnrIFmxpAIGE3sgnO8lAv9FzUaAeuv7HWe47xN9J7+bQzF93yHuIXACPTL +pQHhg2zMv5C7BAbuDHfbj1Cu294Z832yhSfBcziWGskOvl3es2EcHytbS9c9P+0z +Mpka7zGC1FHrvLb/FoduH86TeZt0QjZ6pcplNzoaxDnDvzTJ6CC2Eny+qH/APFCu +VUv5/wjwF+HPm8Pup2ARj9cEp92+0qcerfHacNq5hMeGZdbA/dzdUR/5z5zXdxAk +nl8mcfGb0eMNSTXQmmB/i4AecNnr72uYjzlaXUGYN7Nrb6XouG0pnh0/BBtWWp0U +ShIPpWEAqs7RJBj6+1ZUYXZ4ObrCw962DxhN2p19Hxw9LtuUUcLqqTPrFXYvwO4t +ouj7KJnAkaTUfXGdEaFVtFig1EA30WzJY2X1vAQ7hVnniCjgaXAGqjsU6sklNM9n +xDx5rFCCCEtj9Kh8UHjGK2QqgP5kwgttjOApQMaCoezMfK4KD7WpOXU= +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/letsencryptisrgx2 b/src/java.base/share/data/cacerts/letsencryptisrgx2 new file mode 100644 index 0000000000000..455822e13a810 --- /dev/null +++ b/src/java.base/share/data/cacerts/letsencryptisrgx2 @@ -0,0 +1,21 @@ +Owner: CN=ISRG Root X2, O=Internet Security Research Group, C=US +Issuer: CN=ISRG Root X2, O=Internet Security Research Group, C=US +Serial number: 41d29dd172eaeea780c12c6ce92f8752 +Valid from: Fri Sep 04 00:00:00 GMT 2020 until: Mon Sep 17 16:00:00 GMT 2040 +Signature algorithm name: SHA384withECDSA +Subject Public Key Algorithm: 384-bit EC (secp384r1) key +Version: 3 +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/teliarootcav2 b/src/java.base/share/data/cacerts/teliarootcav2 new file mode 100644 index 0000000000000..24ed624291f8e --- /dev/null +++ b/src/java.base/share/data/cacerts/teliarootcav2 @@ -0,0 +1,39 @@ +Owner: CN=Telia Root CA v2, O=Telia Finland Oyj, C=FI +Issuer: CN=Telia Root CA v2, O=Telia Finland Oyj, C=FI +Serial number: 1675f27d6fe7ae3e4acbe095b059e +Valid from: Thu Nov 29 11:55:54 GMT 2018 until: Sun Nov 29 11:55:54 GMT 2043 +Signature algorithm name: SHA256withRSA +Subject Public Key Algorithm: 4096-bit RSA key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx +CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE +AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1 +NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ +MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq +AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9 +vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9 +lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD +n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT +7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o +6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC +TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6 +WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R +DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI +pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj +YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy +rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ +8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi +0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM +A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS +SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K +TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF +6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er +3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt +Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT +VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW +ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA +rBPuUBQemMc= +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/currency/CurrencyData.properties b/src/java.base/share/data/currency/CurrencyData.properties index 12c0c69801efc..26f4aa24d88d8 100644 --- a/src/java.base/share/data/currency/CurrencyData.properties +++ b/src/java.base/share/data/currency/CurrencyData.properties @@ -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=175 +dataVersion=176 # List of all valid ISO 4217 currency codes. # To ensure compatibility, do not remove codes. @@ -55,7 +55,7 @@ all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036 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-\ - XBB956-XBC957-XBD958-XCD951-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\ + XBB956-XBC957-XBD958-XCD951-XCG532-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\ XPT962-XSU994-XTS963-XUA965-XXX999-YER886-YUM891-ZAR710-ZMK894-ZMW967-ZWD716-ZWL932-\ ZWN942-ZWR935 @@ -189,11 +189,11 @@ CR=CRC # COTE D'IVOIRE CI=XOF # CROATIA -HR=HRK;2022-12-31-23-00-00;EUR +HR=EUR # CUBA CU=CUP # Cura\u00e7ao -CW=ANG +CW=ANG;2025-04-01-04-00-00;XCG # CYPRUS CY=EUR # CZECHIA @@ -510,7 +510,7 @@ SR=SRD # SVALBARD AND JAN MAYEN SJ=NOK # Sint Maarten (Dutch part) -SX=ANG +SX=ANG;2025-04-01-04-00-00;XCG # ESWATINI SZ=SZL # SWEDEN diff --git a/src/java.base/share/data/publicsuffixlist/VERSION b/src/java.base/share/data/publicsuffixlist/VERSION index 4ffc88dbd8332..f86d2df03ca38 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/88467c960d6cdad2ca1623e892e5e17506bc269f/public_suffix_list.dat -Date: 2023-04-14 +Github: https://raw.githubusercontent.com/publicsuffix/list/b5bf572c52988dbe9d865b8f090ea819024a9936/public_suffix_list.dat +Date: 2023-11-09 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 d9f0c71dbb447..fff6e9a494d64 100644 --- a/src/java.base/share/data/publicsuffixlist/public_suffix_list.dat +++ b/src/java.base/share/data/publicsuffixlist/public_suffix_list.dat @@ -1059,22 +1059,11 @@ gouv.fr nom.fr prd.fr tm.fr -// Former "domaines sectoriels", still registration suffixes -aeroport.fr -avocat.fr +// Other SLDs now selfmanaged out of AFNIC range. Former "domaines sectoriels", still registration suffixes avoues.fr cci.fr -chambagri.fr -chirurgiens-dentistes.fr -experts-comptables.fr -geometre-expert.fr greta.fr huissier-justice.fr -medecin.fr -notaires.fr -pharmacien.fr -port.fr -veterinaire.fr // ga : https://en.wikipedia.org/wiki/.ga ga @@ -5146,52 +5135,60 @@ turystyka.pl // Government domains gov.pl ap.gov.pl +griw.gov.pl ic.gov.pl is.gov.pl -us.gov.pl kmpsp.gov.pl +konsulat.gov.pl kppsp.gov.pl -kwpsp.gov.pl -psp.gov.pl -wskr.gov.pl kwp.gov.pl +kwpsp.gov.pl +mup.gov.pl mw.gov.pl -ug.gov.pl -um.gov.pl -umig.gov.pl -ugim.gov.pl -upow.gov.pl -uw.gov.pl -starostwo.gov.pl +oia.gov.pl +oirm.gov.pl +oke.gov.pl +oow.gov.pl +oschr.gov.pl +oum.gov.pl pa.gov.pl +pinb.gov.pl +piw.gov.pl po.gov.pl +pr.gov.pl +psp.gov.pl psse.gov.pl pup.gov.pl rzgw.gov.pl sa.gov.pl +sdn.gov.pl +sko.gov.pl so.gov.pl sr.gov.pl -wsa.gov.pl -sko.gov.pl +starostwo.gov.pl +ug.gov.pl +ugim.gov.pl +um.gov.pl +umig.gov.pl +upow.gov.pl +uppo.gov.pl +us.gov.pl +uw.gov.pl uzs.gov.pl +wif.gov.pl wiih.gov.pl winb.gov.pl -pinb.gov.pl wios.gov.pl witd.gov.pl -wzmiuw.gov.pl -piw.gov.pl wiw.gov.pl -griw.gov.pl -wif.gov.pl -oum.gov.pl -sdn.gov.pl -zp.gov.pl -uppo.gov.pl -mup.gov.pl +wkz.gov.pl +wsa.gov.pl +wskr.gov.pl +wsse.gov.pl wuoz.gov.pl -konsulat.gov.pl -oirm.gov.pl +wzmiuw.gov.pl +zp.gov.pl +zpisdn.gov.pl // pl regional domains (http://www.dns.pl/english/index.html) augustow.pl babia-gora.pl @@ -5876,6 +5873,7 @@ kiev.ua kirovograd.ua km.ua kr.ua +kropyvnytskyi.ua krym.ua ks.ua kv.ua @@ -5883,6 +5881,7 @@ kyiv.ua lg.ua lt.ua lugansk.ua +luhansk.ua lutsk.ua lv.ua lviv.ua @@ -5906,11 +5905,13 @@ te.ua ternopil.ua uz.ua uzhgorod.ua +uzhhorod.ua vinnica.ua vinnytsia.ua vn.ua volyn.ua yalta.ua +zakarpattia.ua zaporizhzhe.ua zaporizhzhia.ua zhitomir.ua @@ -6022,7 +6023,6 @@ k12.ca.us k12.co.us k12.ct.us k12.dc.us -k12.de.us k12.fl.us k12.ga.us k12.gu.us @@ -6264,20 +6264,89 @@ k12.vi net.vi org.vi -// vn : https://www.dot.vn/vnnic/vnnic/domainregistration.jsp +// vn : https://www.vnnic.vn/en/domain/cctld-vn +// https://vnnic.vn/sites/default/files/tailieu/vn.cctld.domains.txt vn +ac.vn +ai.vn +biz.vn com.vn -net.vn -org.vn edu.vn gov.vn -int.vn -ac.vn -biz.vn +health.vn +id.vn info.vn +int.vn +io.vn name.vn +net.vn +org.vn pro.vn -health.vn + +// vn geographical names +angiang.vn +bacgiang.vn +backan.vn +baclieu.vn +bacninh.vn +baria-vungtau.vn +bentre.vn +binhdinh.vn +binhduong.vn +binhphuoc.vn +binhthuan.vn +camau.vn +cantho.vn +caobang.vn +daklak.vn +daknong.vn +danang.vn +dienbien.vn +dongnai.vn +dongthap.vn +gialai.vn +hagiang.vn +haiduong.vn +haiphong.vn +hanam.vn +hanoi.vn +hatinh.vn +haugiang.vn +hoabinh.vn +hungyen.vn +khanhhoa.vn +kiengiang.vn +kontum.vn +laichau.vn +lamdong.vn +langson.vn +laocai.vn +longan.vn +namdinh.vn +nghean.vn +ninhbinh.vn +ninhthuan.vn +phutho.vn +phuyen.vn +quangbinh.vn +quangnam.vn +quangngai.vn +quangninh.vn +quangtri.vn +soctrang.vn +sonla.vn +tayninh.vn +thaibinh.vn +thainguyen.vn +thanhhoa.vn +thanhphohochiminh.vn +thuathienhue.vn +tiengiang.vn +travinh.vn +tuyenquang.vn +vinhlong.vn +vinhphuc.vn +yenbai.vn // vu : https://en.wikipedia.org/wiki/.vu // http://www.vunic.vu/ @@ -6641,3447 +6710,4506 @@ org.zw // newGTLDs -// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2023-04-14T15:13:16Z +// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2023-11-03T15:13:18Z // This list is auto-generated, don't edit it manually. -// aaa : 2015-02-26 American Automobile Association, Inc. +// aaa : American Automobile Association, Inc. +// https://www.iana.org/domains/root/db/aaa.html aaa -// aarp : 2015-05-21 AARP +// aarp : AARP +// https://www.iana.org/domains/root/db/aarp.html aarp -// abarth : 2015-07-30 Fiat Chrysler Automobiles N.V. -abarth - -// abb : 2014-10-24 ABB Ltd +// abb : ABB Ltd +// https://www.iana.org/domains/root/db/abb.html abb -// abbott : 2014-07-24 Abbott Laboratories, Inc. +// abbott : Abbott Laboratories, Inc. +// https://www.iana.org/domains/root/db/abbott.html abbott -// abbvie : 2015-07-30 AbbVie Inc. +// abbvie : AbbVie Inc. +// https://www.iana.org/domains/root/db/abbvie.html abbvie -// abc : 2015-07-30 Disney Enterprises, Inc. +// abc : Disney Enterprises, Inc. +// https://www.iana.org/domains/root/db/abc.html abc -// able : 2015-06-25 Able Inc. +// able : Able Inc. +// https://www.iana.org/domains/root/db/able.html able -// abogado : 2014-04-24 Registry Services, LLC +// abogado : Registry Services, LLC +// https://www.iana.org/domains/root/db/abogado.html abogado -// abudhabi : 2015-07-30 Abu Dhabi Systems and Information Centre +// abudhabi : Abu Dhabi Systems and Information Centre +// https://www.iana.org/domains/root/db/abudhabi.html abudhabi -// academy : 2013-11-07 Binky Moon, LLC +// academy : Binky Moon, LLC +// https://www.iana.org/domains/root/db/academy.html academy -// accenture : 2014-08-15 Accenture plc +// accenture : Accenture plc +// https://www.iana.org/domains/root/db/accenture.html accenture -// accountant : 2014-11-20 dot Accountant Limited +// accountant : dot Accountant Limited +// https://www.iana.org/domains/root/db/accountant.html accountant -// accountants : 2014-03-20 Binky Moon, LLC +// accountants : Binky Moon, LLC +// https://www.iana.org/domains/root/db/accountants.html accountants -// aco : 2015-01-08 ACO Severin Ahlmann GmbH & Co. KG +// aco : ACO Severin Ahlmann GmbH & Co. KG +// https://www.iana.org/domains/root/db/aco.html aco -// actor : 2013-12-12 Dog Beach, LLC +// actor : Dog Beach, LLC +// https://www.iana.org/domains/root/db/actor.html actor -// ads : 2014-12-04 Charleston Road Registry Inc. +// ads : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/ads.html ads -// adult : 2014-10-16 ICM Registry AD LLC +// adult : ICM Registry AD LLC +// https://www.iana.org/domains/root/db/adult.html adult -// aeg : 2015-03-19 Aktiebolaget Electrolux +// aeg : Aktiebolaget Electrolux +// https://www.iana.org/domains/root/db/aeg.html aeg -// aetna : 2015-05-21 Aetna Life Insurance Company +// aetna : Aetna Life Insurance Company +// https://www.iana.org/domains/root/db/aetna.html aetna -// afl : 2014-10-02 Australian Football League +// afl : Australian Football League +// https://www.iana.org/domains/root/db/afl.html afl -// africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa +// africa : ZA Central Registry NPC trading as Registry.Africa +// https://www.iana.org/domains/root/db/africa.html africa -// agakhan : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) +// agakhan : Fondation Aga Khan (Aga Khan Foundation) +// https://www.iana.org/domains/root/db/agakhan.html agakhan -// agency : 2013-11-14 Binky Moon, LLC +// agency : Binky Moon, LLC +// https://www.iana.org/domains/root/db/agency.html agency -// aig : 2014-12-18 American International Group, Inc. +// aig : American International Group, Inc. +// https://www.iana.org/domains/root/db/aig.html aig -// airbus : 2015-07-30 Airbus S.A.S. +// airbus : Airbus S.A.S. +// https://www.iana.org/domains/root/db/airbus.html airbus -// airforce : 2014-03-06 Dog Beach, LLC +// airforce : Dog Beach, LLC +// https://www.iana.org/domains/root/db/airforce.html airforce -// airtel : 2014-10-24 Bharti Airtel Limited +// airtel : Bharti Airtel Limited +// https://www.iana.org/domains/root/db/airtel.html airtel -// akdn : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) +// akdn : Fondation Aga Khan (Aga Khan Foundation) +// https://www.iana.org/domains/root/db/akdn.html akdn -// alfaromeo : 2015-07-31 Fiat Chrysler Automobiles N.V. -alfaromeo - -// alibaba : 2015-01-15 Alibaba Group Holding Limited +// alibaba : Alibaba Group Holding Limited +// https://www.iana.org/domains/root/db/alibaba.html alibaba -// alipay : 2015-01-15 Alibaba Group Holding Limited +// alipay : Alibaba Group Holding Limited +// https://www.iana.org/domains/root/db/alipay.html alipay -// allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft +// allfinanz : Allfinanz Deutsche Vermögensberatung Aktiengesellschaft +// https://www.iana.org/domains/root/db/allfinanz.html allfinanz -// allstate : 2015-07-31 Allstate Fire and Casualty Insurance Company +// allstate : Allstate Fire and Casualty Insurance Company +// https://www.iana.org/domains/root/db/allstate.html allstate -// ally : 2015-06-18 Ally Financial Inc. +// ally : Ally Financial Inc. +// https://www.iana.org/domains/root/db/ally.html ally -// alsace : 2014-07-02 Region Grand Est +// alsace : Region Grand Est +// https://www.iana.org/domains/root/db/alsace.html alsace -// alstom : 2015-07-30 ALSTOM +// alstom : ALSTOM +// https://www.iana.org/domains/root/db/alstom.html alstom -// amazon : 2019-12-19 Amazon Registry Services, Inc. +// amazon : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/amazon.html amazon -// americanexpress : 2015-07-31 American Express Travel Related Services Company, Inc. +// americanexpress : American Express Travel Related Services Company, Inc. +// https://www.iana.org/domains/root/db/americanexpress.html americanexpress -// americanfamily : 2015-07-23 AmFam, Inc. +// americanfamily : AmFam, Inc. +// https://www.iana.org/domains/root/db/americanfamily.html americanfamily -// amex : 2015-07-31 American Express Travel Related Services Company, Inc. +// amex : American Express Travel Related Services Company, Inc. +// https://www.iana.org/domains/root/db/amex.html amex -// amfam : 2015-07-23 AmFam, Inc. +// amfam : AmFam, Inc. +// https://www.iana.org/domains/root/db/amfam.html amfam -// amica : 2015-05-28 Amica Mutual Insurance Company +// amica : Amica Mutual Insurance Company +// https://www.iana.org/domains/root/db/amica.html amica -// amsterdam : 2014-07-24 Gemeente Amsterdam +// amsterdam : Gemeente Amsterdam +// https://www.iana.org/domains/root/db/amsterdam.html amsterdam -// analytics : 2014-12-18 Campus IP LLC +// analytics : Campus IP LLC +// https://www.iana.org/domains/root/db/analytics.html analytics -// android : 2014-08-07 Charleston Road Registry Inc. +// android : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/android.html android -// anquan : 2015-01-08 Beijing Qihu Keji Co., Ltd. +// anquan : Beijing Qihu Keji Co., Ltd. +// https://www.iana.org/domains/root/db/anquan.html anquan -// anz : 2015-07-31 Australia and New Zealand Banking Group Limited +// anz : Australia and New Zealand Banking Group Limited +// https://www.iana.org/domains/root/db/anz.html anz -// aol : 2015-09-17 Oath Inc. +// aol : Oath Inc. +// https://www.iana.org/domains/root/db/aol.html aol -// apartments : 2014-12-11 Binky Moon, LLC +// apartments : Binky Moon, LLC +// https://www.iana.org/domains/root/db/apartments.html apartments -// app : 2015-05-14 Charleston Road Registry Inc. +// app : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/app.html app -// apple : 2015-05-14 Apple Inc. +// apple : Apple Inc. +// https://www.iana.org/domains/root/db/apple.html apple -// aquarelle : 2014-07-24 Aquarelle.com +// aquarelle : Aquarelle.com +// https://www.iana.org/domains/root/db/aquarelle.html aquarelle -// arab : 2015-11-12 League of Arab States +// arab : League of Arab States +// https://www.iana.org/domains/root/db/arab.html arab -// aramco : 2014-11-20 Aramco Services Company +// aramco : Aramco Services Company +// https://www.iana.org/domains/root/db/aramco.html aramco -// archi : 2014-02-06 Identity Digital Limited +// archi : Identity Digital Limited +// https://www.iana.org/domains/root/db/archi.html archi -// army : 2014-03-06 Dog Beach, LLC +// army : Dog Beach, LLC +// https://www.iana.org/domains/root/db/army.html army -// art : 2016-03-24 UK Creative Ideas Limited +// art : UK Creative Ideas Limited +// https://www.iana.org/domains/root/db/art.html art -// arte : 2014-12-11 Association Relative à la Télévision Européenne G.E.I.E. +// arte : Association Relative à la Télévision Européenne G.E.I.E. +// https://www.iana.org/domains/root/db/arte.html arte -// asda : 2015-07-31 Wal-Mart Stores, Inc. +// asda : Wal-Mart Stores, Inc. +// https://www.iana.org/domains/root/db/asda.html asda -// associates : 2014-03-06 Binky Moon, LLC +// associates : Binky Moon, LLC +// https://www.iana.org/domains/root/db/associates.html associates -// athleta : 2015-07-30 The Gap, Inc. +// athleta : The Gap, Inc. +// https://www.iana.org/domains/root/db/athleta.html athleta -// attorney : 2014-03-20 Dog Beach, LLC +// attorney : Dog Beach, LLC +// https://www.iana.org/domains/root/db/attorney.html attorney -// auction : 2014-03-20 Dog Beach, LLC +// auction : Dog Beach, LLC +// https://www.iana.org/domains/root/db/auction.html auction -// audi : 2015-05-21 AUDI Aktiengesellschaft +// audi : AUDI Aktiengesellschaft +// https://www.iana.org/domains/root/db/audi.html audi -// audible : 2015-06-25 Amazon Registry Services, Inc. +// audible : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/audible.html audible -// audio : 2014-03-20 XYZ.COM LLC +// audio : XYZ.COM LLC +// https://www.iana.org/domains/root/db/audio.html audio -// auspost : 2015-08-13 Australian Postal Corporation +// auspost : Australian Postal Corporation +// https://www.iana.org/domains/root/db/auspost.html auspost -// author : 2014-12-18 Amazon Registry Services, Inc. +// author : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/author.html author -// auto : 2014-11-13 XYZ.COM LLC +// auto : XYZ.COM LLC +// https://www.iana.org/domains/root/db/auto.html auto -// autos : 2014-01-09 XYZ.COM LLC +// autos : XYZ.COM LLC +// https://www.iana.org/domains/root/db/autos.html autos -// avianca : 2015-01-08 Avianca Inc. +// avianca : Avianca Inc. +// https://www.iana.org/domains/root/db/avianca.html avianca -// aws : 2015-06-25 AWS Registry LLC +// aws : AWS Registry LLC +// https://www.iana.org/domains/root/db/aws.html aws -// axa : 2013-12-19 AXA Group Operations SAS +// axa : AXA Group Operations SAS +// https://www.iana.org/domains/root/db/axa.html axa -// azure : 2014-12-18 Microsoft Corporation +// azure : Microsoft Corporation +// https://www.iana.org/domains/root/db/azure.html azure -// baby : 2015-04-09 XYZ.COM LLC +// baby : XYZ.COM LLC +// https://www.iana.org/domains/root/db/baby.html baby -// baidu : 2015-01-08 Baidu, Inc. +// baidu : Baidu, Inc. +// https://www.iana.org/domains/root/db/baidu.html baidu -// banamex : 2015-07-30 Citigroup Inc. +// banamex : Citigroup Inc. +// https://www.iana.org/domains/root/db/banamex.html banamex -// bananarepublic : 2015-07-31 The Gap, Inc. +// bananarepublic : The Gap, Inc. +// https://www.iana.org/domains/root/db/bananarepublic.html bananarepublic -// band : 2014-06-12 Dog Beach, LLC +// band : Dog Beach, LLC +// https://www.iana.org/domains/root/db/band.html band -// bank : 2014-09-25 fTLD Registry Services LLC +// bank : fTLD Registry Services LLC +// https://www.iana.org/domains/root/db/bank.html bank -// bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +// bar : Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +// https://www.iana.org/domains/root/db/bar.html bar -// barcelona : 2014-07-24 Municipi de Barcelona +// barcelona : Municipi de Barcelona +// https://www.iana.org/domains/root/db/barcelona.html barcelona -// barclaycard : 2014-11-20 Barclays Bank PLC +// barclaycard : Barclays Bank PLC +// https://www.iana.org/domains/root/db/barclaycard.html barclaycard -// barclays : 2014-11-20 Barclays Bank PLC +// barclays : Barclays Bank PLC +// https://www.iana.org/domains/root/db/barclays.html barclays -// barefoot : 2015-06-11 Gallo Vineyards, Inc. +// barefoot : Gallo Vineyards, Inc. +// https://www.iana.org/domains/root/db/barefoot.html barefoot -// bargains : 2013-11-14 Binky Moon, LLC +// bargains : Binky Moon, LLC +// https://www.iana.org/domains/root/db/bargains.html bargains -// baseball : 2015-10-29 MLB Advanced Media DH, LLC +// baseball : MLB Advanced Media DH, LLC +// https://www.iana.org/domains/root/db/baseball.html baseball -// basketball : 2015-08-20 Fédération Internationale de Basketball (FIBA) +// basketball : Fédération Internationale de Basketball (FIBA) +// https://www.iana.org/domains/root/db/basketball.html basketball -// bauhaus : 2014-04-17 Werkhaus GmbH +// bauhaus : Werkhaus GmbH +// https://www.iana.org/domains/root/db/bauhaus.html bauhaus -// bayern : 2014-01-23 Bayern Connect GmbH +// bayern : Bayern Connect GmbH +// https://www.iana.org/domains/root/db/bayern.html bayern -// bbc : 2014-12-18 British Broadcasting Corporation +// bbc : British Broadcasting Corporation +// https://www.iana.org/domains/root/db/bbc.html bbc -// bbt : 2015-07-23 BB&T Corporation +// bbt : BB&T Corporation +// https://www.iana.org/domains/root/db/bbt.html bbt -// bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A. +// bbva : BANCO BILBAO VIZCAYA ARGENTARIA, S.A. +// https://www.iana.org/domains/root/db/bbva.html bbva -// bcg : 2015-04-02 The Boston Consulting Group, Inc. +// bcg : The Boston Consulting Group, Inc. +// https://www.iana.org/domains/root/db/bcg.html bcg -// bcn : 2014-07-24 Municipi de Barcelona +// bcn : Municipi de Barcelona +// https://www.iana.org/domains/root/db/bcn.html bcn -// beats : 2015-05-14 Beats Electronics, LLC +// beats : Beats Electronics, LLC +// https://www.iana.org/domains/root/db/beats.html beats -// beauty : 2015-12-03 XYZ.COM LLC +// beauty : XYZ.COM LLC +// https://www.iana.org/domains/root/db/beauty.html beauty -// beer : 2014-01-09 Registry Services, LLC +// beer : Registry Services, LLC +// https://www.iana.org/domains/root/db/beer.html beer -// bentley : 2014-12-18 Bentley Motors Limited +// bentley : Bentley Motors Limited +// https://www.iana.org/domains/root/db/bentley.html bentley -// berlin : 2013-10-31 dotBERLIN GmbH & Co. KG +// berlin : dotBERLIN GmbH & Co. KG +// https://www.iana.org/domains/root/db/berlin.html berlin -// best : 2013-12-19 BestTLD Pty Ltd +// best : BestTLD Pty Ltd +// https://www.iana.org/domains/root/db/best.html best -// bestbuy : 2015-07-31 BBY Solutions, Inc. +// bestbuy : BBY Solutions, Inc. +// https://www.iana.org/domains/root/db/bestbuy.html bestbuy -// bet : 2015-05-07 Identity Digital Limited +// bet : Identity Digital Limited +// https://www.iana.org/domains/root/db/bet.html bet -// bharti : 2014-01-09 Bharti Enterprises (Holding) Private Limited +// bharti : Bharti Enterprises (Holding) Private Limited +// https://www.iana.org/domains/root/db/bharti.html bharti -// bible : 2014-06-19 American Bible Society +// bible : American Bible Society +// https://www.iana.org/domains/root/db/bible.html bible -// bid : 2013-12-19 dot Bid Limited +// bid : dot Bid Limited +// https://www.iana.org/domains/root/db/bid.html bid -// bike : 2013-08-27 Binky Moon, LLC +// bike : Binky Moon, LLC +// https://www.iana.org/domains/root/db/bike.html bike -// bing : 2014-12-18 Microsoft Corporation +// bing : Microsoft Corporation +// https://www.iana.org/domains/root/db/bing.html bing -// bingo : 2014-12-04 Binky Moon, LLC +// bingo : Binky Moon, LLC +// https://www.iana.org/domains/root/db/bingo.html bingo -// bio : 2014-03-06 Identity Digital Limited +// bio : Identity Digital Limited +// https://www.iana.org/domains/root/db/bio.html bio -// black : 2014-01-16 Identity Digital Limited +// black : Identity Digital Limited +// https://www.iana.org/domains/root/db/black.html black -// blackfriday : 2014-01-16 Registry Services, LLC +// blackfriday : Registry Services, LLC +// https://www.iana.org/domains/root/db/blackfriday.html blackfriday -// blockbuster : 2015-07-30 Dish DBS Corporation +// blockbuster : Dish DBS Corporation +// https://www.iana.org/domains/root/db/blockbuster.html blockbuster -// blog : 2015-05-14 Knock Knock WHOIS There, LLC +// blog : Knock Knock WHOIS There, LLC +// https://www.iana.org/domains/root/db/blog.html blog -// bloomberg : 2014-07-17 Bloomberg IP Holdings LLC +// bloomberg : Bloomberg IP Holdings LLC +// https://www.iana.org/domains/root/db/bloomberg.html bloomberg -// blue : 2013-11-07 Identity Digital Limited +// blue : Identity Digital Limited +// https://www.iana.org/domains/root/db/blue.html blue -// bms : 2014-10-30 Bristol-Myers Squibb Company +// bms : Bristol-Myers Squibb Company +// https://www.iana.org/domains/root/db/bms.html bms -// bmw : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft +// bmw : Bayerische Motoren Werke Aktiengesellschaft +// https://www.iana.org/domains/root/db/bmw.html bmw -// bnpparibas : 2014-05-29 BNP Paribas +// bnpparibas : BNP Paribas +// https://www.iana.org/domains/root/db/bnpparibas.html bnpparibas -// boats : 2014-12-04 XYZ.COM LLC +// boats : XYZ.COM LLC +// https://www.iana.org/domains/root/db/boats.html boats -// boehringer : 2015-07-09 Boehringer Ingelheim International GmbH +// boehringer : Boehringer Ingelheim International GmbH +// https://www.iana.org/domains/root/db/boehringer.html boehringer -// bofa : 2015-07-31 Bank of America Corporation +// bofa : Bank of America Corporation +// https://www.iana.org/domains/root/db/bofa.html bofa -// bom : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br +// bom : Núcleo de Informação e Coordenação do Ponto BR - NIC.br +// https://www.iana.org/domains/root/db/bom.html bom -// bond : 2014-06-05 ShortDot SA +// bond : ShortDot SA +// https://www.iana.org/domains/root/db/bond.html bond -// boo : 2014-01-30 Charleston Road Registry Inc. +// boo : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/boo.html boo -// book : 2015-08-27 Amazon Registry Services, Inc. +// book : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/book.html book -// booking : 2015-07-16 Booking.com B.V. +// booking : Booking.com B.V. +// https://www.iana.org/domains/root/db/booking.html booking -// bosch : 2015-06-18 Robert Bosch GMBH +// bosch : Robert Bosch GMBH +// https://www.iana.org/domains/root/db/bosch.html bosch -// bostik : 2015-05-28 Bostik SA +// bostik : Bostik SA +// https://www.iana.org/domains/root/db/bostik.html bostik -// boston : 2015-12-10 Registry Services, LLC +// boston : Registry Services, LLC +// https://www.iana.org/domains/root/db/boston.html boston -// bot : 2014-12-18 Amazon Registry Services, Inc. +// bot : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/bot.html bot -// boutique : 2013-11-14 Binky Moon, LLC +// boutique : Binky Moon, LLC +// https://www.iana.org/domains/root/db/boutique.html boutique -// box : 2015-11-12 Intercap Registry Inc. +// box : Intercap Registry Inc. +// https://www.iana.org/domains/root/db/box.html box -// bradesco : 2014-12-18 Banco Bradesco S.A. +// bradesco : Banco Bradesco S.A. +// https://www.iana.org/domains/root/db/bradesco.html bradesco -// bridgestone : 2014-12-18 Bridgestone Corporation +// bridgestone : Bridgestone Corporation +// https://www.iana.org/domains/root/db/bridgestone.html bridgestone -// broadway : 2014-12-22 Celebrate Broadway, Inc. +// broadway : Celebrate Broadway, Inc. +// https://www.iana.org/domains/root/db/broadway.html broadway -// broker : 2014-12-11 Dog Beach, LLC +// broker : Dog Beach, LLC +// https://www.iana.org/domains/root/db/broker.html broker -// brother : 2015-01-29 Brother Industries, Ltd. +// brother : Brother Industries, Ltd. +// https://www.iana.org/domains/root/db/brother.html brother -// brussels : 2014-02-06 DNS.be vzw +// brussels : DNS.be vzw +// https://www.iana.org/domains/root/db/brussels.html brussels -// build : 2013-11-07 Plan Bee LLC +// build : Plan Bee LLC +// https://www.iana.org/domains/root/db/build.html build -// builders : 2013-11-07 Binky Moon, LLC +// builders : Binky Moon, LLC +// https://www.iana.org/domains/root/db/builders.html builders -// business : 2013-11-07 Binky Moon, LLC +// business : Binky Moon, LLC +// https://www.iana.org/domains/root/db/business.html business -// buy : 2014-12-18 Amazon Registry Services, Inc. +// buy : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/buy.html buy -// buzz : 2013-10-02 DOTSTRATEGY CO. +// buzz : DOTSTRATEGY CO. +// https://www.iana.org/domains/root/db/buzz.html buzz -// bzh : 2014-02-27 Association www.bzh +// bzh : Association www.bzh +// https://www.iana.org/domains/root/db/bzh.html bzh -// cab : 2013-10-24 Binky Moon, LLC +// cab : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cab.html cab -// cafe : 2015-02-11 Binky Moon, LLC +// cafe : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cafe.html cafe -// cal : 2014-07-24 Charleston Road Registry Inc. +// cal : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/cal.html cal -// call : 2014-12-18 Amazon Registry Services, Inc. +// call : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/call.html call -// calvinklein : 2015-07-30 PVH gTLD Holdings LLC +// calvinklein : PVH gTLD Holdings LLC +// https://www.iana.org/domains/root/db/calvinklein.html calvinklein -// cam : 2016-04-21 Cam Connecting SARL +// cam : Cam Connecting SARL +// https://www.iana.org/domains/root/db/cam.html cam -// camera : 2013-08-27 Binky Moon, LLC +// camera : Binky Moon, LLC +// https://www.iana.org/domains/root/db/camera.html camera -// camp : 2013-11-07 Binky Moon, LLC +// camp : Binky Moon, LLC +// https://www.iana.org/domains/root/db/camp.html camp -// canon : 2014-09-12 Canon Inc. +// canon : Canon Inc. +// https://www.iana.org/domains/root/db/canon.html canon -// capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +// capetown : ZA Central Registry NPC trading as ZA Central Registry +// https://www.iana.org/domains/root/db/capetown.html capetown -// capital : 2014-03-06 Binky Moon, LLC +// capital : Binky Moon, LLC +// https://www.iana.org/domains/root/db/capital.html capital -// capitalone : 2015-08-06 Capital One Financial Corporation +// capitalone : Capital One Financial Corporation +// https://www.iana.org/domains/root/db/capitalone.html capitalone -// car : 2015-01-22 XYZ.COM LLC +// car : XYZ.COM LLC +// https://www.iana.org/domains/root/db/car.html car -// caravan : 2013-12-12 Caravan International, Inc. +// caravan : Caravan International, Inc. +// https://www.iana.org/domains/root/db/caravan.html caravan -// cards : 2013-12-05 Binky Moon, LLC +// cards : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cards.html cards -// care : 2014-03-06 Binky Moon, LLC +// care : Binky Moon, LLC +// https://www.iana.org/domains/root/db/care.html care -// career : 2013-10-09 dotCareer LLC +// career : dotCareer LLC +// https://www.iana.org/domains/root/db/career.html career -// careers : 2013-10-02 Binky Moon, LLC +// careers : Binky Moon, LLC +// https://www.iana.org/domains/root/db/careers.html careers -// cars : 2014-11-13 XYZ.COM LLC +// cars : XYZ.COM LLC +// https://www.iana.org/domains/root/db/cars.html cars -// casa : 2013-11-21 Registry Services, LLC +// casa : Registry Services, LLC +// https://www.iana.org/domains/root/db/casa.html casa -// case : 2015-09-03 Digity, LLC +// case : Digity, LLC +// https://www.iana.org/domains/root/db/case.html case -// cash : 2014-03-06 Binky Moon, LLC +// cash : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cash.html cash -// casino : 2014-12-18 Binky Moon, LLC +// casino : Binky Moon, LLC +// https://www.iana.org/domains/root/db/casino.html casino -// catering : 2013-12-05 Binky Moon, LLC +// catering : Binky Moon, LLC +// https://www.iana.org/domains/root/db/catering.html catering -// catholic : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// catholic : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// https://www.iana.org/domains/root/db/catholic.html catholic -// cba : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +// cba : COMMONWEALTH BANK OF AUSTRALIA +// https://www.iana.org/domains/root/db/cba.html cba -// cbn : 2014-08-22 The Christian Broadcasting Network, Inc. +// cbn : The Christian Broadcasting Network, Inc. +// https://www.iana.org/domains/root/db/cbn.html cbn -// cbre : 2015-07-02 CBRE, Inc. +// cbre : CBRE, Inc. +// https://www.iana.org/domains/root/db/cbre.html cbre -// cbs : 2015-08-06 CBS Domains Inc. -cbs - -// center : 2013-11-07 Binky Moon, LLC +// center : Binky Moon, LLC +// https://www.iana.org/domains/root/db/center.html center -// ceo : 2013-11-07 CEOTLD Pty Ltd +// ceo : XYZ.COM LLC +// https://www.iana.org/domains/root/db/ceo.html ceo -// cern : 2014-06-05 European Organization for Nuclear Research ("CERN") +// cern : European Organization for Nuclear Research ("CERN") +// https://www.iana.org/domains/root/db/cern.html cern -// cfa : 2014-08-28 CFA Institute +// cfa : CFA Institute +// https://www.iana.org/domains/root/db/cfa.html cfa -// cfd : 2014-12-11 ShortDot SA +// cfd : ShortDot SA +// https://www.iana.org/domains/root/db/cfd.html cfd -// chanel : 2015-04-09 Chanel International B.V. +// chanel : Chanel International B.V. +// https://www.iana.org/domains/root/db/chanel.html chanel -// channel : 2014-05-08 Charleston Road Registry Inc. +// channel : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/channel.html channel -// charity : 2018-04-11 Public Interest Registry +// charity : Public Interest Registry +// https://www.iana.org/domains/root/db/charity.html charity -// chase : 2015-04-30 JPMorgan Chase Bank, National Association +// chase : JPMorgan Chase Bank, National Association +// https://www.iana.org/domains/root/db/chase.html chase -// chat : 2014-12-04 Binky Moon, LLC +// chat : Binky Moon, LLC +// https://www.iana.org/domains/root/db/chat.html chat -// cheap : 2013-11-14 Binky Moon, LLC +// cheap : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cheap.html cheap -// chintai : 2015-06-11 CHINTAI Corporation +// chintai : CHINTAI Corporation +// https://www.iana.org/domains/root/db/chintai.html chintai -// christmas : 2013-11-21 XYZ.COM LLC +// christmas : XYZ.COM LLC +// https://www.iana.org/domains/root/db/christmas.html christmas -// chrome : 2014-07-24 Charleston Road Registry Inc. +// chrome : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/chrome.html chrome -// church : 2014-02-06 Binky Moon, LLC +// church : Binky Moon, LLC +// https://www.iana.org/domains/root/db/church.html church -// cipriani : 2015-02-19 Hotel Cipriani Srl +// cipriani : Hotel Cipriani Srl +// https://www.iana.org/domains/root/db/cipriani.html cipriani -// circle : 2014-12-18 Amazon Registry Services, Inc. +// circle : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/circle.html circle -// cisco : 2014-12-22 Cisco Technology, Inc. +// cisco : Cisco Technology, Inc. +// https://www.iana.org/domains/root/db/cisco.html cisco -// citadel : 2015-07-23 Citadel Domain LLC +// citadel : Citadel Domain LLC +// https://www.iana.org/domains/root/db/citadel.html citadel -// citi : 2015-07-30 Citigroup Inc. +// citi : Citigroup Inc. +// https://www.iana.org/domains/root/db/citi.html citi -// citic : 2014-01-09 CITIC Group Corporation +// citic : CITIC Group Corporation +// https://www.iana.org/domains/root/db/citic.html citic -// city : 2014-05-29 Binky Moon, LLC +// city : Binky Moon, LLC +// https://www.iana.org/domains/root/db/city.html city -// cityeats : 2014-12-11 Lifestyle Domain Holdings, Inc. -cityeats - -// claims : 2014-03-20 Binky Moon, LLC +// claims : Binky Moon, LLC +// https://www.iana.org/domains/root/db/claims.html claims -// cleaning : 2013-12-05 Binky Moon, LLC +// cleaning : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cleaning.html cleaning -// click : 2014-06-05 Internet Naming Company LLC +// click : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/click.html click -// clinic : 2014-03-20 Binky Moon, LLC +// clinic : Binky Moon, LLC +// https://www.iana.org/domains/root/db/clinic.html clinic -// clinique : 2015-10-01 The Estée Lauder Companies Inc. +// clinique : The Estée Lauder Companies Inc. +// https://www.iana.org/domains/root/db/clinique.html clinique -// clothing : 2013-08-27 Binky Moon, LLC +// clothing : Binky Moon, LLC +// https://www.iana.org/domains/root/db/clothing.html clothing -// cloud : 2015-04-16 Aruba PEC S.p.A. +// cloud : Aruba PEC S.p.A. +// https://www.iana.org/domains/root/db/cloud.html cloud -// club : 2013-11-08 Registry Services, LLC +// club : Registry Services, LLC +// https://www.iana.org/domains/root/db/club.html club -// clubmed : 2015-06-25 Club Méditerranée S.A. +// clubmed : Club Méditerranée S.A. +// https://www.iana.org/domains/root/db/clubmed.html clubmed -// coach : 2014-10-09 Binky Moon, LLC +// coach : Binky Moon, LLC +// https://www.iana.org/domains/root/db/coach.html coach -// codes : 2013-10-31 Binky Moon, LLC +// codes : Binky Moon, LLC +// https://www.iana.org/domains/root/db/codes.html codes -// coffee : 2013-10-17 Binky Moon, LLC +// coffee : Binky Moon, LLC +// https://www.iana.org/domains/root/db/coffee.html coffee -// college : 2014-01-16 XYZ.COM LLC +// college : XYZ.COM LLC +// https://www.iana.org/domains/root/db/college.html college -// cologne : 2014-02-05 dotKoeln GmbH +// cologne : dotKoeln GmbH +// https://www.iana.org/domains/root/db/cologne.html cologne -// comcast : 2015-07-23 Comcast IP Holdings I, LLC +// comcast : Comcast IP Holdings I, LLC +// https://www.iana.org/domains/root/db/comcast.html comcast -// commbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +// commbank : COMMONWEALTH BANK OF AUSTRALIA +// https://www.iana.org/domains/root/db/commbank.html commbank -// community : 2013-12-05 Binky Moon, LLC +// community : Binky Moon, LLC +// https://www.iana.org/domains/root/db/community.html community -// company : 2013-11-07 Binky Moon, LLC +// company : Binky Moon, LLC +// https://www.iana.org/domains/root/db/company.html company -// compare : 2015-10-08 Registry Services, LLC +// compare : Registry Services, LLC +// https://www.iana.org/domains/root/db/compare.html compare -// computer : 2013-10-24 Binky Moon, LLC +// computer : Binky Moon, LLC +// https://www.iana.org/domains/root/db/computer.html computer -// comsec : 2015-01-08 VeriSign, Inc. +// comsec : VeriSign, Inc. +// https://www.iana.org/domains/root/db/comsec.html comsec -// condos : 2013-12-05 Binky Moon, LLC +// condos : Binky Moon, LLC +// https://www.iana.org/domains/root/db/condos.html condos -// construction : 2013-09-16 Binky Moon, LLC +// construction : Binky Moon, LLC +// https://www.iana.org/domains/root/db/construction.html construction -// consulting : 2013-12-05 Dog Beach, LLC +// consulting : Dog Beach, LLC +// https://www.iana.org/domains/root/db/consulting.html consulting -// contact : 2015-01-08 Dog Beach, LLC +// contact : Dog Beach, LLC +// https://www.iana.org/domains/root/db/contact.html contact -// contractors : 2013-09-10 Binky Moon, LLC +// contractors : Binky Moon, LLC +// https://www.iana.org/domains/root/db/contractors.html contractors -// cooking : 2013-11-21 Registry Services, LLC +// cooking : Registry Services, LLC +// https://www.iana.org/domains/root/db/cooking.html cooking -// cookingchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. -cookingchannel - -// cool : 2013-11-14 Binky Moon, LLC +// cool : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cool.html cool -// corsica : 2014-09-25 Collectivité de Corse +// corsica : Collectivité de Corse +// https://www.iana.org/domains/root/db/corsica.html corsica -// country : 2013-12-19 Internet Naming Company LLC +// country : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/country.html country -// coupon : 2015-02-26 Amazon Registry Services, Inc. +// coupon : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/coupon.html coupon -// coupons : 2015-03-26 Binky Moon, LLC +// coupons : Binky Moon, LLC +// https://www.iana.org/domains/root/db/coupons.html coupons -// courses : 2014-12-04 Registry Services, LLC +// courses : Registry Services, LLC +// https://www.iana.org/domains/root/db/courses.html courses -// cpa : 2019-06-10 American Institute of Certified Public Accountants +// cpa : American Institute of Certified Public Accountants +// https://www.iana.org/domains/root/db/cpa.html cpa -// credit : 2014-03-20 Binky Moon, LLC +// credit : Binky Moon, LLC +// https://www.iana.org/domains/root/db/credit.html credit -// creditcard : 2014-03-20 Binky Moon, LLC +// creditcard : Binky Moon, LLC +// https://www.iana.org/domains/root/db/creditcard.html creditcard -// creditunion : 2015-01-22 DotCooperation LLC +// creditunion : DotCooperation LLC +// https://www.iana.org/domains/root/db/creditunion.html creditunion -// cricket : 2014-10-09 dot Cricket Limited +// cricket : dot Cricket Limited +// https://www.iana.org/domains/root/db/cricket.html cricket -// crown : 2014-10-24 Crown Equipment Corporation +// crown : Crown Equipment Corporation +// https://www.iana.org/domains/root/db/crown.html crown -// crs : 2014-04-03 Federated Co-operatives Limited +// crs : Federated Co-operatives Limited +// https://www.iana.org/domains/root/db/crs.html crs -// cruise : 2015-12-10 Viking River Cruises (Bermuda) Ltd. +// cruise : Viking River Cruises (Bermuda) Ltd. +// https://www.iana.org/domains/root/db/cruise.html cruise -// cruises : 2013-12-05 Binky Moon, LLC +// cruises : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cruises.html cruises -// cuisinella : 2014-04-03 SCHMIDT GROUPE S.A.S. +// cuisinella : SCHMIDT GROUPE S.A.S. +// https://www.iana.org/domains/root/db/cuisinella.html cuisinella -// cymru : 2014-05-08 Nominet UK +// cymru : Nominet UK +// https://www.iana.org/domains/root/db/cymru.html cymru -// cyou : 2015-01-22 ShortDot SA +// cyou : ShortDot SA +// https://www.iana.org/domains/root/db/cyou.html cyou -// dabur : 2014-02-06 Dabur India Limited +// dabur : Dabur India Limited +// https://www.iana.org/domains/root/db/dabur.html dabur -// dad : 2014-01-23 Charleston Road Registry Inc. +// dad : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/dad.html dad -// dance : 2013-10-24 Dog Beach, LLC +// dance : Dog Beach, LLC +// https://www.iana.org/domains/root/db/dance.html dance -// data : 2016-06-02 Dish DBS Corporation +// data : Dish DBS Corporation +// https://www.iana.org/domains/root/db/data.html data -// date : 2014-11-20 dot Date Limited +// date : dot Date Limited +// https://www.iana.org/domains/root/db/date.html date -// dating : 2013-12-05 Binky Moon, LLC +// dating : Binky Moon, LLC +// https://www.iana.org/domains/root/db/dating.html dating -// datsun : 2014-03-27 NISSAN MOTOR CO., LTD. +// datsun : NISSAN MOTOR CO., LTD. +// https://www.iana.org/domains/root/db/datsun.html datsun -// day : 2014-01-30 Charleston Road Registry Inc. +// day : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/day.html day -// dclk : 2014-11-20 Charleston Road Registry Inc. +// dclk : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/dclk.html dclk -// dds : 2015-05-07 Registry Services, LLC +// dds : Registry Services, LLC +// https://www.iana.org/domains/root/db/dds.html dds -// deal : 2015-06-25 Amazon Registry Services, Inc. +// deal : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/deal.html deal -// dealer : 2014-12-22 Intercap Registry Inc. +// dealer : Intercap Registry Inc. +// https://www.iana.org/domains/root/db/dealer.html dealer -// deals : 2014-05-22 Binky Moon, LLC +// deals : Binky Moon, LLC +// https://www.iana.org/domains/root/db/deals.html deals -// degree : 2014-03-06 Dog Beach, LLC +// degree : Dog Beach, LLC +// https://www.iana.org/domains/root/db/degree.html degree -// delivery : 2014-09-11 Binky Moon, LLC +// delivery : Binky Moon, LLC +// https://www.iana.org/domains/root/db/delivery.html delivery -// dell : 2014-10-24 Dell Inc. +// dell : Dell Inc. +// https://www.iana.org/domains/root/db/dell.html dell -// deloitte : 2015-07-31 Deloitte Touche Tohmatsu +// deloitte : Deloitte Touche Tohmatsu +// https://www.iana.org/domains/root/db/deloitte.html deloitte -// delta : 2015-02-19 Delta Air Lines, Inc. +// delta : Delta Air Lines, Inc. +// https://www.iana.org/domains/root/db/delta.html delta -// democrat : 2013-10-24 Dog Beach, LLC +// democrat : Dog Beach, LLC +// https://www.iana.org/domains/root/db/democrat.html democrat -// dental : 2014-03-20 Binky Moon, LLC +// dental : Binky Moon, LLC +// https://www.iana.org/domains/root/db/dental.html dental -// dentist : 2014-03-20 Dog Beach, LLC +// dentist : Dog Beach, LLC +// https://www.iana.org/domains/root/db/dentist.html dentist -// desi : 2013-11-14 Desi Networks LLC -desi - -// design : 2014-11-07 Registry Services, LLC +// design : Registry Services, LLC +// https://www.iana.org/domains/root/db/design.html design -// dev : 2014-10-16 Charleston Road Registry Inc. +// dev : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/dev.html dev -// dhl : 2015-07-23 Deutsche Post AG +// dhl : Deutsche Post AG +// https://www.iana.org/domains/root/db/dhl.html dhl -// diamonds : 2013-09-22 Binky Moon, LLC +// diamonds : Binky Moon, LLC +// https://www.iana.org/domains/root/db/diamonds.html diamonds -// diet : 2014-06-26 XYZ.COM LLC +// diet : XYZ.COM LLC +// https://www.iana.org/domains/root/db/diet.html diet -// digital : 2014-03-06 Binky Moon, LLC +// digital : Binky Moon, LLC +// https://www.iana.org/domains/root/db/digital.html digital -// direct : 2014-04-10 Binky Moon, LLC +// direct : Binky Moon, LLC +// https://www.iana.org/domains/root/db/direct.html direct -// directory : 2013-09-20 Binky Moon, LLC +// directory : Binky Moon, LLC +// https://www.iana.org/domains/root/db/directory.html directory -// discount : 2014-03-06 Binky Moon, LLC +// discount : Binky Moon, LLC +// https://www.iana.org/domains/root/db/discount.html discount -// discover : 2015-07-23 Discover Financial Services +// discover : Discover Financial Services +// https://www.iana.org/domains/root/db/discover.html discover -// dish : 2015-07-30 Dish DBS Corporation +// dish : Dish DBS Corporation +// https://www.iana.org/domains/root/db/dish.html dish -// diy : 2015-11-05 Lifestyle Domain Holdings, Inc. +// diy : Lifestyle Domain Holdings, Inc. +// https://www.iana.org/domains/root/db/diy.html diy -// dnp : 2013-12-13 Dai Nippon Printing Co., Ltd. +// dnp : Dai Nippon Printing Co., Ltd. +// https://www.iana.org/domains/root/db/dnp.html dnp -// docs : 2014-10-16 Charleston Road Registry Inc. +// docs : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/docs.html docs -// doctor : 2016-06-02 Binky Moon, LLC +// doctor : Binky Moon, LLC +// https://www.iana.org/domains/root/db/doctor.html doctor -// dog : 2014-12-04 Binky Moon, LLC +// dog : Binky Moon, LLC +// https://www.iana.org/domains/root/db/dog.html dog -// domains : 2013-10-17 Binky Moon, LLC +// domains : Binky Moon, LLC +// https://www.iana.org/domains/root/db/domains.html domains -// dot : 2015-05-21 Dish DBS Corporation +// dot : Dish DBS Corporation +// https://www.iana.org/domains/root/db/dot.html dot -// download : 2014-11-20 dot Support Limited +// download : dot Support Limited +// https://www.iana.org/domains/root/db/download.html download -// drive : 2015-03-05 Charleston Road Registry Inc. +// drive : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/drive.html drive -// dtv : 2015-06-04 Dish DBS Corporation +// dtv : Dish DBS Corporation +// https://www.iana.org/domains/root/db/dtv.html dtv -// dubai : 2015-01-01 Dubai Smart Government Department +// dubai : Dubai Smart Government Department +// https://www.iana.org/domains/root/db/dubai.html dubai -// dunlop : 2015-07-02 The Goodyear Tire & Rubber Company +// dunlop : The Goodyear Tire & Rubber Company +// https://www.iana.org/domains/root/db/dunlop.html dunlop -// dupont : 2015-06-25 DuPont Specialty Products USA, LLC +// dupont : DuPont Specialty Products USA, LLC +// https://www.iana.org/domains/root/db/dupont.html dupont -// durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +// durban : ZA Central Registry NPC trading as ZA Central Registry +// https://www.iana.org/domains/root/db/durban.html durban -// dvag : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +// dvag : Deutsche Vermögensberatung Aktiengesellschaft DVAG +// https://www.iana.org/domains/root/db/dvag.html dvag -// dvr : 2016-05-26 DISH Technologies L.L.C. +// dvr : DISH Technologies L.L.C. +// https://www.iana.org/domains/root/db/dvr.html dvr -// earth : 2014-12-04 Interlink Systems Innovation Institute K.K. +// earth : Interlink Systems Innovation Institute K.K. +// https://www.iana.org/domains/root/db/earth.html earth -// eat : 2014-01-23 Charleston Road Registry Inc. +// eat : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/eat.html eat -// eco : 2016-07-08 Big Room Inc. +// eco : Big Room Inc. +// https://www.iana.org/domains/root/db/eco.html eco -// edeka : 2014-12-18 EDEKA Verband kaufmännischer Genossenschaften e.V. +// edeka : EDEKA Verband kaufmännischer Genossenschaften e.V. +// https://www.iana.org/domains/root/db/edeka.html edeka -// education : 2013-11-07 Binky Moon, LLC +// education : Binky Moon, LLC +// https://www.iana.org/domains/root/db/education.html education -// email : 2013-10-31 Binky Moon, LLC +// email : Binky Moon, LLC +// https://www.iana.org/domains/root/db/email.html email -// emerck : 2014-04-03 Merck KGaA +// emerck : Merck KGaA +// https://www.iana.org/domains/root/db/emerck.html emerck -// energy : 2014-09-11 Binky Moon, LLC +// energy : Binky Moon, LLC +// https://www.iana.org/domains/root/db/energy.html energy -// engineer : 2014-03-06 Dog Beach, LLC +// engineer : Dog Beach, LLC +// https://www.iana.org/domains/root/db/engineer.html engineer -// engineering : 2014-03-06 Binky Moon, LLC +// engineering : Binky Moon, LLC +// https://www.iana.org/domains/root/db/engineering.html engineering -// enterprises : 2013-09-20 Binky Moon, LLC +// enterprises : Binky Moon, LLC +// https://www.iana.org/domains/root/db/enterprises.html enterprises -// epson : 2014-12-04 Seiko Epson Corporation +// epson : Seiko Epson Corporation +// https://www.iana.org/domains/root/db/epson.html epson -// equipment : 2013-08-27 Binky Moon, LLC +// equipment : Binky Moon, LLC +// https://www.iana.org/domains/root/db/equipment.html equipment -// ericsson : 2015-07-09 Telefonaktiebolaget L M Ericsson +// ericsson : Telefonaktiebolaget L M Ericsson +// https://www.iana.org/domains/root/db/ericsson.html ericsson -// erni : 2014-04-03 ERNI Group Holding AG +// erni : ERNI Group Holding AG +// https://www.iana.org/domains/root/db/erni.html erni -// esq : 2014-05-08 Charleston Road Registry Inc. +// esq : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/esq.html esq -// estate : 2013-08-27 Binky Moon, LLC +// estate : Binky Moon, LLC +// https://www.iana.org/domains/root/db/estate.html estate -// etisalat : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat) +// etisalat : Emirates Telecommunications Corporation (trading as Etisalat) +// https://www.iana.org/domains/root/db/etisalat.html etisalat -// eurovision : 2014-04-24 European Broadcasting Union (EBU) +// eurovision : European Broadcasting Union (EBU) +// https://www.iana.org/domains/root/db/eurovision.html eurovision -// eus : 2013-12-12 Puntueus Fundazioa +// eus : Puntueus Fundazioa +// https://www.iana.org/domains/root/db/eus.html eus -// events : 2013-12-05 Binky Moon, LLC +// events : Binky Moon, LLC +// https://www.iana.org/domains/root/db/events.html events -// exchange : 2014-03-06 Binky Moon, LLC +// exchange : Binky Moon, LLC +// https://www.iana.org/domains/root/db/exchange.html exchange -// expert : 2013-11-21 Binky Moon, LLC +// expert : Binky Moon, LLC +// https://www.iana.org/domains/root/db/expert.html expert -// exposed : 2013-12-05 Binky Moon, LLC +// exposed : Binky Moon, LLC +// https://www.iana.org/domains/root/db/exposed.html exposed -// express : 2015-02-11 Binky Moon, LLC +// express : Binky Moon, LLC +// https://www.iana.org/domains/root/db/express.html express -// extraspace : 2015-05-14 Extra Space Storage LLC +// extraspace : Extra Space Storage LLC +// https://www.iana.org/domains/root/db/extraspace.html extraspace -// fage : 2014-12-18 Fage International S.A. +// fage : Fage International S.A. +// https://www.iana.org/domains/root/db/fage.html fage -// fail : 2014-03-06 Binky Moon, LLC +// fail : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fail.html fail -// fairwinds : 2014-11-13 FairWinds Partners, LLC +// fairwinds : FairWinds Partners, LLC +// https://www.iana.org/domains/root/db/fairwinds.html fairwinds -// faith : 2014-11-20 dot Faith Limited +// faith : dot Faith Limited +// https://www.iana.org/domains/root/db/faith.html faith -// family : 2015-04-02 Dog Beach, LLC +// family : Dog Beach, LLC +// https://www.iana.org/domains/root/db/family.html family -// fan : 2014-03-06 Dog Beach, LLC +// fan : Dog Beach, LLC +// https://www.iana.org/domains/root/db/fan.html fan -// fans : 2014-11-07 ZDNS International Limited +// fans : ZDNS International Limited +// https://www.iana.org/domains/root/db/fans.html fans -// farm : 2013-11-07 Binky Moon, LLC +// farm : Binky Moon, LLC +// https://www.iana.org/domains/root/db/farm.html farm -// farmers : 2015-07-09 Farmers Insurance Exchange +// farmers : Farmers Insurance Exchange +// https://www.iana.org/domains/root/db/farmers.html farmers -// fashion : 2014-07-03 Registry Services, LLC +// fashion : Registry Services, LLC +// https://www.iana.org/domains/root/db/fashion.html fashion -// fast : 2014-12-18 Amazon Registry Services, Inc. +// fast : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/fast.html fast -// fedex : 2015-08-06 Federal Express Corporation +// fedex : Federal Express Corporation +// https://www.iana.org/domains/root/db/fedex.html fedex -// feedback : 2013-12-19 Top Level Spectrum, Inc. +// feedback : Top Level Spectrum, Inc. +// https://www.iana.org/domains/root/db/feedback.html feedback -// ferrari : 2015-07-31 Fiat Chrysler Automobiles N.V. +// ferrari : Fiat Chrysler Automobiles N.V. +// https://www.iana.org/domains/root/db/ferrari.html ferrari -// ferrero : 2014-12-18 Ferrero Trading Lux S.A. +// ferrero : Ferrero Trading Lux S.A. +// https://www.iana.org/domains/root/db/ferrero.html ferrero -// fiat : 2015-07-31 Fiat Chrysler Automobiles N.V. -fiat - -// fidelity : 2015-07-30 Fidelity Brokerage Services LLC +// fidelity : Fidelity Brokerage Services LLC +// https://www.iana.org/domains/root/db/fidelity.html fidelity -// fido : 2015-08-06 Rogers Communications Canada Inc. +// fido : Rogers Communications Canada Inc. +// https://www.iana.org/domains/root/db/fido.html fido -// film : 2015-01-08 Motion Picture Domain Registry Pty Ltd +// film : Motion Picture Domain Registry Pty Ltd +// https://www.iana.org/domains/root/db/film.html film -// final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br +// final : Núcleo de Informação e Coordenação do Ponto BR - NIC.br +// https://www.iana.org/domains/root/db/final.html final -// finance : 2014-03-20 Binky Moon, LLC +// finance : Binky Moon, LLC +// https://www.iana.org/domains/root/db/finance.html finance -// financial : 2014-03-06 Binky Moon, LLC +// financial : Binky Moon, LLC +// https://www.iana.org/domains/root/db/financial.html financial -// fire : 2015-06-25 Amazon Registry Services, Inc. +// fire : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/fire.html fire -// firestone : 2014-12-18 Bridgestone Licensing Services, Inc +// firestone : Bridgestone Licensing Services, Inc +// https://www.iana.org/domains/root/db/firestone.html firestone -// firmdale : 2014-03-27 Firmdale Holdings Limited +// firmdale : Firmdale Holdings Limited +// https://www.iana.org/domains/root/db/firmdale.html firmdale -// fish : 2013-12-12 Binky Moon, LLC +// fish : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fish.html fish -// fishing : 2013-11-21 Registry Services, LLC +// fishing : Registry Services, LLC +// https://www.iana.org/domains/root/db/fishing.html fishing -// fit : 2014-11-07 Registry Services, LLC +// fit : Registry Services, LLC +// https://www.iana.org/domains/root/db/fit.html fit -// fitness : 2014-03-06 Binky Moon, LLC +// fitness : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fitness.html fitness -// flickr : 2015-04-02 Flickr, Inc. +// flickr : Flickr, Inc. +// https://www.iana.org/domains/root/db/flickr.html flickr -// flights : 2013-12-05 Binky Moon, LLC +// flights : Binky Moon, LLC +// https://www.iana.org/domains/root/db/flights.html flights -// flir : 2015-07-23 FLIR Systems, Inc. +// flir : FLIR Systems, Inc. +// https://www.iana.org/domains/root/db/flir.html flir -// florist : 2013-11-07 Binky Moon, LLC +// florist : Binky Moon, LLC +// https://www.iana.org/domains/root/db/florist.html florist -// flowers : 2014-10-09 XYZ.COM LLC +// flowers : XYZ.COM LLC +// https://www.iana.org/domains/root/db/flowers.html flowers -// fly : 2014-05-08 Charleston Road Registry Inc. +// fly : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/fly.html fly -// foo : 2014-01-23 Charleston Road Registry Inc. +// foo : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/foo.html foo -// food : 2016-04-21 Lifestyle Domain Holdings, Inc. +// food : Lifestyle Domain Holdings, Inc. +// https://www.iana.org/domains/root/db/food.html food -// foodnetwork : 2015-07-02 Lifestyle Domain Holdings, Inc. -foodnetwork - -// football : 2014-12-18 Binky Moon, LLC +// football : Binky Moon, LLC +// https://www.iana.org/domains/root/db/football.html football -// ford : 2014-11-13 Ford Motor Company +// ford : Ford Motor Company +// https://www.iana.org/domains/root/db/ford.html ford -// forex : 2014-12-11 Dog Beach, LLC +// forex : Dog Beach, LLC +// https://www.iana.org/domains/root/db/forex.html forex -// forsale : 2014-05-22 Dog Beach, LLC +// forsale : Dog Beach, LLC +// https://www.iana.org/domains/root/db/forsale.html forsale -// forum : 2015-04-02 Fegistry, LLC +// forum : Fegistry, LLC +// https://www.iana.org/domains/root/db/forum.html forum -// foundation : 2013-12-05 Public Interest Registry +// foundation : Public Interest Registry +// https://www.iana.org/domains/root/db/foundation.html foundation -// fox : 2015-09-11 FOX Registry, LLC +// fox : FOX Registry, LLC +// https://www.iana.org/domains/root/db/fox.html fox -// free : 2015-12-10 Amazon Registry Services, Inc. +// free : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/free.html free -// fresenius : 2015-07-30 Fresenius Immobilien-Verwaltungs-GmbH +// fresenius : Fresenius Immobilien-Verwaltungs-GmbH +// https://www.iana.org/domains/root/db/fresenius.html fresenius -// frl : 2014-05-15 FRLregistry B.V. +// frl : FRLregistry B.V. +// https://www.iana.org/domains/root/db/frl.html frl -// frogans : 2013-12-19 OP3FT +// frogans : OP3FT +// https://www.iana.org/domains/root/db/frogans.html frogans -// frontdoor : 2015-07-02 Lifestyle Domain Holdings, Inc. -frontdoor - -// frontier : 2015-02-05 Frontier Communications Corporation +// frontier : Frontier Communications Corporation +// https://www.iana.org/domains/root/db/frontier.html frontier -// ftr : 2015-07-16 Frontier Communications Corporation +// ftr : Frontier Communications Corporation +// https://www.iana.org/domains/root/db/ftr.html ftr -// fujitsu : 2015-07-30 Fujitsu Limited +// fujitsu : Fujitsu Limited +// https://www.iana.org/domains/root/db/fujitsu.html fujitsu -// fun : 2016-01-14 Radix FZC +// fun : Radix FZC DMCC +// https://www.iana.org/domains/root/db/fun.html fun -// fund : 2014-03-20 Binky Moon, LLC +// fund : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fund.html fund -// furniture : 2014-03-20 Binky Moon, LLC +// furniture : Binky Moon, LLC +// https://www.iana.org/domains/root/db/furniture.html furniture -// futbol : 2013-09-20 Dog Beach, LLC +// futbol : Dog Beach, LLC +// https://www.iana.org/domains/root/db/futbol.html futbol -// fyi : 2015-04-02 Binky Moon, LLC +// fyi : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fyi.html fyi -// gal : 2013-11-07 Asociación puntoGAL +// gal : Asociación puntoGAL +// https://www.iana.org/domains/root/db/gal.html gal -// gallery : 2013-09-13 Binky Moon, LLC +// gallery : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gallery.html gallery -// gallo : 2015-06-11 Gallo Vineyards, Inc. +// gallo : Gallo Vineyards, Inc. +// https://www.iana.org/domains/root/db/gallo.html gallo -// gallup : 2015-02-19 Gallup, Inc. +// gallup : Gallup, Inc. +// https://www.iana.org/domains/root/db/gallup.html gallup -// game : 2015-05-28 XYZ.COM LLC +// game : XYZ.COM LLC +// https://www.iana.org/domains/root/db/game.html game -// games : 2015-05-28 Dog Beach, LLC +// games : Dog Beach, LLC +// https://www.iana.org/domains/root/db/games.html games -// gap : 2015-07-31 The Gap, Inc. +// gap : The Gap, Inc. +// https://www.iana.org/domains/root/db/gap.html gap -// garden : 2014-06-26 Registry Services, LLC +// garden : Registry Services, LLC +// https://www.iana.org/domains/root/db/garden.html garden -// gay : 2019-05-23 Top Level Design, LLC +// gay : Registry Services, LLC +// https://www.iana.org/domains/root/db/gay.html gay -// gbiz : 2014-07-17 Charleston Road Registry Inc. +// gbiz : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/gbiz.html gbiz -// gdn : 2014-07-31 Joint Stock Company "Navigation-information systems" +// gdn : Joint Stock Company "Navigation-information systems" +// https://www.iana.org/domains/root/db/gdn.html gdn -// gea : 2014-12-04 GEA Group Aktiengesellschaft +// gea : GEA Group Aktiengesellschaft +// https://www.iana.org/domains/root/db/gea.html gea -// gent : 2014-01-23 Easyhost BV +// gent : Easyhost BV +// https://www.iana.org/domains/root/db/gent.html gent -// genting : 2015-03-12 Resorts World Inc Pte. Ltd. +// genting : Resorts World Inc Pte. Ltd. +// https://www.iana.org/domains/root/db/genting.html genting -// george : 2015-07-31 Wal-Mart Stores, Inc. +// george : Wal-Mart Stores, Inc. +// https://www.iana.org/domains/root/db/george.html george -// ggee : 2014-01-09 GMO Internet, Inc. +// ggee : GMO Internet, Inc. +// https://www.iana.org/domains/root/db/ggee.html ggee -// gift : 2013-10-17 DotGift, LLC +// gift : DotGift, LLC +// https://www.iana.org/domains/root/db/gift.html gift -// gifts : 2014-07-03 Binky Moon, LLC +// gifts : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gifts.html gifts -// gives : 2014-03-06 Public Interest Registry +// gives : Public Interest Registry +// https://www.iana.org/domains/root/db/gives.html gives -// giving : 2014-11-13 Public Interest Registry +// giving : Public Interest Registry +// https://www.iana.org/domains/root/db/giving.html giving -// glass : 2013-11-07 Binky Moon, LLC +// glass : Binky Moon, LLC +// https://www.iana.org/domains/root/db/glass.html glass -// gle : 2014-07-24 Charleston Road Registry Inc. +// gle : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/gle.html gle -// global : 2014-04-17 Identity Digital Limited +// global : Identity Digital Limited +// https://www.iana.org/domains/root/db/global.html global -// globo : 2013-12-19 Globo Comunicação e Participações S.A +// globo : Globo Comunicação e Participações S.A +// https://www.iana.org/domains/root/db/globo.html globo -// gmail : 2014-05-01 Charleston Road Registry Inc. +// gmail : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/gmail.html gmail -// gmbh : 2016-01-29 Binky Moon, LLC +// gmbh : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gmbh.html gmbh -// gmo : 2014-01-09 GMO Internet, Inc. +// gmo : GMO Internet, Inc. +// https://www.iana.org/domains/root/db/gmo.html gmo -// gmx : 2014-04-24 1&1 Mail & Media GmbH +// gmx : 1&1 Mail & Media GmbH +// https://www.iana.org/domains/root/db/gmx.html gmx -// godaddy : 2015-07-23 Go Daddy East, LLC +// godaddy : Go Daddy East, LLC +// https://www.iana.org/domains/root/db/godaddy.html godaddy -// gold : 2015-01-22 Binky Moon, LLC +// gold : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gold.html gold -// goldpoint : 2014-11-20 YODOBASHI CAMERA CO.,LTD. +// goldpoint : YODOBASHI CAMERA CO.,LTD. +// https://www.iana.org/domains/root/db/goldpoint.html goldpoint -// golf : 2014-12-18 Binky Moon, LLC +// golf : Binky Moon, LLC +// https://www.iana.org/domains/root/db/golf.html golf -// goo : 2014-12-18 NTT Resonant Inc. +// goo : NTT Resonant Inc. +// https://www.iana.org/domains/root/db/goo.html goo -// goodyear : 2015-07-02 The Goodyear Tire & Rubber Company +// goodyear : The Goodyear Tire & Rubber Company +// https://www.iana.org/domains/root/db/goodyear.html goodyear -// goog : 2014-11-20 Charleston Road Registry Inc. +// goog : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/goog.html goog -// google : 2014-07-24 Charleston Road Registry Inc. +// google : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/google.html google -// gop : 2014-01-16 Republican State Leadership Committee, Inc. +// gop : Republican State Leadership Committee, Inc. +// https://www.iana.org/domains/root/db/gop.html gop -// got : 2014-12-18 Amazon Registry Services, Inc. +// got : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/got.html got -// grainger : 2015-05-07 Grainger Registry Services, LLC +// grainger : Grainger Registry Services, LLC +// https://www.iana.org/domains/root/db/grainger.html grainger -// graphics : 2013-09-13 Binky Moon, LLC +// graphics : Binky Moon, LLC +// https://www.iana.org/domains/root/db/graphics.html graphics -// gratis : 2014-03-20 Binky Moon, LLC +// gratis : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gratis.html gratis -// green : 2014-05-08 Identity Digital Limited +// green : Identity Digital Limited +// https://www.iana.org/domains/root/db/green.html green -// gripe : 2014-03-06 Binky Moon, LLC +// gripe : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gripe.html gripe -// grocery : 2016-06-16 Wal-Mart Stores, Inc. +// grocery : Wal-Mart Stores, Inc. +// https://www.iana.org/domains/root/db/grocery.html grocery -// group : 2014-08-15 Binky Moon, LLC +// group : Binky Moon, LLC +// https://www.iana.org/domains/root/db/group.html group -// guardian : 2015-07-30 The Guardian Life Insurance Company of America +// guardian : The Guardian Life Insurance Company of America +// https://www.iana.org/domains/root/db/guardian.html guardian -// gucci : 2014-11-13 Guccio Gucci S.p.a. +// gucci : Guccio Gucci S.p.a. +// https://www.iana.org/domains/root/db/gucci.html gucci -// guge : 2014-08-28 Charleston Road Registry Inc. +// guge : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/guge.html guge -// guide : 2013-09-13 Binky Moon, LLC +// guide : Binky Moon, LLC +// https://www.iana.org/domains/root/db/guide.html guide -// guitars : 2013-11-14 XYZ.COM LLC +// guitars : XYZ.COM LLC +// https://www.iana.org/domains/root/db/guitars.html guitars -// guru : 2013-08-27 Binky Moon, LLC +// guru : Binky Moon, LLC +// https://www.iana.org/domains/root/db/guru.html guru -// hair : 2015-12-03 XYZ.COM LLC +// hair : XYZ.COM LLC +// https://www.iana.org/domains/root/db/hair.html hair -// hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH +// hamburg : Hamburg Top-Level-Domain GmbH +// https://www.iana.org/domains/root/db/hamburg.html hamburg -// hangout : 2014-11-13 Charleston Road Registry Inc. +// hangout : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/hangout.html hangout -// haus : 2013-12-05 Dog Beach, LLC +// haus : Dog Beach, LLC +// https://www.iana.org/domains/root/db/haus.html haus -// hbo : 2015-07-30 HBO Registry Services, Inc. +// hbo : HBO Registry Services, Inc. +// https://www.iana.org/domains/root/db/hbo.html hbo -// hdfc : 2015-07-30 HOUSING DEVELOPMENT FINANCE CORPORATION LIMITED +// hdfc : HOUSING DEVELOPMENT FINANCE CORPORATION LIMITED +// https://www.iana.org/domains/root/db/hdfc.html hdfc -// hdfcbank : 2015-02-12 HDFC Bank Limited +// hdfcbank : HDFC Bank Limited +// https://www.iana.org/domains/root/db/hdfcbank.html hdfcbank -// health : 2015-02-11 DotHealth, LLC +// health : Registry Services, LLC +// https://www.iana.org/domains/root/db/health.html health -// healthcare : 2014-06-12 Binky Moon, LLC +// healthcare : Binky Moon, LLC +// https://www.iana.org/domains/root/db/healthcare.html healthcare -// help : 2014-06-26 Innovation service Limited +// help : Innovation service Limited +// https://www.iana.org/domains/root/db/help.html help -// helsinki : 2015-02-05 City of Helsinki +// helsinki : City of Helsinki +// https://www.iana.org/domains/root/db/helsinki.html helsinki -// here : 2014-02-06 Charleston Road Registry Inc. +// here : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/here.html here -// hermes : 2014-07-10 HERMES INTERNATIONAL +// hermes : HERMES INTERNATIONAL +// https://www.iana.org/domains/root/db/hermes.html hermes -// hgtv : 2015-07-02 Lifestyle Domain Holdings, Inc. -hgtv - -// hiphop : 2014-03-06 Dot Hip Hop, LLC +// hiphop : Dot Hip Hop, LLC +// https://www.iana.org/domains/root/db/hiphop.html hiphop -// hisamitsu : 2015-07-16 Hisamitsu Pharmaceutical Co.,Inc. +// hisamitsu : Hisamitsu Pharmaceutical Co.,Inc. +// https://www.iana.org/domains/root/db/hisamitsu.html hisamitsu -// hitachi : 2014-10-31 Hitachi, Ltd. +// hitachi : Hitachi, Ltd. +// https://www.iana.org/domains/root/db/hitachi.html hitachi -// hiv : 2014-03-13 Internet Naming Company LLC +// hiv : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/hiv.html hiv -// hkt : 2015-05-14 PCCW-HKT DataCom Services Limited +// hkt : PCCW-HKT DataCom Services Limited +// https://www.iana.org/domains/root/db/hkt.html hkt -// hockey : 2015-03-19 Binky Moon, LLC +// hockey : Binky Moon, LLC +// https://www.iana.org/domains/root/db/hockey.html hockey -// holdings : 2013-08-27 Binky Moon, LLC +// holdings : Binky Moon, LLC +// https://www.iana.org/domains/root/db/holdings.html holdings -// holiday : 2013-11-07 Binky Moon, LLC +// holiday : Binky Moon, LLC +// https://www.iana.org/domains/root/db/holiday.html holiday -// homedepot : 2015-04-02 Home Depot Product Authority, LLC +// homedepot : Home Depot Product Authority, LLC +// https://www.iana.org/domains/root/db/homedepot.html homedepot -// homegoods : 2015-07-16 The TJX Companies, Inc. +// homegoods : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/homegoods.html homegoods -// homes : 2014-01-09 XYZ.COM LLC +// homes : XYZ.COM LLC +// https://www.iana.org/domains/root/db/homes.html homes -// homesense : 2015-07-16 The TJX Companies, Inc. +// homesense : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/homesense.html homesense -// honda : 2014-12-18 Honda Motor Co., Ltd. +// honda : Honda Motor Co., Ltd. +// https://www.iana.org/domains/root/db/honda.html honda -// horse : 2013-11-21 Registry Services, LLC +// horse : Registry Services, LLC +// https://www.iana.org/domains/root/db/horse.html horse -// hospital : 2016-10-20 Binky Moon, LLC +// hospital : Binky Moon, LLC +// https://www.iana.org/domains/root/db/hospital.html hospital -// host : 2014-04-17 Radix FZC +// host : Radix FZC DMCC +// https://www.iana.org/domains/root/db/host.html host -// hosting : 2014-05-29 XYZ.COM LLC +// hosting : XYZ.COM LLC +// https://www.iana.org/domains/root/db/hosting.html hosting -// hot : 2015-08-27 Amazon Registry Services, Inc. +// hot : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/hot.html hot -// hoteles : 2015-03-05 Travel Reservations SRL -hoteles - -// hotels : 2016-04-07 Booking.com B.V. +// hotels : Booking.com B.V. +// https://www.iana.org/domains/root/db/hotels.html hotels -// hotmail : 2014-12-18 Microsoft Corporation +// hotmail : Microsoft Corporation +// https://www.iana.org/domains/root/db/hotmail.html hotmail -// house : 2013-11-07 Binky Moon, LLC +// house : Binky Moon, LLC +// https://www.iana.org/domains/root/db/house.html house -// how : 2014-01-23 Charleston Road Registry Inc. +// how : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/how.html how -// hsbc : 2014-10-24 HSBC Global Services (UK) Limited +// hsbc : HSBC Global Services (UK) Limited +// https://www.iana.org/domains/root/db/hsbc.html hsbc -// hughes : 2015-07-30 Hughes Satellite Systems Corporation +// hughes : Hughes Satellite Systems Corporation +// https://www.iana.org/domains/root/db/hughes.html hughes -// hyatt : 2015-07-30 Hyatt GTLD, L.L.C. +// hyatt : Hyatt GTLD, L.L.C. +// https://www.iana.org/domains/root/db/hyatt.html hyatt -// hyundai : 2015-07-09 Hyundai Motor Company +// hyundai : Hyundai Motor Company +// https://www.iana.org/domains/root/db/hyundai.html hyundai -// ibm : 2014-07-31 International Business Machines Corporation +// ibm : International Business Machines Corporation +// https://www.iana.org/domains/root/db/ibm.html ibm -// icbc : 2015-02-19 Industrial and Commercial Bank of China Limited +// icbc : Industrial and Commercial Bank of China Limited +// https://www.iana.org/domains/root/db/icbc.html icbc -// ice : 2014-10-30 IntercontinentalExchange, Inc. +// ice : IntercontinentalExchange, Inc. +// https://www.iana.org/domains/root/db/ice.html ice -// icu : 2015-01-08 ShortDot SA +// icu : ShortDot SA +// https://www.iana.org/domains/root/db/icu.html icu -// ieee : 2015-07-23 IEEE Global LLC +// ieee : IEEE Global LLC +// https://www.iana.org/domains/root/db/ieee.html ieee -// ifm : 2014-01-30 ifm electronic gmbh +// ifm : ifm electronic gmbh +// https://www.iana.org/domains/root/db/ifm.html ifm -// ikano : 2015-07-09 Ikano S.A. +// ikano : Ikano S.A. +// https://www.iana.org/domains/root/db/ikano.html ikano -// imamat : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation) +// imamat : Fondation Aga Khan (Aga Khan Foundation) +// https://www.iana.org/domains/root/db/imamat.html imamat -// imdb : 2015-06-25 Amazon Registry Services, Inc. +// imdb : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/imdb.html imdb -// immo : 2014-07-10 Binky Moon, LLC +// immo : Binky Moon, LLC +// https://www.iana.org/domains/root/db/immo.html immo -// immobilien : 2013-11-07 Dog Beach, LLC +// immobilien : Dog Beach, LLC +// https://www.iana.org/domains/root/db/immobilien.html immobilien -// inc : 2018-03-10 Intercap Registry Inc. +// inc : Intercap Registry Inc. +// https://www.iana.org/domains/root/db/inc.html inc -// industries : 2013-12-05 Binky Moon, LLC +// industries : Binky Moon, LLC +// https://www.iana.org/domains/root/db/industries.html industries -// infiniti : 2014-03-27 NISSAN MOTOR CO., LTD. +// infiniti : NISSAN MOTOR CO., LTD. +// https://www.iana.org/domains/root/db/infiniti.html infiniti -// ing : 2014-01-23 Charleston Road Registry Inc. +// ing : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/ing.html ing -// ink : 2013-12-05 Top Level Design, LLC +// ink : Registry Services, LLC +// https://www.iana.org/domains/root/db/ink.html ink -// institute : 2013-11-07 Binky Moon, LLC +// institute : Binky Moon, LLC +// https://www.iana.org/domains/root/db/institute.html institute -// insurance : 2015-02-19 fTLD Registry Services LLC +// insurance : fTLD Registry Services LLC +// https://www.iana.org/domains/root/db/insurance.html insurance -// insure : 2014-03-20 Binky Moon, LLC +// insure : Binky Moon, LLC +// https://www.iana.org/domains/root/db/insure.html insure -// international : 2013-11-07 Binky Moon, LLC +// international : Binky Moon, LLC +// https://www.iana.org/domains/root/db/international.html international -// intuit : 2015-07-30 Intuit Administrative Services, Inc. +// intuit : Intuit Administrative Services, Inc. +// https://www.iana.org/domains/root/db/intuit.html intuit -// investments : 2014-03-20 Binky Moon, LLC +// investments : Binky Moon, LLC +// https://www.iana.org/domains/root/db/investments.html investments -// ipiranga : 2014-08-28 Ipiranga Produtos de Petroleo S.A. +// ipiranga : Ipiranga Produtos de Petroleo S.A. +// https://www.iana.org/domains/root/db/ipiranga.html ipiranga -// irish : 2014-08-07 Binky Moon, LLC +// irish : Binky Moon, LLC +// https://www.iana.org/domains/root/db/irish.html irish -// ismaili : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation) +// ismaili : Fondation Aga Khan (Aga Khan Foundation) +// https://www.iana.org/domains/root/db/ismaili.html ismaili -// ist : 2014-08-28 Istanbul Metropolitan Municipality +// ist : Istanbul Metropolitan Municipality +// https://www.iana.org/domains/root/db/ist.html ist -// istanbul : 2014-08-28 Istanbul Metropolitan Municipality +// istanbul : Istanbul Metropolitan Municipality +// https://www.iana.org/domains/root/db/istanbul.html istanbul -// itau : 2014-10-02 Itau Unibanco Holding S.A. +// itau : Itau Unibanco Holding S.A. +// https://www.iana.org/domains/root/db/itau.html itau -// itv : 2015-07-09 ITV Services Limited +// itv : ITV Services Limited +// https://www.iana.org/domains/root/db/itv.html itv -// jaguar : 2014-11-13 Jaguar Land Rover Ltd +// jaguar : Jaguar Land Rover Ltd +// https://www.iana.org/domains/root/db/jaguar.html jaguar -// java : 2014-06-19 Oracle Corporation +// java : Oracle Corporation +// https://www.iana.org/domains/root/db/java.html java -// jcb : 2014-11-20 JCB Co., Ltd. +// jcb : JCB Co., Ltd. +// https://www.iana.org/domains/root/db/jcb.html jcb -// jeep : 2015-07-30 FCA US LLC. +// jeep : FCA US LLC. +// https://www.iana.org/domains/root/db/jeep.html jeep -// jetzt : 2014-01-09 Binky Moon, LLC +// jetzt : Binky Moon, LLC +// https://www.iana.org/domains/root/db/jetzt.html jetzt -// jewelry : 2015-03-05 Binky Moon, LLC +// jewelry : Binky Moon, LLC +// https://www.iana.org/domains/root/db/jewelry.html jewelry -// jio : 2015-04-02 Reliance Industries Limited +// jio : Reliance Industries Limited +// https://www.iana.org/domains/root/db/jio.html jio -// jll : 2015-04-02 Jones Lang LaSalle Incorporated +// jll : Jones Lang LaSalle Incorporated +// https://www.iana.org/domains/root/db/jll.html jll -// jmp : 2015-03-26 Matrix IP LLC +// jmp : Matrix IP LLC +// https://www.iana.org/domains/root/db/jmp.html jmp -// jnj : 2015-06-18 Johnson & Johnson Services, Inc. +// jnj : Johnson & Johnson Services, Inc. +// https://www.iana.org/domains/root/db/jnj.html jnj -// joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +// joburg : ZA Central Registry NPC trading as ZA Central Registry +// https://www.iana.org/domains/root/db/joburg.html joburg -// jot : 2014-12-18 Amazon Registry Services, Inc. +// jot : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/jot.html jot -// joy : 2014-12-18 Amazon Registry Services, Inc. +// joy : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/joy.html joy -// jpmorgan : 2015-04-30 JPMorgan Chase Bank, National Association +// jpmorgan : JPMorgan Chase Bank, National Association +// https://www.iana.org/domains/root/db/jpmorgan.html jpmorgan -// jprs : 2014-09-18 Japan Registry Services Co., Ltd. +// jprs : Japan Registry Services Co., Ltd. +// https://www.iana.org/domains/root/db/jprs.html jprs -// juegos : 2014-03-20 Internet Naming Company LLC +// juegos : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/juegos.html juegos -// juniper : 2015-07-30 JUNIPER NETWORKS, INC. +// juniper : JUNIPER NETWORKS, INC. +// https://www.iana.org/domains/root/db/juniper.html juniper -// kaufen : 2013-11-07 Dog Beach, LLC +// kaufen : Dog Beach, LLC +// https://www.iana.org/domains/root/db/kaufen.html kaufen -// kddi : 2014-09-12 KDDI CORPORATION +// kddi : KDDI CORPORATION +// https://www.iana.org/domains/root/db/kddi.html kddi -// kerryhotels : 2015-04-30 Kerry Trading Co. Limited +// kerryhotels : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/kerryhotels.html kerryhotels -// kerrylogistics : 2015-04-09 Kerry Trading Co. Limited +// kerrylogistics : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/kerrylogistics.html kerrylogistics -// kerryproperties : 2015-04-09 Kerry Trading Co. Limited +// kerryproperties : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/kerryproperties.html kerryproperties -// kfh : 2014-12-04 Kuwait Finance House +// kfh : Kuwait Finance House +// https://www.iana.org/domains/root/db/kfh.html kfh -// kia : 2015-07-09 KIA MOTORS CORPORATION +// kia : KIA MOTORS CORPORATION +// https://www.iana.org/domains/root/db/kia.html kia -// kids : 2021-08-13 DotKids Foundation Limited +// kids : DotKids Foundation Limited +// https://www.iana.org/domains/root/db/kids.html kids -// kim : 2013-09-23 Identity Digital Limited +// kim : Identity Digital Limited +// https://www.iana.org/domains/root/db/kim.html kim -// kinder : 2014-11-07 Ferrero Trading Lux S.A. -kinder - -// kindle : 2015-06-25 Amazon Registry Services, Inc. +// kindle : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/kindle.html kindle -// kitchen : 2013-09-20 Binky Moon, LLC +// kitchen : Binky Moon, LLC +// https://www.iana.org/domains/root/db/kitchen.html kitchen -// kiwi : 2013-09-20 DOT KIWI LIMITED +// kiwi : DOT KIWI LIMITED +// https://www.iana.org/domains/root/db/kiwi.html kiwi -// koeln : 2014-01-09 dotKoeln GmbH +// koeln : dotKoeln GmbH +// https://www.iana.org/domains/root/db/koeln.html koeln -// komatsu : 2015-01-08 Komatsu Ltd. +// komatsu : Komatsu Ltd. +// https://www.iana.org/domains/root/db/komatsu.html komatsu -// kosher : 2015-08-20 Kosher Marketing Assets LLC +// kosher : Kosher Marketing Assets LLC +// https://www.iana.org/domains/root/db/kosher.html kosher -// kpmg : 2015-04-23 KPMG International Cooperative (KPMG International Genossenschaft) +// kpmg : KPMG International Cooperative (KPMG International Genossenschaft) +// https://www.iana.org/domains/root/db/kpmg.html kpmg -// kpn : 2015-01-08 Koninklijke KPN N.V. +// kpn : Koninklijke KPN N.V. +// https://www.iana.org/domains/root/db/kpn.html kpn -// krd : 2013-12-05 KRG Department of Information Technology +// krd : KRG Department of Information Technology +// https://www.iana.org/domains/root/db/krd.html krd -// kred : 2013-12-19 KredTLD Pty Ltd +// kred : KredTLD Pty Ltd +// https://www.iana.org/domains/root/db/kred.html kred -// kuokgroup : 2015-04-09 Kerry Trading Co. Limited +// kuokgroup : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/kuokgroup.html kuokgroup -// kyoto : 2014-11-07 Academic Institution: Kyoto Jyoho Gakuen +// kyoto : Academic Institution: Kyoto Jyoho Gakuen +// https://www.iana.org/domains/root/db/kyoto.html kyoto -// lacaixa : 2014-01-09 Fundación Bancaria Caixa d’Estalvis i Pensions de Barcelona, “la Caixa” +// lacaixa : Fundación Bancaria Caixa d’Estalvis i Pensions de Barcelona, “la Caixa” +// https://www.iana.org/domains/root/db/lacaixa.html lacaixa -// lamborghini : 2015-06-04 Automobili Lamborghini S.p.A. +// lamborghini : Automobili Lamborghini S.p.A. +// https://www.iana.org/domains/root/db/lamborghini.html lamborghini -// lamer : 2015-10-01 The Estée Lauder Companies Inc. +// lamer : The Estée Lauder Companies Inc. +// https://www.iana.org/domains/root/db/lamer.html lamer -// lancaster : 2015-02-12 LANCASTER +// lancaster : LANCASTER +// https://www.iana.org/domains/root/db/lancaster.html lancaster -// lancia : 2015-07-31 Fiat Chrysler Automobiles N.V. -lancia - -// land : 2013-09-10 Binky Moon, LLC +// land : Binky Moon, LLC +// https://www.iana.org/domains/root/db/land.html land -// landrover : 2014-11-13 Jaguar Land Rover Ltd +// landrover : Jaguar Land Rover Ltd +// https://www.iana.org/domains/root/db/landrover.html landrover -// lanxess : 2015-07-30 LANXESS Corporation +// lanxess : LANXESS Corporation +// https://www.iana.org/domains/root/db/lanxess.html lanxess -// lasalle : 2015-04-02 Jones Lang LaSalle Incorporated +// lasalle : Jones Lang LaSalle Incorporated +// https://www.iana.org/domains/root/db/lasalle.html lasalle -// lat : 2014-10-16 XYZ.COM LLC +// lat : XYZ.COM LLC +// https://www.iana.org/domains/root/db/lat.html lat -// latino : 2015-07-30 Dish DBS Corporation +// latino : Dish DBS Corporation +// https://www.iana.org/domains/root/db/latino.html latino -// latrobe : 2014-06-16 La Trobe University +// latrobe : La Trobe University +// https://www.iana.org/domains/root/db/latrobe.html latrobe -// law : 2015-01-22 Registry Services, LLC +// law : Registry Services, LLC +// https://www.iana.org/domains/root/db/law.html law -// lawyer : 2014-03-20 Dog Beach, LLC +// lawyer : Dog Beach, LLC +// https://www.iana.org/domains/root/db/lawyer.html lawyer -// lds : 2014-03-20 IRI Domain Management, LLC +// lds : IRI Domain Management, LLC +// https://www.iana.org/domains/root/db/lds.html lds -// lease : 2014-03-06 Binky Moon, LLC +// lease : Binky Moon, LLC +// https://www.iana.org/domains/root/db/lease.html lease -// leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc +// leclerc : A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc +// https://www.iana.org/domains/root/db/leclerc.html leclerc -// lefrak : 2015-07-16 LeFrak Organization, Inc. +// lefrak : LeFrak Organization, Inc. +// https://www.iana.org/domains/root/db/lefrak.html lefrak -// legal : 2014-10-16 Binky Moon, LLC +// legal : Binky Moon, LLC +// https://www.iana.org/domains/root/db/legal.html legal -// lego : 2015-07-16 LEGO Juris A/S +// lego : LEGO Juris A/S +// https://www.iana.org/domains/root/db/lego.html lego -// lexus : 2015-04-23 TOYOTA MOTOR CORPORATION +// lexus : TOYOTA MOTOR CORPORATION +// https://www.iana.org/domains/root/db/lexus.html lexus -// lgbt : 2014-05-08 Identity Digital Limited +// lgbt : Identity Digital Limited +// https://www.iana.org/domains/root/db/lgbt.html lgbt -// lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG +// lidl : Schwarz Domains und Services GmbH & Co. KG +// https://www.iana.org/domains/root/db/lidl.html lidl -// life : 2014-02-06 Binky Moon, LLC +// life : Binky Moon, LLC +// https://www.iana.org/domains/root/db/life.html life -// lifeinsurance : 2015-01-15 American Council of Life Insurers +// lifeinsurance : American Council of Life Insurers +// https://www.iana.org/domains/root/db/lifeinsurance.html lifeinsurance -// lifestyle : 2014-12-11 Lifestyle Domain Holdings, Inc. +// lifestyle : Lifestyle Domain Holdings, Inc. +// https://www.iana.org/domains/root/db/lifestyle.html lifestyle -// lighting : 2013-08-27 Binky Moon, LLC +// lighting : Binky Moon, LLC +// https://www.iana.org/domains/root/db/lighting.html lighting -// like : 2014-12-18 Amazon Registry Services, Inc. +// like : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/like.html like -// lilly : 2015-07-31 Eli Lilly and Company +// lilly : Eli Lilly and Company +// https://www.iana.org/domains/root/db/lilly.html lilly -// limited : 2014-03-06 Binky Moon, LLC +// limited : Binky Moon, LLC +// https://www.iana.org/domains/root/db/limited.html limited -// limo : 2013-10-17 Binky Moon, LLC +// limo : Binky Moon, LLC +// https://www.iana.org/domains/root/db/limo.html limo -// lincoln : 2014-11-13 Ford Motor Company +// lincoln : Ford Motor Company +// https://www.iana.org/domains/root/db/lincoln.html lincoln -// link : 2013-11-14 Nova Registry Ltd +// link : Nova Registry Ltd +// https://www.iana.org/domains/root/db/link.html link -// lipsy : 2015-06-25 Lipsy Ltd +// lipsy : Lipsy Ltd +// https://www.iana.org/domains/root/db/lipsy.html lipsy -// live : 2014-12-04 Dog Beach, LLC +// live : Dog Beach, LLC +// https://www.iana.org/domains/root/db/live.html live -// living : 2015-07-30 Lifestyle Domain Holdings, Inc. +// living : Lifestyle Domain Holdings, Inc. +// https://www.iana.org/domains/root/db/living.html living -// llc : 2017-12-14 Identity Digital Limited +// llc : Identity Digital Limited +// https://www.iana.org/domains/root/db/llc.html llc -// llp : 2019-08-26 Intercap Registry Inc. +// llp : Intercap Registry Inc. +// https://www.iana.org/domains/root/db/llp.html llp -// loan : 2014-11-20 dot Loan Limited +// loan : dot Loan Limited +// https://www.iana.org/domains/root/db/loan.html loan -// loans : 2014-03-20 Binky Moon, LLC +// loans : Binky Moon, LLC +// https://www.iana.org/domains/root/db/loans.html loans -// locker : 2015-06-04 Dish DBS Corporation +// locker : Orange Domains LLC +// https://www.iana.org/domains/root/db/locker.html locker -// locus : 2015-06-25 Locus Analytics LLC +// locus : Locus Analytics LLC +// https://www.iana.org/domains/root/db/locus.html locus -// lol : 2015-01-30 XYZ.COM LLC +// lol : XYZ.COM LLC +// https://www.iana.org/domains/root/db/lol.html lol -// london : 2013-11-14 Dot London Domains Limited +// london : Dot London Domains Limited +// https://www.iana.org/domains/root/db/london.html london -// lotte : 2014-11-07 Lotte Holdings Co., Ltd. +// lotte : Lotte Holdings Co., Ltd. +// https://www.iana.org/domains/root/db/lotte.html lotte -// lotto : 2014-04-10 Identity Digital Limited +// lotto : Identity Digital Limited +// https://www.iana.org/domains/root/db/lotto.html lotto -// love : 2014-12-22 Merchant Law Group LLP +// love : Merchant Law Group LLP +// https://www.iana.org/domains/root/db/love.html love -// lpl : 2015-07-30 LPL Holdings, Inc. +// lpl : LPL Holdings, Inc. +// https://www.iana.org/domains/root/db/lpl.html lpl -// lplfinancial : 2015-07-30 LPL Holdings, Inc. +// lplfinancial : LPL Holdings, Inc. +// https://www.iana.org/domains/root/db/lplfinancial.html lplfinancial -// ltd : 2014-09-25 Binky Moon, LLC +// ltd : Binky Moon, LLC +// https://www.iana.org/domains/root/db/ltd.html ltd -// ltda : 2014-04-17 InterNetX, Corp +// ltda : InterNetX, Corp +// https://www.iana.org/domains/root/db/ltda.html ltda -// lundbeck : 2015-08-06 H. Lundbeck A/S +// lundbeck : H. Lundbeck A/S +// https://www.iana.org/domains/root/db/lundbeck.html lundbeck -// luxe : 2014-01-09 Registry Services, LLC +// luxe : Registry Services, LLC +// https://www.iana.org/domains/root/db/luxe.html luxe -// luxury : 2013-10-17 Luxury Partners, LLC +// luxury : Luxury Partners, LLC +// https://www.iana.org/domains/root/db/luxury.html luxury -// madrid : 2014-05-01 Comunidad de Madrid +// madrid : Comunidad de Madrid +// https://www.iana.org/domains/root/db/madrid.html madrid -// maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF) +// maif : Mutuelle Assurance Instituteur France (MAIF) +// https://www.iana.org/domains/root/db/maif.html maif -// maison : 2013-12-05 Binky Moon, LLC +// maison : Binky Moon, LLC +// https://www.iana.org/domains/root/db/maison.html maison -// makeup : 2015-01-15 XYZ.COM LLC +// makeup : XYZ.COM LLC +// https://www.iana.org/domains/root/db/makeup.html makeup -// man : 2014-12-04 MAN SE +// man : MAN SE +// https://www.iana.org/domains/root/db/man.html man -// management : 2013-11-07 Binky Moon, LLC +// management : Binky Moon, LLC +// https://www.iana.org/domains/root/db/management.html management -// mango : 2013-10-24 PUNTO FA S.L. +// mango : PUNTO FA S.L. +// https://www.iana.org/domains/root/db/mango.html mango -// map : 2016-06-09 Charleston Road Registry Inc. +// map : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/map.html map -// market : 2014-03-06 Dog Beach, LLC +// market : Dog Beach, LLC +// https://www.iana.org/domains/root/db/market.html market -// marketing : 2013-11-07 Binky Moon, LLC +// marketing : Binky Moon, LLC +// https://www.iana.org/domains/root/db/marketing.html marketing -// markets : 2014-12-11 Dog Beach, LLC +// markets : Dog Beach, LLC +// https://www.iana.org/domains/root/db/markets.html markets -// marriott : 2014-10-09 Marriott Worldwide Corporation +// marriott : Marriott Worldwide Corporation +// https://www.iana.org/domains/root/db/marriott.html marriott -// marshalls : 2015-07-16 The TJX Companies, Inc. +// marshalls : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/marshalls.html marshalls -// maserati : 2015-07-31 Fiat Chrysler Automobiles N.V. -maserati - -// mattel : 2015-08-06 Mattel Sites, Inc. +// mattel : Mattel Sites, Inc. +// https://www.iana.org/domains/root/db/mattel.html mattel -// mba : 2015-04-02 Binky Moon, LLC +// mba : Binky Moon, LLC +// https://www.iana.org/domains/root/db/mba.html mba -// mckinsey : 2015-07-31 McKinsey Holdings, Inc. +// mckinsey : McKinsey Holdings, Inc. +// https://www.iana.org/domains/root/db/mckinsey.html mckinsey -// med : 2015-08-06 Medistry LLC +// med : Medistry LLC +// https://www.iana.org/domains/root/db/med.html med -// media : 2014-03-06 Binky Moon, LLC +// media : Binky Moon, LLC +// https://www.iana.org/domains/root/db/media.html media -// meet : 2014-01-16 Charleston Road Registry Inc. +// meet : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/meet.html meet -// melbourne : 2014-05-29 The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation +// melbourne : The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation +// https://www.iana.org/domains/root/db/melbourne.html melbourne -// meme : 2014-01-30 Charleston Road Registry Inc. +// meme : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/meme.html meme -// memorial : 2014-10-16 Dog Beach, LLC +// memorial : Dog Beach, LLC +// https://www.iana.org/domains/root/db/memorial.html memorial -// men : 2015-02-26 Exclusive Registry Limited +// men : Exclusive Registry Limited +// https://www.iana.org/domains/root/db/men.html men -// menu : 2013-09-11 Dot Menu Registry, LLC +// menu : Dot Menu Registry, LLC +// https://www.iana.org/domains/root/db/menu.html menu -// merckmsd : 2016-07-14 MSD Registry Holdings, Inc. +// merckmsd : MSD Registry Holdings, Inc. +// https://www.iana.org/domains/root/db/merckmsd.html merckmsd -// miami : 2013-12-19 Registry Services, LLC +// miami : Registry Services, LLC +// https://www.iana.org/domains/root/db/miami.html miami -// microsoft : 2014-12-18 Microsoft Corporation +// microsoft : Microsoft Corporation +// https://www.iana.org/domains/root/db/microsoft.html microsoft -// mini : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft +// mini : Bayerische Motoren Werke Aktiengesellschaft +// https://www.iana.org/domains/root/db/mini.html mini -// mint : 2015-07-30 Intuit Administrative Services, Inc. +// mint : Intuit Administrative Services, Inc. +// https://www.iana.org/domains/root/db/mint.html mint -// mit : 2015-07-02 Massachusetts Institute of Technology +// mit : Massachusetts Institute of Technology +// https://www.iana.org/domains/root/db/mit.html mit -// mitsubishi : 2015-07-23 Mitsubishi Corporation +// mitsubishi : Mitsubishi Corporation +// https://www.iana.org/domains/root/db/mitsubishi.html mitsubishi -// mlb : 2015-05-21 MLB Advanced Media DH, LLC +// mlb : MLB Advanced Media DH, LLC +// https://www.iana.org/domains/root/db/mlb.html mlb -// mls : 2015-04-23 The Canadian Real Estate Association +// mls : The Canadian Real Estate Association +// https://www.iana.org/domains/root/db/mls.html mls -// mma : 2014-11-07 MMA IARD +// mma : MMA IARD +// https://www.iana.org/domains/root/db/mma.html mma -// mobile : 2016-06-02 Dish DBS Corporation +// mobile : Dish DBS Corporation +// https://www.iana.org/domains/root/db/mobile.html mobile -// moda : 2013-11-07 Dog Beach, LLC +// moda : Dog Beach, LLC +// https://www.iana.org/domains/root/db/moda.html moda -// moe : 2013-11-13 Interlink Systems Innovation Institute K.K. +// moe : Interlink Systems Innovation Institute K.K. +// https://www.iana.org/domains/root/db/moe.html moe -// moi : 2014-12-18 Amazon Registry Services, Inc. +// moi : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/moi.html moi -// mom : 2015-04-16 XYZ.COM LLC +// mom : XYZ.COM LLC +// https://www.iana.org/domains/root/db/mom.html mom -// monash : 2013-09-30 Monash University +// monash : Monash University +// https://www.iana.org/domains/root/db/monash.html monash -// money : 2014-10-16 Binky Moon, LLC +// money : Binky Moon, LLC +// https://www.iana.org/domains/root/db/money.html money -// monster : 2015-09-11 XYZ.COM LLC +// monster : XYZ.COM LLC +// https://www.iana.org/domains/root/db/monster.html monster -// mormon : 2013-12-05 IRI Domain Management, LLC +// mormon : IRI Domain Management, LLC +// https://www.iana.org/domains/root/db/mormon.html mormon -// mortgage : 2014-03-20 Dog Beach, LLC +// mortgage : Dog Beach, LLC +// https://www.iana.org/domains/root/db/mortgage.html mortgage -// moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +// moscow : Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +// https://www.iana.org/domains/root/db/moscow.html moscow -// moto : 2015-06-04 Motorola Trademark Holdings, LLC +// moto : Motorola Trademark Holdings, LLC +// https://www.iana.org/domains/root/db/moto.html moto -// motorcycles : 2014-01-09 XYZ.COM LLC +// motorcycles : XYZ.COM LLC +// https://www.iana.org/domains/root/db/motorcycles.html motorcycles -// mov : 2014-01-30 Charleston Road Registry Inc. +// mov : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/mov.html mov -// movie : 2015-02-05 Binky Moon, LLC +// movie : Binky Moon, LLC +// https://www.iana.org/domains/root/db/movie.html movie -// msd : 2015-07-23 MSD Registry Holdings, Inc. +// msd : MSD Registry Holdings, Inc. +// https://www.iana.org/domains/root/db/msd.html msd -// mtn : 2014-12-04 MTN Dubai Limited +// mtn : MTN Dubai Limited +// https://www.iana.org/domains/root/db/mtn.html mtn -// mtr : 2015-03-12 MTR Corporation Limited +// mtr : MTR Corporation Limited +// https://www.iana.org/domains/root/db/mtr.html mtr -// music : 2021-05-04 DotMusic Limited +// music : DotMusic Limited +// https://www.iana.org/domains/root/db/music.html music -// mutual : 2015-04-02 Northwestern Mutual MU TLD Registry, LLC -mutual - -// nab : 2015-08-20 National Australia Bank Limited +// nab : National Australia Bank Limited +// https://www.iana.org/domains/root/db/nab.html nab -// nagoya : 2013-10-24 GMO Registry, Inc. +// nagoya : GMO Registry, Inc. +// https://www.iana.org/domains/root/db/nagoya.html nagoya -// natura : 2015-03-12 NATURA COSMÉTICOS S.A. +// natura : NATURA COSMÉTICOS S.A. +// https://www.iana.org/domains/root/db/natura.html natura -// navy : 2014-03-06 Dog Beach, LLC +// navy : Dog Beach, LLC +// https://www.iana.org/domains/root/db/navy.html navy -// nba : 2015-07-31 NBA REGISTRY, LLC +// nba : NBA REGISTRY, LLC +// https://www.iana.org/domains/root/db/nba.html nba -// nec : 2015-01-08 NEC Corporation +// nec : NEC Corporation +// https://www.iana.org/domains/root/db/nec.html nec -// netbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +// netbank : COMMONWEALTH BANK OF AUSTRALIA +// https://www.iana.org/domains/root/db/netbank.html netbank -// netflix : 2015-06-18 Netflix, Inc. +// netflix : Netflix, Inc. +// https://www.iana.org/domains/root/db/netflix.html netflix -// network : 2013-11-14 Binky Moon, LLC +// network : Binky Moon, LLC +// https://www.iana.org/domains/root/db/network.html network -// neustar : 2013-12-05 NeuStar, Inc. +// neustar : NeuStar, Inc. +// https://www.iana.org/domains/root/db/neustar.html neustar -// new : 2014-01-30 Charleston Road Registry Inc. +// new : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/new.html new -// news : 2014-12-18 Dog Beach, LLC +// news : Dog Beach, LLC +// https://www.iana.org/domains/root/db/news.html news -// next : 2015-06-18 Next plc +// next : Next plc +// https://www.iana.org/domains/root/db/next.html next -// nextdirect : 2015-06-18 Next plc +// nextdirect : Next plc +// https://www.iana.org/domains/root/db/nextdirect.html nextdirect -// nexus : 2014-07-24 Charleston Road Registry Inc. +// nexus : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/nexus.html nexus -// nfl : 2015-07-23 NFL Reg Ops LLC +// nfl : NFL Reg Ops LLC +// https://www.iana.org/domains/root/db/nfl.html nfl -// ngo : 2014-03-06 Public Interest Registry +// ngo : Public Interest Registry +// https://www.iana.org/domains/root/db/ngo.html ngo -// nhk : 2014-02-13 Japan Broadcasting Corporation (NHK) +// nhk : Japan Broadcasting Corporation (NHK) +// https://www.iana.org/domains/root/db/nhk.html nhk -// nico : 2014-12-04 DWANGO Co., Ltd. +// nico : DWANGO Co., Ltd. +// https://www.iana.org/domains/root/db/nico.html nico -// nike : 2015-07-23 NIKE, Inc. +// nike : NIKE, Inc. +// https://www.iana.org/domains/root/db/nike.html nike -// nikon : 2015-05-21 NIKON CORPORATION +// nikon : NIKON CORPORATION +// https://www.iana.org/domains/root/db/nikon.html nikon -// ninja : 2013-11-07 Dog Beach, LLC +// ninja : Dog Beach, LLC +// https://www.iana.org/domains/root/db/ninja.html ninja -// nissan : 2014-03-27 NISSAN MOTOR CO., LTD. +// nissan : NISSAN MOTOR CO., LTD. +// https://www.iana.org/domains/root/db/nissan.html nissan -// nissay : 2015-10-29 Nippon Life Insurance Company +// nissay : Nippon Life Insurance Company +// https://www.iana.org/domains/root/db/nissay.html nissay -// nokia : 2015-01-08 Nokia Corporation +// nokia : Nokia Corporation +// https://www.iana.org/domains/root/db/nokia.html nokia -// northwesternmutual : 2015-06-18 Northwestern Mutual Registry, LLC -northwesternmutual - -// norton : 2014-12-04 NortonLifeLock Inc. +// norton : NortonLifeLock Inc. +// https://www.iana.org/domains/root/db/norton.html norton -// now : 2015-06-25 Amazon Registry Services, Inc. +// now : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/now.html now -// nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// nowruz : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// https://www.iana.org/domains/root/db/nowruz.html nowruz -// nowtv : 2015-05-14 Starbucks (HK) Limited +// nowtv : Starbucks (HK) Limited +// https://www.iana.org/domains/root/db/nowtv.html nowtv -// nra : 2014-05-22 NRA Holdings Company, INC. +// nra : NRA Holdings Company, INC. +// https://www.iana.org/domains/root/db/nra.html nra -// nrw : 2013-11-21 Minds + Machines GmbH +// nrw : Minds + Machines GmbH +// https://www.iana.org/domains/root/db/nrw.html nrw -// ntt : 2014-10-31 NIPPON TELEGRAPH AND TELEPHONE CORPORATION +// ntt : NIPPON TELEGRAPH AND TELEPHONE CORPORATION +// https://www.iana.org/domains/root/db/ntt.html ntt -// nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications +// nyc : The City of New York by and through the New York City Department of Information Technology & Telecommunications +// https://www.iana.org/domains/root/db/nyc.html nyc -// obi : 2014-09-25 OBI Group Holding SE & Co. KGaA +// obi : OBI Group Holding SE & Co. KGaA +// https://www.iana.org/domains/root/db/obi.html obi -// observer : 2015-04-30 Dog Beach, LLC +// observer : Fegistry, LLC +// https://www.iana.org/domains/root/db/observer.html observer -// office : 2015-03-12 Microsoft Corporation +// office : Microsoft Corporation +// https://www.iana.org/domains/root/db/office.html office -// okinawa : 2013-12-05 BRregistry, Inc. +// okinawa : BRregistry, Inc. +// https://www.iana.org/domains/root/db/okinawa.html okinawa -// olayan : 2015-05-14 Crescent Holding GmbH +// olayan : Competrol (Luxembourg) Sarl +// https://www.iana.org/domains/root/db/olayan.html olayan -// olayangroup : 2015-05-14 Crescent Holding GmbH +// olayangroup : Competrol (Luxembourg) Sarl +// https://www.iana.org/domains/root/db/olayangroup.html olayangroup -// oldnavy : 2015-07-31 The Gap, Inc. +// oldnavy : The Gap, Inc. +// https://www.iana.org/domains/root/db/oldnavy.html oldnavy -// ollo : 2015-06-04 Dish DBS Corporation +// ollo : Dish DBS Corporation +// https://www.iana.org/domains/root/db/ollo.html ollo -// omega : 2015-01-08 The Swatch Group Ltd +// omega : The Swatch Group Ltd +// https://www.iana.org/domains/root/db/omega.html omega -// one : 2014-11-07 One.com A/S +// one : One.com A/S +// https://www.iana.org/domains/root/db/one.html one -// ong : 2014-03-06 Public Interest Registry +// ong : Public Interest Registry +// https://www.iana.org/domains/root/db/ong.html ong -// onl : 2013-09-16 iRegistry GmbH +// onl : iRegistry GmbH +// https://www.iana.org/domains/root/db/onl.html onl -// online : 2015-01-15 Radix FZC +// online : Radix FZC DMCC +// https://www.iana.org/domains/root/db/online.html online -// ooo : 2014-01-09 INFIBEAM AVENUES LIMITED +// ooo : INFIBEAM AVENUES LIMITED +// https://www.iana.org/domains/root/db/ooo.html ooo -// open : 2015-07-31 American Express Travel Related Services Company, Inc. +// open : American Express Travel Related Services Company, Inc. +// https://www.iana.org/domains/root/db/open.html open -// oracle : 2014-06-19 Oracle Corporation +// oracle : Oracle Corporation +// https://www.iana.org/domains/root/db/oracle.html oracle -// orange : 2015-03-12 Orange Brand Services Limited +// orange : Orange Brand Services Limited +// https://www.iana.org/domains/root/db/orange.html orange -// organic : 2014-03-27 Identity Digital Limited +// organic : Identity Digital Limited +// https://www.iana.org/domains/root/db/organic.html organic -// origins : 2015-10-01 The Estée Lauder Companies Inc. +// origins : The Estée Lauder Companies Inc. +// https://www.iana.org/domains/root/db/origins.html origins -// osaka : 2014-09-04 Osaka Registry Co., Ltd. +// osaka : Osaka Registry Co., Ltd. +// https://www.iana.org/domains/root/db/osaka.html osaka -// otsuka : 2013-10-11 Otsuka Holdings Co., Ltd. +// otsuka : Otsuka Holdings Co., Ltd. +// https://www.iana.org/domains/root/db/otsuka.html otsuka -// ott : 2015-06-04 Dish DBS Corporation +// ott : Dish DBS Corporation +// https://www.iana.org/domains/root/db/ott.html ott -// ovh : 2014-01-16 MédiaBC +// ovh : MédiaBC +// https://www.iana.org/domains/root/db/ovh.html ovh -// page : 2014-12-04 Charleston Road Registry Inc. +// page : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/page.html page -// panasonic : 2015-07-30 Panasonic Holdings Corporation +// panasonic : Panasonic Holdings Corporation +// https://www.iana.org/domains/root/db/panasonic.html panasonic -// paris : 2014-01-30 City of Paris +// paris : City of Paris +// https://www.iana.org/domains/root/db/paris.html paris -// pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// pars : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// https://www.iana.org/domains/root/db/pars.html pars -// partners : 2013-12-05 Binky Moon, LLC +// partners : Binky Moon, LLC +// https://www.iana.org/domains/root/db/partners.html partners -// parts : 2013-12-05 Binky Moon, LLC +// parts : Binky Moon, LLC +// https://www.iana.org/domains/root/db/parts.html parts -// party : 2014-09-11 Blue Sky Registry Limited +// party : Blue Sky Registry Limited +// https://www.iana.org/domains/root/db/party.html party -// passagens : 2015-03-05 Travel Reservations SRL -passagens - -// pay : 2015-08-27 Amazon Registry Services, Inc. +// pay : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/pay.html pay -// pccw : 2015-05-14 PCCW Enterprises Limited +// pccw : PCCW Enterprises Limited +// https://www.iana.org/domains/root/db/pccw.html pccw -// pet : 2015-05-07 Identity Digital Limited +// pet : Identity Digital Limited +// https://www.iana.org/domains/root/db/pet.html pet -// pfizer : 2015-09-11 Pfizer Inc. +// pfizer : Pfizer Inc. +// https://www.iana.org/domains/root/db/pfizer.html pfizer -// pharmacy : 2014-06-19 National Association of Boards of Pharmacy +// pharmacy : National Association of Boards of Pharmacy +// https://www.iana.org/domains/root/db/pharmacy.html pharmacy -// phd : 2016-07-28 Charleston Road Registry Inc. +// phd : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/phd.html phd -// philips : 2014-11-07 Koninklijke Philips N.V. +// philips : Koninklijke Philips N.V. +// https://www.iana.org/domains/root/db/philips.html philips -// phone : 2016-06-02 Dish DBS Corporation +// phone : Dish DBS Corporation +// https://www.iana.org/domains/root/db/phone.html phone -// photo : 2013-11-14 Registry Services, LLC +// photo : Registry Services, LLC +// https://www.iana.org/domains/root/db/photo.html photo -// photography : 2013-09-20 Binky Moon, LLC +// photography : Binky Moon, LLC +// https://www.iana.org/domains/root/db/photography.html photography -// photos : 2013-10-17 Binky Moon, LLC +// photos : Binky Moon, LLC +// https://www.iana.org/domains/root/db/photos.html photos -// physio : 2014-05-01 PhysBiz Pty Ltd +// physio : PhysBiz Pty Ltd +// https://www.iana.org/domains/root/db/physio.html physio -// pics : 2013-11-14 XYZ.COM LLC +// pics : XYZ.COM LLC +// https://www.iana.org/domains/root/db/pics.html pics -// pictet : 2014-06-26 Pictet Europe S.A. +// pictet : Pictet Europe S.A. +// https://www.iana.org/domains/root/db/pictet.html pictet -// pictures : 2014-03-06 Binky Moon, LLC +// pictures : Binky Moon, LLC +// https://www.iana.org/domains/root/db/pictures.html pictures -// pid : 2015-01-08 Top Level Spectrum, Inc. +// pid : Top Level Spectrum, Inc. +// https://www.iana.org/domains/root/db/pid.html pid -// pin : 2014-12-18 Amazon Registry Services, Inc. +// pin : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/pin.html pin -// ping : 2015-06-11 Ping Registry Provider, Inc. +// ping : Ping Registry Provider, Inc. +// https://www.iana.org/domains/root/db/ping.html ping -// pink : 2013-10-01 Identity Digital Limited +// pink : Identity Digital Limited +// https://www.iana.org/domains/root/db/pink.html pink -// pioneer : 2015-07-16 Pioneer Corporation +// pioneer : Pioneer Corporation +// https://www.iana.org/domains/root/db/pioneer.html pioneer -// pizza : 2014-06-26 Binky Moon, LLC +// pizza : Binky Moon, LLC +// https://www.iana.org/domains/root/db/pizza.html pizza -// place : 2014-04-24 Binky Moon, LLC +// place : Binky Moon, LLC +// https://www.iana.org/domains/root/db/place.html place -// play : 2015-03-05 Charleston Road Registry Inc. +// play : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/play.html play -// playstation : 2015-07-02 Sony Interactive Entertainment Inc. +// playstation : Sony Interactive Entertainment Inc. +// https://www.iana.org/domains/root/db/playstation.html playstation -// plumbing : 2013-09-10 Binky Moon, LLC +// plumbing : Binky Moon, LLC +// https://www.iana.org/domains/root/db/plumbing.html plumbing -// plus : 2015-02-05 Binky Moon, LLC +// plus : Binky Moon, LLC +// https://www.iana.org/domains/root/db/plus.html plus -// pnc : 2015-07-02 PNC Domain Co., LLC +// pnc : PNC Domain Co., LLC +// https://www.iana.org/domains/root/db/pnc.html pnc -// pohl : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +// pohl : Deutsche Vermögensberatung Aktiengesellschaft DVAG +// https://www.iana.org/domains/root/db/pohl.html pohl -// poker : 2014-07-03 Identity Digital Limited +// poker : Identity Digital Limited +// https://www.iana.org/domains/root/db/poker.html poker -// politie : 2015-08-20 Politie Nederland +// politie : Politie Nederland +// https://www.iana.org/domains/root/db/politie.html politie -// porn : 2014-10-16 ICM Registry PN LLC +// porn : ICM Registry PN LLC +// https://www.iana.org/domains/root/db/porn.html porn -// pramerica : 2015-07-30 Prudential Financial, Inc. +// pramerica : Prudential Financial, Inc. +// https://www.iana.org/domains/root/db/pramerica.html pramerica -// praxi : 2013-12-05 Praxi S.p.A. +// praxi : Praxi S.p.A. +// https://www.iana.org/domains/root/db/praxi.html praxi -// press : 2014-04-03 Radix FZC +// press : Radix FZC DMCC +// https://www.iana.org/domains/root/db/press.html press -// prime : 2015-06-25 Amazon Registry Services, Inc. +// prime : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/prime.html prime -// prod : 2014-01-23 Charleston Road Registry Inc. +// prod : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/prod.html prod -// productions : 2013-12-05 Binky Moon, LLC +// productions : Binky Moon, LLC +// https://www.iana.org/domains/root/db/productions.html productions -// prof : 2014-07-24 Charleston Road Registry Inc. +// prof : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/prof.html prof -// progressive : 2015-07-23 Progressive Casualty Insurance Company +// progressive : Progressive Casualty Insurance Company +// https://www.iana.org/domains/root/db/progressive.html progressive -// promo : 2014-12-18 Identity Digital Limited +// promo : Identity Digital Limited +// https://www.iana.org/domains/root/db/promo.html promo -// properties : 2013-12-05 Binky Moon, LLC +// properties : Binky Moon, LLC +// https://www.iana.org/domains/root/db/properties.html properties -// property : 2014-05-22 Internet Naming Company LLC +// property : Digital Property Infrastructure Limited +// https://www.iana.org/domains/root/db/property.html property -// protection : 2015-04-23 XYZ.COM LLC +// protection : XYZ.COM LLC +// https://www.iana.org/domains/root/db/protection.html protection -// pru : 2015-07-30 Prudential Financial, Inc. +// pru : Prudential Financial, Inc. +// https://www.iana.org/domains/root/db/pru.html pru -// prudential : 2015-07-30 Prudential Financial, Inc. +// prudential : Prudential Financial, Inc. +// https://www.iana.org/domains/root/db/prudential.html prudential -// pub : 2013-12-12 Dog Beach, LLC +// pub : Dog Beach, LLC +// https://www.iana.org/domains/root/db/pub.html pub -// pwc : 2015-10-29 PricewaterhouseCoopers LLP +// pwc : PricewaterhouseCoopers LLP +// https://www.iana.org/domains/root/db/pwc.html pwc -// qpon : 2013-11-14 dotQPON LLC +// qpon : dotQPON LLC +// https://www.iana.org/domains/root/db/qpon.html qpon -// quebec : 2013-12-19 PointQuébec Inc +// quebec : PointQuébec Inc +// https://www.iana.org/domains/root/db/quebec.html quebec -// quest : 2015-03-26 XYZ.COM LLC +// quest : XYZ.COM LLC +// https://www.iana.org/domains/root/db/quest.html quest -// racing : 2014-12-04 Premier Registry Limited +// racing : Premier Registry Limited +// https://www.iana.org/domains/root/db/racing.html racing -// radio : 2016-07-21 European Broadcasting Union (EBU) +// radio : European Broadcasting Union (EBU) +// https://www.iana.org/domains/root/db/radio.html radio -// read : 2014-12-18 Amazon Registry Services, Inc. +// read : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/read.html read -// realestate : 2015-09-11 dotRealEstate LLC +// realestate : dotRealEstate LLC +// https://www.iana.org/domains/root/db/realestate.html realestate -// realtor : 2014-05-29 Real Estate Domains LLC +// realtor : Real Estate Domains LLC +// https://www.iana.org/domains/root/db/realtor.html realtor -// realty : 2015-03-19 Dog Beach, LLC +// realty : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/realty.html realty -// recipes : 2013-10-17 Binky Moon, LLC +// recipes : Binky Moon, LLC +// https://www.iana.org/domains/root/db/recipes.html recipes -// red : 2013-11-07 Identity Digital Limited +// red : Identity Digital Limited +// https://www.iana.org/domains/root/db/red.html red -// redstone : 2014-10-31 Redstone Haute Couture Co., Ltd. +// redstone : Redstone Haute Couture Co., Ltd. +// https://www.iana.org/domains/root/db/redstone.html redstone -// redumbrella : 2015-03-26 Travelers TLD, LLC +// redumbrella : Travelers TLD, LLC +// https://www.iana.org/domains/root/db/redumbrella.html redumbrella -// rehab : 2014-03-06 Dog Beach, LLC +// rehab : Dog Beach, LLC +// https://www.iana.org/domains/root/db/rehab.html rehab -// reise : 2014-03-13 Binky Moon, LLC +// reise : Binky Moon, LLC +// https://www.iana.org/domains/root/db/reise.html reise -// reisen : 2014-03-06 Binky Moon, LLC +// reisen : Binky Moon, LLC +// https://www.iana.org/domains/root/db/reisen.html reisen -// reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc. +// reit : National Association of Real Estate Investment Trusts, Inc. +// https://www.iana.org/domains/root/db/reit.html reit -// reliance : 2015-04-02 Reliance Industries Limited +// reliance : Reliance Industries Limited +// https://www.iana.org/domains/root/db/reliance.html reliance -// ren : 2013-12-12 ZDNS International Limited +// ren : ZDNS International Limited +// https://www.iana.org/domains/root/db/ren.html ren -// rent : 2014-12-04 XYZ.COM LLC +// rent : XYZ.COM LLC +// https://www.iana.org/domains/root/db/rent.html rent -// rentals : 2013-12-05 Binky Moon, LLC +// rentals : Binky Moon, LLC +// https://www.iana.org/domains/root/db/rentals.html rentals -// repair : 2013-11-07 Binky Moon, LLC +// repair : Binky Moon, LLC +// https://www.iana.org/domains/root/db/repair.html repair -// report : 2013-12-05 Binky Moon, LLC +// report : Binky Moon, LLC +// https://www.iana.org/domains/root/db/report.html report -// republican : 2014-03-20 Dog Beach, LLC +// republican : Dog Beach, LLC +// https://www.iana.org/domains/root/db/republican.html republican -// rest : 2013-12-19 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +// rest : Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +// https://www.iana.org/domains/root/db/rest.html rest -// restaurant : 2014-07-03 Binky Moon, LLC +// restaurant : Binky Moon, LLC +// https://www.iana.org/domains/root/db/restaurant.html restaurant -// review : 2014-11-20 dot Review Limited +// review : dot Review Limited +// https://www.iana.org/domains/root/db/review.html review -// reviews : 2013-09-13 Dog Beach, LLC +// reviews : Dog Beach, LLC +// https://www.iana.org/domains/root/db/reviews.html reviews -// rexroth : 2015-06-18 Robert Bosch GMBH +// rexroth : Robert Bosch GMBH +// https://www.iana.org/domains/root/db/rexroth.html rexroth -// rich : 2013-11-21 iRegistry GmbH +// rich : iRegistry GmbH +// https://www.iana.org/domains/root/db/rich.html rich -// richardli : 2015-05-14 Pacific Century Asset Management (HK) Limited +// richardli : Pacific Century Asset Management (HK) Limited +// https://www.iana.org/domains/root/db/richardli.html richardli -// ricoh : 2014-11-20 Ricoh Company, Ltd. +// ricoh : Ricoh Company, Ltd. +// https://www.iana.org/domains/root/db/ricoh.html ricoh -// ril : 2015-04-02 Reliance Industries Limited +// ril : Reliance Industries Limited +// https://www.iana.org/domains/root/db/ril.html ril -// rio : 2014-02-27 Empresa Municipal de Informática SA - IPLANRIO +// rio : Empresa Municipal de Informática SA - IPLANRIO +// https://www.iana.org/domains/root/db/rio.html rio -// rip : 2014-07-10 Dog Beach, LLC +// rip : Dog Beach, LLC +// https://www.iana.org/domains/root/db/rip.html rip -// rocher : 2014-12-18 Ferrero Trading Lux S.A. -rocher - -// rocks : 2013-11-14 Dog Beach, LLC +// rocks : Dog Beach, LLC +// https://www.iana.org/domains/root/db/rocks.html rocks -// rodeo : 2013-12-19 Registry Services, LLC +// rodeo : Registry Services, LLC +// https://www.iana.org/domains/root/db/rodeo.html rodeo -// rogers : 2015-08-06 Rogers Communications Canada Inc. +// rogers : Rogers Communications Canada Inc. +// https://www.iana.org/domains/root/db/rogers.html rogers -// room : 2014-12-18 Amazon Registry Services, Inc. +// room : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/room.html room -// rsvp : 2014-05-08 Charleston Road Registry Inc. +// rsvp : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/rsvp.html rsvp -// rugby : 2016-12-15 World Rugby Strategic Developments Limited +// rugby : World Rugby Strategic Developments Limited +// https://www.iana.org/domains/root/db/rugby.html rugby -// ruhr : 2013-10-02 dotSaarland GmbH +// ruhr : dotSaarland GmbH +// https://www.iana.org/domains/root/db/ruhr.html ruhr -// run : 2015-03-19 Binky Moon, LLC +// run : Binky Moon, LLC +// https://www.iana.org/domains/root/db/run.html run -// rwe : 2015-04-02 RWE AG +// rwe : RWE AG +// https://www.iana.org/domains/root/db/rwe.html rwe -// ryukyu : 2014-01-09 BRregistry, Inc. +// ryukyu : BRregistry, Inc. +// https://www.iana.org/domains/root/db/ryukyu.html ryukyu -// saarland : 2013-12-12 dotSaarland GmbH +// saarland : dotSaarland GmbH +// https://www.iana.org/domains/root/db/saarland.html saarland -// safe : 2014-12-18 Amazon Registry Services, Inc. +// safe : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/safe.html safe -// safety : 2015-01-08 Safety Registry Services, LLC. +// safety : Safety Registry Services, LLC. +// https://www.iana.org/domains/root/db/safety.html safety -// sakura : 2014-12-18 SAKURA Internet Inc. +// sakura : SAKURA Internet Inc. +// https://www.iana.org/domains/root/db/sakura.html sakura -// sale : 2014-10-16 Dog Beach, LLC +// sale : Dog Beach, LLC +// https://www.iana.org/domains/root/db/sale.html sale -// salon : 2014-12-11 Binky Moon, LLC +// salon : Binky Moon, LLC +// https://www.iana.org/domains/root/db/salon.html salon -// samsclub : 2015-07-31 Wal-Mart Stores, Inc. +// samsclub : Wal-Mart Stores, Inc. +// https://www.iana.org/domains/root/db/samsclub.html samsclub -// samsung : 2014-04-03 SAMSUNG SDS CO., LTD +// samsung : SAMSUNG SDS CO., LTD +// https://www.iana.org/domains/root/db/samsung.html samsung -// sandvik : 2014-11-13 Sandvik AB +// sandvik : Sandvik AB +// https://www.iana.org/domains/root/db/sandvik.html sandvik -// sandvikcoromant : 2014-11-07 Sandvik AB +// sandvikcoromant : Sandvik AB +// https://www.iana.org/domains/root/db/sandvikcoromant.html sandvikcoromant -// sanofi : 2014-10-09 Sanofi +// sanofi : Sanofi +// https://www.iana.org/domains/root/db/sanofi.html sanofi -// sap : 2014-03-27 SAP AG +// sap : SAP AG +// https://www.iana.org/domains/root/db/sap.html sap -// sarl : 2014-07-03 Binky Moon, LLC +// sarl : Binky Moon, LLC +// https://www.iana.org/domains/root/db/sarl.html sarl -// sas : 2015-04-02 Research IP LLC +// sas : Research IP LLC +// https://www.iana.org/domains/root/db/sas.html sas -// save : 2015-06-25 Amazon Registry Services, Inc. +// save : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/save.html save -// saxo : 2014-10-31 Saxo Bank A/S +// saxo : Saxo Bank A/S +// https://www.iana.org/domains/root/db/saxo.html saxo -// sbi : 2015-03-12 STATE BANK OF INDIA +// sbi : STATE BANK OF INDIA +// https://www.iana.org/domains/root/db/sbi.html sbi -// sbs : 2014-11-07 ShortDot SA +// sbs : ShortDot SA +// https://www.iana.org/domains/root/db/sbs.html sbs -// sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ) +// sca : SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ) +// https://www.iana.org/domains/root/db/sca.html sca -// scb : 2014-02-20 The Siam Commercial Bank Public Company Limited ("SCB") +// scb : The Siam Commercial Bank Public Company Limited ("SCB") +// https://www.iana.org/domains/root/db/scb.html scb -// schaeffler : 2015-08-06 Schaeffler Technologies AG & Co. KG +// schaeffler : Schaeffler Technologies AG & Co. KG +// https://www.iana.org/domains/root/db/schaeffler.html schaeffler -// schmidt : 2014-04-03 SCHMIDT GROUPE S.A.S. +// schmidt : SCHMIDT GROUPE S.A.S. +// https://www.iana.org/domains/root/db/schmidt.html schmidt -// scholarships : 2014-04-24 Scholarships.com, LLC +// scholarships : Scholarships.com, LLC +// https://www.iana.org/domains/root/db/scholarships.html scholarships -// school : 2014-12-18 Binky Moon, LLC +// school : Binky Moon, LLC +// https://www.iana.org/domains/root/db/school.html school -// schule : 2014-03-06 Binky Moon, LLC +// schule : Binky Moon, LLC +// https://www.iana.org/domains/root/db/schule.html schule -// schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG +// schwarz : Schwarz Domains und Services GmbH & Co. KG +// https://www.iana.org/domains/root/db/schwarz.html schwarz -// science : 2014-09-11 dot Science Limited +// science : dot Science Limited +// https://www.iana.org/domains/root/db/science.html science -// scot : 2014-01-23 Dot Scot Registry Limited +// scot : Dot Scot Registry Limited +// https://www.iana.org/domains/root/db/scot.html scot -// search : 2016-06-09 Charleston Road Registry Inc. +// search : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/search.html search -// seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal) +// seat : SEAT, S.A. (Sociedad Unipersonal) +// https://www.iana.org/domains/root/db/seat.html seat -// secure : 2015-08-27 Amazon Registry Services, Inc. +// secure : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/secure.html secure -// security : 2015-05-14 XYZ.COM LLC +// security : XYZ.COM LLC +// https://www.iana.org/domains/root/db/security.html security -// seek : 2014-12-04 Seek Limited +// seek : Seek Limited +// https://www.iana.org/domains/root/db/seek.html seek -// select : 2015-10-08 Registry Services, LLC +// select : Registry Services, LLC +// https://www.iana.org/domains/root/db/select.html select -// sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A. +// sener : Sener Ingeniería y Sistemas, S.A. +// https://www.iana.org/domains/root/db/sener.html sener -// services : 2014-02-27 Binky Moon, LLC +// services : Binky Moon, LLC +// https://www.iana.org/domains/root/db/services.html services -// seven : 2015-08-06 Seven West Media Ltd +// seven : Seven West Media Ltd +// https://www.iana.org/domains/root/db/seven.html seven -// sew : 2014-07-17 SEW-EURODRIVE GmbH & Co KG +// sew : SEW-EURODRIVE GmbH & Co KG +// https://www.iana.org/domains/root/db/sew.html sew -// sex : 2014-11-13 ICM Registry SX LLC +// sex : ICM Registry SX LLC +// https://www.iana.org/domains/root/db/sex.html sex -// sexy : 2013-09-11 Internet Naming Company LLC +// sexy : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/sexy.html sexy -// sfr : 2015-08-13 Societe Francaise du Radiotelephone - SFR +// sfr : Societe Francaise du Radiotelephone - SFR +// https://www.iana.org/domains/root/db/sfr.html sfr -// shangrila : 2015-09-03 Shangri‐La International Hotel Management Limited +// shangrila : Shangri‐La International Hotel Management Limited +// https://www.iana.org/domains/root/db/shangrila.html shangrila -// sharp : 2014-05-01 Sharp Corporation +// sharp : Sharp Corporation +// https://www.iana.org/domains/root/db/sharp.html sharp -// shaw : 2015-04-23 Shaw Cablesystems G.P. +// shaw : Shaw Cablesystems G.P. +// https://www.iana.org/domains/root/db/shaw.html shaw -// shell : 2015-07-30 Shell Information Technology International Inc +// shell : Shell Information Technology International Inc +// https://www.iana.org/domains/root/db/shell.html shell -// shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// shia : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// https://www.iana.org/domains/root/db/shia.html shia -// shiksha : 2013-11-14 Identity Digital Limited +// shiksha : Identity Digital Limited +// https://www.iana.org/domains/root/db/shiksha.html shiksha -// shoes : 2013-10-02 Binky Moon, LLC +// shoes : Binky Moon, LLC +// https://www.iana.org/domains/root/db/shoes.html shoes -// shop : 2016-04-08 GMO Registry, Inc. +// shop : GMO Registry, Inc. +// https://www.iana.org/domains/root/db/shop.html shop -// shopping : 2016-03-31 Binky Moon, LLC +// shopping : Binky Moon, LLC +// https://www.iana.org/domains/root/db/shopping.html shopping -// shouji : 2015-01-08 Beijing Qihu Keji Co., Ltd. +// shouji : Beijing Qihu Keji Co., Ltd. +// https://www.iana.org/domains/root/db/shouji.html shouji -// show : 2015-03-05 Binky Moon, LLC +// show : Binky Moon, LLC +// https://www.iana.org/domains/root/db/show.html show -// showtime : 2015-08-06 CBS Domains Inc. -showtime - -// silk : 2015-06-25 Amazon Registry Services, Inc. +// silk : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/silk.html silk -// sina : 2015-03-12 Sina Corporation +// sina : Sina Corporation +// https://www.iana.org/domains/root/db/sina.html sina -// singles : 2013-08-27 Binky Moon, LLC +// singles : Binky Moon, LLC +// https://www.iana.org/domains/root/db/singles.html singles -// site : 2015-01-15 Radix FZC +// site : Radix FZC DMCC +// https://www.iana.org/domains/root/db/site.html site -// ski : 2015-04-09 Identity Digital Limited +// ski : Identity Digital Limited +// https://www.iana.org/domains/root/db/ski.html ski -// skin : 2015-01-15 XYZ.COM LLC +// skin : XYZ.COM LLC +// https://www.iana.org/domains/root/db/skin.html skin -// sky : 2014-06-19 Sky International AG +// sky : Sky International AG +// https://www.iana.org/domains/root/db/sky.html sky -// skype : 2014-12-18 Microsoft Corporation +// skype : Microsoft Corporation +// https://www.iana.org/domains/root/db/skype.html skype -// sling : 2015-07-30 DISH Technologies L.L.C. +// sling : DISH Technologies L.L.C. +// https://www.iana.org/domains/root/db/sling.html sling -// smart : 2015-07-09 Smart Communications, Inc. (SMART) +// smart : Smart Communications, Inc. (SMART) +// https://www.iana.org/domains/root/db/smart.html smart -// smile : 2014-12-18 Amazon Registry Services, Inc. +// smile : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/smile.html smile -// sncf : 2015-02-19 Société Nationale SNCF +// sncf : Société Nationale SNCF +// https://www.iana.org/domains/root/db/sncf.html sncf -// soccer : 2015-03-26 Binky Moon, LLC +// soccer : Binky Moon, LLC +// https://www.iana.org/domains/root/db/soccer.html soccer -// social : 2013-11-07 Dog Beach, LLC +// social : Dog Beach, LLC +// https://www.iana.org/domains/root/db/social.html social -// softbank : 2015-07-02 SoftBank Group Corp. +// softbank : SoftBank Group Corp. +// https://www.iana.org/domains/root/db/softbank.html softbank -// software : 2014-03-20 Dog Beach, LLC +// software : Dog Beach, LLC +// https://www.iana.org/domains/root/db/software.html software -// sohu : 2013-12-19 Sohu.com Limited +// sohu : Sohu.com Limited +// https://www.iana.org/domains/root/db/sohu.html sohu -// solar : 2013-11-07 Binky Moon, LLC +// solar : Binky Moon, LLC +// https://www.iana.org/domains/root/db/solar.html solar -// solutions : 2013-11-07 Binky Moon, LLC +// solutions : Binky Moon, LLC +// https://www.iana.org/domains/root/db/solutions.html solutions -// song : 2015-02-26 Amazon Registry Services, Inc. +// song : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/song.html song -// sony : 2015-01-08 Sony Corporation +// sony : Sony Corporation +// https://www.iana.org/domains/root/db/sony.html sony -// soy : 2014-01-23 Charleston Road Registry Inc. +// soy : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/soy.html soy -// spa : 2019-09-19 Asia Spa and Wellness Promotion Council Limited +// spa : Asia Spa and Wellness Promotion Council Limited +// https://www.iana.org/domains/root/db/spa.html spa -// space : 2014-04-03 Radix FZC +// space : Radix FZC DMCC +// https://www.iana.org/domains/root/db/space.html space -// sport : 2017-11-16 Global Association of International Sports Federations (GAISF) +// sport : SportAccord +// https://www.iana.org/domains/root/db/sport.html sport -// spot : 2015-02-26 Amazon Registry Services, Inc. +// spot : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/spot.html spot -// srl : 2015-05-07 InterNetX, Corp +// srl : InterNetX, Corp +// https://www.iana.org/domains/root/db/srl.html srl -// stada : 2014-11-13 STADA Arzneimittel AG +// stada : STADA Arzneimittel AG +// https://www.iana.org/domains/root/db/stada.html stada -// staples : 2015-07-30 Staples, Inc. +// staples : Staples, Inc. +// https://www.iana.org/domains/root/db/staples.html staples -// star : 2015-01-08 Star India Private Limited +// star : Star India Private Limited +// https://www.iana.org/domains/root/db/star.html star -// statebank : 2015-03-12 STATE BANK OF INDIA +// statebank : STATE BANK OF INDIA +// https://www.iana.org/domains/root/db/statebank.html statebank -// statefarm : 2015-07-30 State Farm Mutual Automobile Insurance Company +// statefarm : State Farm Mutual Automobile Insurance Company +// https://www.iana.org/domains/root/db/statefarm.html statefarm -// stc : 2014-10-09 Saudi Telecom Company +// stc : Saudi Telecom Company +// https://www.iana.org/domains/root/db/stc.html stc -// stcgroup : 2014-10-09 Saudi Telecom Company +// stcgroup : Saudi Telecom Company +// https://www.iana.org/domains/root/db/stcgroup.html stcgroup -// stockholm : 2014-12-18 Stockholms kommun +// stockholm : Stockholms kommun +// https://www.iana.org/domains/root/db/stockholm.html stockholm -// storage : 2014-12-22 XYZ.COM LLC +// storage : XYZ.COM LLC +// https://www.iana.org/domains/root/db/storage.html storage -// store : 2015-04-09 Radix FZC +// store : Radix FZC DMCC +// https://www.iana.org/domains/root/db/store.html store -// stream : 2016-01-08 dot Stream Limited +// stream : dot Stream Limited +// https://www.iana.org/domains/root/db/stream.html stream -// studio : 2015-02-11 Dog Beach, LLC +// studio : Dog Beach, LLC +// https://www.iana.org/domains/root/db/studio.html studio -// study : 2014-12-11 Registry Services, LLC +// study : Registry Services, LLC +// https://www.iana.org/domains/root/db/study.html study -// style : 2014-12-04 Binky Moon, LLC +// style : Binky Moon, LLC +// https://www.iana.org/domains/root/db/style.html style -// sucks : 2014-12-22 Vox Populi Registry Ltd. +// sucks : Vox Populi Registry Ltd. +// https://www.iana.org/domains/root/db/sucks.html sucks -// supplies : 2013-12-19 Binky Moon, LLC +// supplies : Binky Moon, LLC +// https://www.iana.org/domains/root/db/supplies.html supplies -// supply : 2013-12-19 Binky Moon, LLC +// supply : Binky Moon, LLC +// https://www.iana.org/domains/root/db/supply.html supply -// support : 2013-10-24 Binky Moon, LLC +// support : Binky Moon, LLC +// https://www.iana.org/domains/root/db/support.html support -// surf : 2014-01-09 Registry Services, LLC +// surf : Registry Services, LLC +// https://www.iana.org/domains/root/db/surf.html surf -// surgery : 2014-03-20 Binky Moon, LLC +// surgery : Binky Moon, LLC +// https://www.iana.org/domains/root/db/surgery.html surgery -// suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION +// suzuki : SUZUKI MOTOR CORPORATION +// https://www.iana.org/domains/root/db/suzuki.html suzuki -// swatch : 2015-01-08 The Swatch Group Ltd +// swatch : The Swatch Group Ltd +// https://www.iana.org/domains/root/db/swatch.html swatch -// swiss : 2014-10-16 Swiss Confederation +// swiss : Swiss Confederation +// https://www.iana.org/domains/root/db/swiss.html swiss -// sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet +// sydney : State of New South Wales, Department of Premier and Cabinet +// https://www.iana.org/domains/root/db/sydney.html sydney -// systems : 2013-11-07 Binky Moon, LLC +// systems : Binky Moon, LLC +// https://www.iana.org/domains/root/db/systems.html systems -// tab : 2014-12-04 Tabcorp Holdings Limited +// tab : Tabcorp Holdings Limited +// https://www.iana.org/domains/root/db/tab.html tab -// taipei : 2014-07-10 Taipei City Government +// taipei : Taipei City Government +// https://www.iana.org/domains/root/db/taipei.html taipei -// talk : 2015-04-09 Amazon Registry Services, Inc. +// talk : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/talk.html talk -// taobao : 2015-01-15 Alibaba Group Holding Limited +// taobao : Alibaba Group Holding Limited +// https://www.iana.org/domains/root/db/taobao.html taobao -// target : 2015-07-31 Target Domain Holdings, LLC +// target : Target Domain Holdings, LLC +// https://www.iana.org/domains/root/db/target.html target -// tatamotors : 2015-03-12 Tata Motors Ltd +// tatamotors : Tata Motors Ltd +// https://www.iana.org/domains/root/db/tatamotors.html tatamotors -// tatar : 2014-04-24 Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" +// tatar : Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" +// https://www.iana.org/domains/root/db/tatar.html tatar -// tattoo : 2013-08-30 Top Level Design, LLC +// tattoo : Registry Services, LLC +// https://www.iana.org/domains/root/db/tattoo.html tattoo -// tax : 2014-03-20 Binky Moon, LLC +// tax : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tax.html tax -// taxi : 2015-03-19 Binky Moon, LLC +// taxi : Binky Moon, LLC +// https://www.iana.org/domains/root/db/taxi.html taxi -// tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// tci : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// https://www.iana.org/domains/root/db/tci.html tci -// tdk : 2015-06-11 TDK Corporation +// tdk : TDK Corporation +// https://www.iana.org/domains/root/db/tdk.html tdk -// team : 2015-03-05 Binky Moon, LLC +// team : Binky Moon, LLC +// https://www.iana.org/domains/root/db/team.html team -// tech : 2015-01-30 Radix FZC +// tech : Radix FZC DMCC +// https://www.iana.org/domains/root/db/tech.html tech -// technology : 2013-09-13 Binky Moon, LLC +// technology : Binky Moon, LLC +// https://www.iana.org/domains/root/db/technology.html technology -// temasek : 2014-08-07 Temasek Holdings (Private) Limited +// temasek : Temasek Holdings (Private) Limited +// https://www.iana.org/domains/root/db/temasek.html temasek -// tennis : 2014-12-04 Binky Moon, LLC +// tennis : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tennis.html tennis -// teva : 2015-07-02 Teva Pharmaceutical Industries Limited +// teva : Teva Pharmaceutical Industries Limited +// https://www.iana.org/domains/root/db/teva.html teva -// thd : 2015-04-02 Home Depot Product Authority, LLC +// thd : Home Depot Product Authority, LLC +// https://www.iana.org/domains/root/db/thd.html thd -// theater : 2015-03-19 Binky Moon, LLC +// theater : Binky Moon, LLC +// https://www.iana.org/domains/root/db/theater.html theater -// theatre : 2015-05-07 XYZ.COM LLC +// theatre : XYZ.COM LLC +// https://www.iana.org/domains/root/db/theatre.html theatre -// tiaa : 2015-07-23 Teachers Insurance and Annuity Association of America +// tiaa : Teachers Insurance and Annuity Association of America +// https://www.iana.org/domains/root/db/tiaa.html tiaa -// tickets : 2015-02-05 XYZ.COM LLC +// tickets : XYZ.COM LLC +// https://www.iana.org/domains/root/db/tickets.html tickets -// tienda : 2013-11-14 Binky Moon, LLC +// tienda : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tienda.html tienda -// tiffany : 2015-01-30 Tiffany and Company -tiffany - -// tips : 2013-09-20 Binky Moon, LLC +// tips : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tips.html tips -// tires : 2014-11-07 Binky Moon, LLC +// tires : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tires.html tires -// tirol : 2014-04-24 punkt Tirol GmbH +// tirol : punkt Tirol GmbH +// https://www.iana.org/domains/root/db/tirol.html tirol -// tjmaxx : 2015-07-16 The TJX Companies, Inc. +// tjmaxx : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/tjmaxx.html tjmaxx -// tjx : 2015-07-16 The TJX Companies, Inc. +// tjx : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/tjx.html tjx -// tkmaxx : 2015-07-16 The TJX Companies, Inc. +// tkmaxx : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/tkmaxx.html tkmaxx -// tmall : 2015-01-15 Alibaba Group Holding Limited +// tmall : Alibaba Group Holding Limited +// https://www.iana.org/domains/root/db/tmall.html tmall -// today : 2013-09-20 Binky Moon, LLC +// today : Binky Moon, LLC +// https://www.iana.org/domains/root/db/today.html today -// tokyo : 2013-11-13 GMO Registry, Inc. +// tokyo : GMO Registry, Inc. +// https://www.iana.org/domains/root/db/tokyo.html tokyo -// tools : 2013-11-21 Binky Moon, LLC +// tools : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tools.html tools -// top : 2014-03-20 .TOP Registry +// top : .TOP Registry +// https://www.iana.org/domains/root/db/top.html top -// toray : 2014-12-18 Toray Industries, Inc. +// toray : Toray Industries, Inc. +// https://www.iana.org/domains/root/db/toray.html toray -// toshiba : 2014-04-10 TOSHIBA Corporation +// toshiba : TOSHIBA Corporation +// https://www.iana.org/domains/root/db/toshiba.html toshiba -// total : 2015-08-06 TotalEnergies SE +// total : TotalEnergies SE +// https://www.iana.org/domains/root/db/total.html total -// tours : 2015-01-22 Binky Moon, LLC +// tours : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tours.html tours -// town : 2014-03-06 Binky Moon, LLC +// town : Binky Moon, LLC +// https://www.iana.org/domains/root/db/town.html town -// toyota : 2015-04-23 TOYOTA MOTOR CORPORATION +// toyota : TOYOTA MOTOR CORPORATION +// https://www.iana.org/domains/root/db/toyota.html toyota -// toys : 2014-03-06 Binky Moon, LLC +// toys : Binky Moon, LLC +// https://www.iana.org/domains/root/db/toys.html toys -// trade : 2014-01-23 Elite Registry Limited +// trade : Elite Registry Limited +// https://www.iana.org/domains/root/db/trade.html trade -// trading : 2014-12-11 Dog Beach, LLC +// trading : Dog Beach, LLC +// https://www.iana.org/domains/root/db/trading.html trading -// training : 2013-11-07 Binky Moon, LLC +// training : Binky Moon, LLC +// https://www.iana.org/domains/root/db/training.html training -// travel : 2015-10-09 Dog Beach, LLC +// travel : Dog Beach, LLC +// https://www.iana.org/domains/root/db/travel.html travel -// travelchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. -travelchannel - -// travelers : 2015-03-26 Travelers TLD, LLC +// travelers : Travelers TLD, LLC +// https://www.iana.org/domains/root/db/travelers.html travelers -// travelersinsurance : 2015-03-26 Travelers TLD, LLC +// travelersinsurance : Travelers TLD, LLC +// https://www.iana.org/domains/root/db/travelersinsurance.html travelersinsurance -// trust : 2014-10-16 Internet Naming Company LLC +// trust : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/trust.html trust -// trv : 2015-03-26 Travelers TLD, LLC +// trv : Travelers TLD, LLC +// https://www.iana.org/domains/root/db/trv.html trv -// tube : 2015-06-11 Latin American Telecom LLC +// tube : Latin American Telecom LLC +// https://www.iana.org/domains/root/db/tube.html tube -// tui : 2014-07-03 TUI AG +// tui : TUI AG +// https://www.iana.org/domains/root/db/tui.html tui -// tunes : 2015-02-26 Amazon Registry Services, Inc. +// tunes : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/tunes.html tunes -// tushu : 2014-12-18 Amazon Registry Services, Inc. +// tushu : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/tushu.html tushu -// tvs : 2015-02-19 T V SUNDRAM IYENGAR & SONS LIMITED +// tvs : T V SUNDRAM IYENGAR & SONS LIMITED +// https://www.iana.org/domains/root/db/tvs.html tvs -// ubank : 2015-08-20 National Australia Bank Limited +// ubank : National Australia Bank Limited +// https://www.iana.org/domains/root/db/ubank.html ubank -// ubs : 2014-12-11 UBS AG +// ubs : UBS AG +// https://www.iana.org/domains/root/db/ubs.html ubs -// unicom : 2015-10-15 China United Network Communications Corporation Limited +// unicom : China United Network Communications Corporation Limited +// https://www.iana.org/domains/root/db/unicom.html unicom -// university : 2014-03-06 Binky Moon, LLC +// university : Binky Moon, LLC +// https://www.iana.org/domains/root/db/university.html university -// uno : 2013-09-11 Radix FZC +// uno : Radix FZC DMCC +// https://www.iana.org/domains/root/db/uno.html uno -// uol : 2014-05-01 UBN INTERNET LTDA. +// uol : UBN INTERNET LTDA. +// https://www.iana.org/domains/root/db/uol.html uol -// ups : 2015-06-25 UPS Market Driver, Inc. +// ups : UPS Market Driver, Inc. +// https://www.iana.org/domains/root/db/ups.html ups -// vacations : 2013-12-05 Binky Moon, LLC +// vacations : Binky Moon, LLC +// https://www.iana.org/domains/root/db/vacations.html vacations -// vana : 2014-12-11 Lifestyle Domain Holdings, Inc. +// vana : Lifestyle Domain Holdings, Inc. +// https://www.iana.org/domains/root/db/vana.html vana -// vanguard : 2015-09-03 The Vanguard Group, Inc. +// vanguard : The Vanguard Group, Inc. +// https://www.iana.org/domains/root/db/vanguard.html vanguard -// vegas : 2014-01-16 Dot Vegas, Inc. +// vegas : Dot Vegas, Inc. +// https://www.iana.org/domains/root/db/vegas.html vegas -// ventures : 2013-08-27 Binky Moon, LLC +// ventures : Binky Moon, LLC +// https://www.iana.org/domains/root/db/ventures.html ventures -// verisign : 2015-08-13 VeriSign, Inc. +// verisign : VeriSign, Inc. +// https://www.iana.org/domains/root/db/verisign.html verisign -// versicherung : 2014-03-20 tldbox GmbH +// versicherung : tldbox GmbH +// https://www.iana.org/domains/root/db/versicherung.html versicherung -// vet : 2014-03-06 Dog Beach, LLC +// vet : Dog Beach, LLC +// https://www.iana.org/domains/root/db/vet.html vet -// viajes : 2013-10-17 Binky Moon, LLC +// viajes : Binky Moon, LLC +// https://www.iana.org/domains/root/db/viajes.html viajes -// video : 2014-10-16 Dog Beach, LLC +// video : Dog Beach, LLC +// https://www.iana.org/domains/root/db/video.html video -// vig : 2015-05-14 VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe +// vig : VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe +// https://www.iana.org/domains/root/db/vig.html vig -// viking : 2015-04-02 Viking River Cruises (Bermuda) Ltd. +// viking : Viking River Cruises (Bermuda) Ltd. +// https://www.iana.org/domains/root/db/viking.html viking -// villas : 2013-12-05 Binky Moon, LLC +// villas : Binky Moon, LLC +// https://www.iana.org/domains/root/db/villas.html villas -// vin : 2015-06-18 Binky Moon, LLC +// vin : Binky Moon, LLC +// https://www.iana.org/domains/root/db/vin.html vin -// vip : 2015-01-22 Registry Services, LLC +// vip : Registry Services, LLC +// https://www.iana.org/domains/root/db/vip.html vip -// virgin : 2014-09-25 Virgin Enterprises Limited +// virgin : Virgin Enterprises Limited +// https://www.iana.org/domains/root/db/virgin.html virgin -// visa : 2015-07-30 Visa Worldwide Pte. Limited +// visa : Visa Worldwide Pte. Limited +// https://www.iana.org/domains/root/db/visa.html visa -// vision : 2013-12-05 Binky Moon, LLC +// vision : Binky Moon, LLC +// https://www.iana.org/domains/root/db/vision.html vision -// viva : 2014-11-07 Saudi Telecom Company +// viva : Saudi Telecom Company +// https://www.iana.org/domains/root/db/viva.html viva -// vivo : 2015-07-31 Telefonica Brasil S.A. +// vivo : Telefonica Brasil S.A. +// https://www.iana.org/domains/root/db/vivo.html vivo -// vlaanderen : 2014-02-06 DNS.be vzw +// vlaanderen : DNS.be vzw +// https://www.iana.org/domains/root/db/vlaanderen.html vlaanderen -// vodka : 2013-12-19 Registry Services, LLC +// vodka : Registry Services, LLC +// https://www.iana.org/domains/root/db/vodka.html vodka -// volkswagen : 2015-05-14 Volkswagen Group of America Inc. +// volkswagen : Volkswagen Group of America Inc. +// https://www.iana.org/domains/root/db/volkswagen.html volkswagen -// volvo : 2015-11-12 Volvo Holding Sverige Aktiebolag +// volvo : Volvo Holding Sverige Aktiebolag +// https://www.iana.org/domains/root/db/volvo.html volvo -// vote : 2013-11-21 Monolith Registry LLC +// vote : Monolith Registry LLC +// https://www.iana.org/domains/root/db/vote.html vote -// voting : 2013-11-13 Valuetainment Corp. +// voting : Valuetainment Corp. +// https://www.iana.org/domains/root/db/voting.html voting -// voto : 2013-11-21 Monolith Registry LLC +// voto : Monolith Registry LLC +// https://www.iana.org/domains/root/db/voto.html voto -// voyage : 2013-08-27 Binky Moon, LLC +// voyage : Binky Moon, LLC +// https://www.iana.org/domains/root/db/voyage.html voyage -// vuelos : 2015-03-05 Travel Reservations SRL -vuelos - -// wales : 2014-05-08 Nominet UK +// wales : Nominet UK +// https://www.iana.org/domains/root/db/wales.html wales -// walmart : 2015-07-31 Wal-Mart Stores, Inc. +// walmart : Wal-Mart Stores, Inc. +// https://www.iana.org/domains/root/db/walmart.html walmart -// walter : 2014-11-13 Sandvik AB +// walter : Sandvik AB +// https://www.iana.org/domains/root/db/walter.html walter -// wang : 2013-10-24 Zodiac Wang Limited +// wang : Zodiac Wang Limited +// https://www.iana.org/domains/root/db/wang.html wang -// wanggou : 2014-12-18 Amazon Registry Services, Inc. +// wanggou : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/wanggou.html wanggou -// watch : 2013-11-14 Binky Moon, LLC +// watch : Binky Moon, LLC +// https://www.iana.org/domains/root/db/watch.html watch -// watches : 2014-12-22 Identity Digital Limited +// watches : Identity Digital Limited +// https://www.iana.org/domains/root/db/watches.html watches -// weather : 2015-01-08 International Business Machines Corporation +// weather : International Business Machines Corporation +// https://www.iana.org/domains/root/db/weather.html weather -// weatherchannel : 2015-03-12 International Business Machines Corporation +// weatherchannel : International Business Machines Corporation +// https://www.iana.org/domains/root/db/weatherchannel.html weatherchannel -// webcam : 2014-01-23 dot Webcam Limited +// webcam : dot Webcam Limited +// https://www.iana.org/domains/root/db/webcam.html webcam -// weber : 2015-06-04 Saint-Gobain Weber SA +// weber : Saint-Gobain Weber SA +// https://www.iana.org/domains/root/db/weber.html weber -// website : 2014-04-03 Radix FZC +// website : Radix FZC DMCC +// https://www.iana.org/domains/root/db/website.html website -// wedding : 2014-04-24 Registry Services, LLC +// wedding : Registry Services, LLC +// https://www.iana.org/domains/root/db/wedding.html wedding -// weibo : 2015-03-05 Sina Corporation +// weibo : Sina Corporation +// https://www.iana.org/domains/root/db/weibo.html weibo -// weir : 2015-01-29 Weir Group IP Limited +// weir : Weir Group IP Limited +// https://www.iana.org/domains/root/db/weir.html weir -// whoswho : 2014-02-20 Who's Who Registry +// whoswho : Who's Who Registry +// https://www.iana.org/domains/root/db/whoswho.html whoswho -// wien : 2013-10-28 punkt.wien GmbH +// wien : punkt.wien GmbH +// https://www.iana.org/domains/root/db/wien.html wien -// wiki : 2013-11-07 Top Level Design, LLC +// wiki : Registry Services, LLC +// https://www.iana.org/domains/root/db/wiki.html wiki -// williamhill : 2014-03-13 William Hill Organization Limited +// williamhill : William Hill Organization Limited +// https://www.iana.org/domains/root/db/williamhill.html williamhill -// win : 2014-11-20 First Registry Limited +// win : First Registry Limited +// https://www.iana.org/domains/root/db/win.html win -// windows : 2014-12-18 Microsoft Corporation +// windows : Microsoft Corporation +// https://www.iana.org/domains/root/db/windows.html windows -// wine : 2015-06-18 Binky Moon, LLC +// wine : Binky Moon, LLC +// https://www.iana.org/domains/root/db/wine.html wine -// winners : 2015-07-16 The TJX Companies, Inc. +// winners : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/winners.html winners -// wme : 2014-02-13 William Morris Endeavor Entertainment, LLC +// wme : William Morris Endeavor Entertainment, LLC +// https://www.iana.org/domains/root/db/wme.html wme -// wolterskluwer : 2015-08-06 Wolters Kluwer N.V. +// wolterskluwer : Wolters Kluwer N.V. +// https://www.iana.org/domains/root/db/wolterskluwer.html wolterskluwer -// woodside : 2015-07-09 Woodside Petroleum Limited +// woodside : Woodside Petroleum Limited +// https://www.iana.org/domains/root/db/woodside.html woodside -// work : 2013-12-19 Registry Services, LLC +// work : Registry Services, LLC +// https://www.iana.org/domains/root/db/work.html work -// works : 2013-11-14 Binky Moon, LLC +// works : Binky Moon, LLC +// https://www.iana.org/domains/root/db/works.html works -// world : 2014-06-12 Binky Moon, LLC +// world : Binky Moon, LLC +// https://www.iana.org/domains/root/db/world.html world -// wow : 2015-10-08 Amazon Registry Services, Inc. +// wow : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/wow.html wow -// wtc : 2013-12-19 World Trade Centers Association, Inc. +// wtc : World Trade Centers Association, Inc. +// https://www.iana.org/domains/root/db/wtc.html wtc -// wtf : 2014-03-06 Binky Moon, LLC +// wtf : Binky Moon, LLC +// https://www.iana.org/domains/root/db/wtf.html wtf -// xbox : 2014-12-18 Microsoft Corporation +// xbox : Microsoft Corporation +// https://www.iana.org/domains/root/db/xbox.html xbox -// xerox : 2014-10-24 Xerox DNHC LLC +// xerox : Xerox DNHC LLC +// https://www.iana.org/domains/root/db/xerox.html xerox -// xfinity : 2015-07-09 Comcast IP Holdings I, LLC +// xfinity : Comcast IP Holdings I, LLC +// https://www.iana.org/domains/root/db/xfinity.html xfinity -// xihuan : 2015-01-08 Beijing Qihu Keji Co., Ltd. +// xihuan : Beijing Qihu Keji Co., Ltd. +// https://www.iana.org/domains/root/db/xihuan.html xihuan -// xin : 2014-12-11 Elegant Leader Limited +// xin : Elegant Leader Limited +// https://www.iana.org/domains/root/db/xin.html xin -// xn--11b4c3d : 2015-01-15 VeriSign Sarl +// xn--11b4c3d : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--11b4c3d.html कॉम -// xn--1ck2e1b : 2015-02-26 Amazon Registry Services, Inc. +// xn--1ck2e1b : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--1ck2e1b.html セール -// xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd. +// xn--1qqw23a : Guangzhou YU Wei Information Technology Co., Ltd. +// https://www.iana.org/domains/root/db/xn--1qqw23a.html 佛山 -// xn--30rr7y : 2014-06-12 Excellent First Limited +// xn--30rr7y : Excellent First Limited +// https://www.iana.org/domains/root/db/xn--30rr7y.html 慈善 -// xn--3bst00m : 2013-09-13 Eagle Horizon Limited +// xn--3bst00m : Eagle Horizon Limited +// https://www.iana.org/domains/root/db/xn--3bst00m.html 集团 -// xn--3ds443g : 2013-09-08 TLD REGISTRY LIMITED OY +// xn--3ds443g : TLD REGISTRY LIMITED OY +// https://www.iana.org/domains/root/db/xn--3ds443g.html 在线 -// xn--3pxu8k : 2015-01-15 VeriSign Sarl +// xn--3pxu8k : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--3pxu8k.html 点看 -// xn--42c2d9a : 2015-01-15 VeriSign Sarl +// xn--42c2d9a : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--42c2d9a.html คอม -// xn--45q11c : 2013-11-21 Zodiac Gemini Ltd +// xn--45q11c : Zodiac Gemini Ltd +// https://www.iana.org/domains/root/db/xn--45q11c.html 八卦 -// xn--4gbrim : 2013-10-04 Helium TLDs Ltd +// xn--4gbrim : Helium TLDs Ltd +// https://www.iana.org/domains/root/db/xn--4gbrim.html موقع -// xn--55qw42g : 2013-11-08 China Organizational Name Administration Center +// xn--55qw42g : China Organizational Name Administration Center +// https://www.iana.org/domains/root/db/xn--55qw42g.html 公益 -// xn--55qx5d : 2013-11-14 China Internet Network Information Center (CNNIC) +// xn--55qx5d : China Internet Network Information Center (CNNIC) +// https://www.iana.org/domains/root/db/xn--55qx5d.html 公司 -// xn--5su34j936bgsg : 2015-09-03 Shangri‐La International Hotel Management Limited +// xn--5su34j936bgsg : Shangri‐La International Hotel Management Limited +// https://www.iana.org/domains/root/db/xn--5su34j936bgsg.html 香格里拉 -// xn--5tzm5g : 2014-12-22 Global Website TLD Asia Limited +// xn--5tzm5g : Global Website TLD Asia Limited +// https://www.iana.org/domains/root/db/xn--5tzm5g.html 网站 -// xn--6frz82g : 2013-09-23 Identity Digital Limited +// xn--6frz82g : Identity Digital Limited +// https://www.iana.org/domains/root/db/xn--6frz82g.html 移动 -// xn--6qq986b3xl : 2013-09-13 Tycoon Treasure Limited +// xn--6qq986b3xl : Tycoon Treasure Limited +// https://www.iana.org/domains/root/db/xn--6qq986b3xl.html 我爱你 -// xn--80adxhks : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +// xn--80adxhks : Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +// https://www.iana.org/domains/root/db/xn--80adxhks.html москва -// xn--80aqecdr1a : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// xn--80aqecdr1a : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// https://www.iana.org/domains/root/db/xn--80aqecdr1a.html католик -// xn--80asehdb : 2013-07-14 CORE Association +// xn--80asehdb : CORE Association +// https://www.iana.org/domains/root/db/xn--80asehdb.html онлайн -// xn--80aswg : 2013-07-14 CORE Association +// xn--80aswg : CORE Association +// https://www.iana.org/domains/root/db/xn--80aswg.html сайт -// xn--8y0a063a : 2015-03-26 China United Network Communications Corporation Limited +// xn--8y0a063a : China United Network Communications Corporation Limited +// https://www.iana.org/domains/root/db/xn--8y0a063a.html 联通 -// xn--9dbq2a : 2015-01-15 VeriSign Sarl +// xn--9dbq2a : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--9dbq2a.html קום -// xn--9et52u : 2014-06-12 RISE VICTORY LIMITED +// xn--9et52u : RISE VICTORY LIMITED +// https://www.iana.org/domains/root/db/xn--9et52u.html 时尚 -// xn--9krt00a : 2015-03-12 Sina Corporation +// xn--9krt00a : Sina Corporation +// https://www.iana.org/domains/root/db/xn--9krt00a.html 微博 -// xn--b4w605ferd : 2014-08-07 Temasek Holdings (Private) Limited +// xn--b4w605ferd : Temasek Holdings (Private) Limited +// https://www.iana.org/domains/root/db/xn--b4w605ferd.html 淡马锡 -// xn--bck1b9a5dre4c : 2015-02-26 Amazon Registry Services, Inc. +// xn--bck1b9a5dre4c : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--bck1b9a5dre4c.html ファッション -// xn--c1avg : 2013-11-14 Public Interest Registry +// xn--c1avg : Public Interest Registry +// https://www.iana.org/domains/root/db/xn--c1avg.html орг -// xn--c2br7g : 2015-01-15 VeriSign Sarl +// xn--c2br7g : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--c2br7g.html नेट -// xn--cck2b3b : 2015-02-26 Amazon Registry Services, Inc. +// xn--cck2b3b : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--cck2b3b.html ストア -// xn--cckwcxetd : 2019-12-19 Amazon Registry Services, Inc. +// xn--cckwcxetd : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--cckwcxetd.html アマゾン -// xn--cg4bki : 2013-09-27 SAMSUNG SDS CO., LTD +// xn--cg4bki : SAMSUNG SDS CO., LTD +// https://www.iana.org/domains/root/db/xn--cg4bki.html 삼성 -// xn--czr694b : 2014-01-16 Internet DotTrademark Organisation Limited +// xn--czr694b : Internet DotTrademark Organisation Limited +// https://www.iana.org/domains/root/db/xn--czr694b.html 商标 -// xn--czrs0t : 2013-12-19 Binky Moon, LLC +// xn--czrs0t : Binky Moon, LLC +// https://www.iana.org/domains/root/db/xn--czrs0t.html 商店 -// xn--czru2d : 2013-11-21 Zodiac Aquarius Limited +// xn--czru2d : Zodiac Aquarius Limited +// https://www.iana.org/domains/root/db/xn--czru2d.html 商城 -// xn--d1acj3b : 2013-11-20 The Foundation for Network Initiatives “The Smart Internet” +// xn--d1acj3b : The Foundation for Network Initiatives “The Smart Internet” +// https://www.iana.org/domains/root/db/xn--d1acj3b.html дети -// xn--eckvdtc9d : 2014-12-18 Amazon Registry Services, Inc. +// xn--eckvdtc9d : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--eckvdtc9d.html ポイント -// xn--efvy88h : 2014-08-22 Guangzhou YU Wei Information Technology Co., Ltd. +// xn--efvy88h : Guangzhou YU Wei Information Technology Co., Ltd. +// https://www.iana.org/domains/root/db/xn--efvy88h.html 新闻 -// xn--fct429k : 2015-04-09 Amazon Registry Services, Inc. +// xn--fct429k : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--fct429k.html 家電 -// xn--fhbei : 2015-01-15 VeriSign Sarl +// xn--fhbei : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--fhbei.html كوم -// xn--fiq228c5hs : 2013-09-08 TLD REGISTRY LIMITED OY +// xn--fiq228c5hs : TLD REGISTRY LIMITED OY +// https://www.iana.org/domains/root/db/xn--fiq228c5hs.html 中文网 -// xn--fiq64b : 2013-10-14 CITIC Group Corporation +// xn--fiq64b : CITIC Group Corporation +// https://www.iana.org/domains/root/db/xn--fiq64b.html 中信 -// xn--fjq720a : 2014-05-22 Binky Moon, LLC +// xn--fjq720a : Binky Moon, LLC +// https://www.iana.org/domains/root/db/xn--fjq720a.html 娱乐 -// xn--flw351e : 2014-07-31 Charleston Road Registry Inc. +// xn--flw351e : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/xn--flw351e.html 谷歌 -// xn--fzys8d69uvgm : 2015-05-14 PCCW Enterprises Limited +// xn--fzys8d69uvgm : PCCW Enterprises Limited +// https://www.iana.org/domains/root/db/xn--fzys8d69uvgm.html 電訊盈科 -// xn--g2xx48c : 2015-01-30 Nawang Heli(Xiamen) Network Service Co., LTD. +// xn--g2xx48c : Nawang Heli(Xiamen) Network Service Co., LTD. +// https://www.iana.org/domains/root/db/xn--g2xx48c.html 购物 -// xn--gckr3f0f : 2015-02-26 Amazon Registry Services, Inc. +// xn--gckr3f0f : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--gckr3f0f.html クラウド -// xn--gk3at1e : 2015-10-08 Amazon Registry Services, Inc. +// xn--gk3at1e : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--gk3at1e.html 通販 -// xn--hxt814e : 2014-05-15 Zodiac Taurus Limited +// xn--hxt814e : Zodiac Taurus Limited +// https://www.iana.org/domains/root/db/xn--hxt814e.html 网店 -// xn--i1b6b1a6a2e : 2013-11-14 Public Interest Registry +// xn--i1b6b1a6a2e : Public Interest Registry +// https://www.iana.org/domains/root/db/xn--i1b6b1a6a2e.html संगठन -// xn--imr513n : 2014-12-11 Internet DotTrademark Organisation Limited +// xn--imr513n : Internet DotTrademark Organisation Limited +// https://www.iana.org/domains/root/db/xn--imr513n.html 餐厅 -// xn--io0a7i : 2013-11-14 China Internet Network Information Center (CNNIC) +// xn--io0a7i : China Internet Network Information Center (CNNIC) +// https://www.iana.org/domains/root/db/xn--io0a7i.html 网络 -// xn--j1aef : 2015-01-15 VeriSign Sarl +// xn--j1aef : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--j1aef.html ком -// xn--jlq480n2rg : 2019-12-19 Amazon Registry Services, Inc. +// xn--jlq480n2rg : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--jlq480n2rg.html 亚马逊 -// xn--jvr189m : 2015-02-26 Amazon Registry Services, Inc. +// xn--jvr189m : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--jvr189m.html 食品 -// xn--kcrx77d1x4a : 2014-11-07 Koninklijke Philips N.V. +// xn--kcrx77d1x4a : Koninklijke Philips N.V. +// https://www.iana.org/domains/root/db/xn--kcrx77d1x4a.html 飞利浦 -// xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd +// xn--kput3i : Beijing RITT-Net Technology Development Co., Ltd +// https://www.iana.org/domains/root/db/xn--kput3i.html 手机 -// xn--mgba3a3ejt : 2014-11-20 Aramco Services Company +// xn--mgba3a3ejt : Aramco Services Company +// https://www.iana.org/domains/root/db/xn--mgba3a3ejt.html ارامكو -// xn--mgba7c0bbn0a : 2015-05-14 Crescent Holding GmbH +// xn--mgba7c0bbn0a : Competrol (Luxembourg) Sarl +// https://www.iana.org/domains/root/db/xn--mgba7c0bbn0a.html العليان -// xn--mgbaakc7dvf : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat) +// xn--mgbaakc7dvf : Emirates Telecommunications Corporation (trading as Etisalat) +// https://www.iana.org/domains/root/db/xn--mgbaakc7dvf.html اتصالات -// xn--mgbab2bd : 2013-10-31 CORE Association +// xn--mgbab2bd : CORE Association +// https://www.iana.org/domains/root/db/xn--mgbab2bd.html بازار -// xn--mgbca7dzdo : 2015-07-30 Abu Dhabi Systems and Information Centre +// xn--mgbca7dzdo : Abu Dhabi Systems and Information Centre +// https://www.iana.org/domains/root/db/xn--mgbca7dzdo.html ابوظبي -// xn--mgbi4ecexp : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// xn--mgbi4ecexp : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// https://www.iana.org/domains/root/db/xn--mgbi4ecexp.html كاثوليك -// xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// xn--mgbt3dhd : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// https://www.iana.org/domains/root/db/xn--mgbt3dhd.html همراه -// xn--mk1bu44c : 2015-01-15 VeriSign Sarl +// xn--mk1bu44c : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--mk1bu44c.html 닷컴 -// xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd. +// xn--mxtq1m : Net-Chinese Co., Ltd. +// https://www.iana.org/domains/root/db/xn--mxtq1m.html 政府 -// xn--ngbc5azd : 2013-07-13 International Domain Registry Pty. Ltd. +// xn--ngbc5azd : International Domain Registry Pty. Ltd. +// https://www.iana.org/domains/root/db/xn--ngbc5azd.html شبكة -// xn--ngbe9e0a : 2014-12-04 Kuwait Finance House +// xn--ngbe9e0a : Kuwait Finance House +// https://www.iana.org/domains/root/db/xn--ngbe9e0a.html بيتك -// xn--ngbrx : 2015-11-12 League of Arab States +// xn--ngbrx : League of Arab States +// https://www.iana.org/domains/root/db/xn--ngbrx.html عرب -// xn--nqv7f : 2013-11-14 Public Interest Registry +// xn--nqv7f : Public Interest Registry +// https://www.iana.org/domains/root/db/xn--nqv7f.html 机构 -// xn--nqv7fs00ema : 2013-11-14 Public Interest Registry +// xn--nqv7fs00ema : Public Interest Registry +// https://www.iana.org/domains/root/db/xn--nqv7fs00ema.html 组织机构 -// xn--nyqy26a : 2014-11-07 Stable Tone Limited +// xn--nyqy26a : Stable Tone Limited +// https://www.iana.org/domains/root/db/xn--nyqy26a.html 健康 -// xn--otu796d : 2017-08-06 Jiang Yu Liang Cai Technology Company Limited +// xn--otu796d : Jiang Yu Liang Cai Technology Company Limited +// https://www.iana.org/domains/root/db/xn--otu796d.html 招聘 -// xn--p1acf : 2013-12-12 Rusnames Limited +// xn--p1acf : Rusnames Limited +// https://www.iana.org/domains/root/db/xn--p1acf.html рус -// xn--pssy2u : 2015-01-15 VeriSign Sarl +// xn--pssy2u : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--pssy2u.html 大拿 -// xn--q9jyb4c : 2013-09-17 Charleston Road Registry Inc. +// xn--q9jyb4c : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/xn--q9jyb4c.html みんな -// xn--qcka1pmc : 2014-07-31 Charleston Road Registry Inc. +// xn--qcka1pmc : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/xn--qcka1pmc.html グーグル -// xn--rhqv96g : 2013-09-11 Stable Tone Limited +// xn--rhqv96g : Stable Tone Limited +// https://www.iana.org/domains/root/db/xn--rhqv96g.html 世界 -// xn--rovu88b : 2015-02-26 Amazon Registry Services, Inc. +// xn--rovu88b : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--rovu88b.html 書籍 -// xn--ses554g : 2014-01-16 KNET Co., Ltd. +// xn--ses554g : KNET Co., Ltd. +// https://www.iana.org/domains/root/db/xn--ses554g.html 网址 -// xn--t60b56a : 2015-01-15 VeriSign Sarl +// xn--t60b56a : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--t60b56a.html 닷넷 -// xn--tckwe : 2015-01-15 VeriSign Sarl +// xn--tckwe : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--tckwe.html コム -// xn--tiq49xqyj : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// xn--tiq49xqyj : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// https://www.iana.org/domains/root/db/xn--tiq49xqyj.html 天主教 -// xn--unup4y : 2013-07-14 Binky Moon, LLC +// xn--unup4y : Binky Moon, LLC +// https://www.iana.org/domains/root/db/xn--unup4y.html 游戏 -// xn--vermgensberater-ctb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +// xn--vermgensberater-ctb : Deutsche Vermögensberatung Aktiengesellschaft DVAG +// https://www.iana.org/domains/root/db/xn--vermgensberater-ctb.html vermögensberater -// xn--vermgensberatung-pwb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +// xn--vermgensberatung-pwb : Deutsche Vermögensberatung Aktiengesellschaft DVAG +// https://www.iana.org/domains/root/db/xn--vermgensberatung-pwb.html vermögensberatung -// xn--vhquv : 2013-08-27 Binky Moon, LLC +// xn--vhquv : Binky Moon, LLC +// https://www.iana.org/domains/root/db/xn--vhquv.html 企业 -// xn--vuq861b : 2014-10-16 Beijing Tele-info Network Technology Co., Ltd. +// xn--vuq861b : Beijing Tele-info Technology Co., Ltd. +// https://www.iana.org/domains/root/db/xn--vuq861b.html 信息 -// xn--w4r85el8fhu5dnra : 2015-04-30 Kerry Trading Co. Limited +// xn--w4r85el8fhu5dnra : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/xn--w4r85el8fhu5dnra.html 嘉里大酒店 -// xn--w4rs40l : 2015-07-30 Kerry Trading Co. Limited +// xn--w4rs40l : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/xn--w4rs40l.html 嘉里 -// xn--xhq521b : 2013-11-14 Guangzhou YU Wei Information Technology Co., Ltd. +// xn--xhq521b : Guangzhou YU Wei Information Technology Co., Ltd. +// https://www.iana.org/domains/root/db/xn--xhq521b.html 广东 -// xn--zfr164b : 2013-11-08 China Organizational Name Administration Center +// xn--zfr164b : China Organizational Name Administration Center +// https://www.iana.org/domains/root/db/xn--zfr164b.html 政务 -// xyz : 2013-12-05 XYZ.COM LLC +// xyz : XYZ.COM LLC +// https://www.iana.org/domains/root/db/xyz.html xyz -// yachts : 2014-01-09 XYZ.COM LLC +// yachts : XYZ.COM LLC +// https://www.iana.org/domains/root/db/yachts.html yachts -// yahoo : 2015-04-02 Oath Inc. +// yahoo : Oath Inc. +// https://www.iana.org/domains/root/db/yahoo.html yahoo -// yamaxun : 2014-12-18 Amazon Registry Services, Inc. +// yamaxun : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/yamaxun.html yamaxun -// yandex : 2014-04-10 Yandex Europe B.V. +// yandex : Yandex Europe B.V. +// https://www.iana.org/domains/root/db/yandex.html yandex -// yodobashi : 2014-11-20 YODOBASHI CAMERA CO.,LTD. +// yodobashi : YODOBASHI CAMERA CO.,LTD. +// https://www.iana.org/domains/root/db/yodobashi.html yodobashi -// yoga : 2014-05-29 Registry Services, LLC +// yoga : Registry Services, LLC +// https://www.iana.org/domains/root/db/yoga.html yoga -// yokohama : 2013-12-12 GMO Registry, Inc. +// yokohama : GMO Registry, Inc. +// https://www.iana.org/domains/root/db/yokohama.html yokohama -// you : 2015-04-09 Amazon Registry Services, Inc. +// you : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/you.html you -// youtube : 2014-05-01 Charleston Road Registry Inc. +// youtube : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/youtube.html youtube -// yun : 2015-01-08 Beijing Qihu Keji Co., Ltd. +// yun : Beijing Qihu Keji Co., Ltd. +// https://www.iana.org/domains/root/db/yun.html yun -// zappos : 2015-06-25 Amazon Registry Services, Inc. +// zappos : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/zappos.html zappos -// zara : 2014-11-07 Industria de Diseño Textil, S.A. (INDITEX, S.A.) +// zara : Industria de Diseño Textil, S.A. (INDITEX, S.A.) +// https://www.iana.org/domains/root/db/zara.html zara -// zero : 2014-12-18 Amazon Registry Services, Inc. +// zero : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/zero.html zero -// zip : 2014-05-08 Charleston Road Registry Inc. +// zip : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/zip.html zip -// zone : 2013-11-14 Binky Moon, LLC +// zone : Binky Moon, LLC +// https://www.iana.org/domains/root/db/zone.html zone -// zuerich : 2014-11-07 Kanton Zürich (Canton of Zurich) +// zuerich : Kanton Zürich (Canton of Zurich) +// https://www.iana.org/domains/root/db/zuerich.html zuerich @@ -10189,11 +11317,78 @@ myamaze.net // Submitted by AWS Security // Subsections of Amazon/subsidiaries will appear until "concludes" tag +// Amazon API Gateway +// Submitted by AWS Security +// Reference: 4d863337-ff98-4501-a6f2-361eba8445d6 +execute-api.cn-north-1.amazonaws.com.cn +execute-api.cn-northwest-1.amazonaws.com.cn +execute-api.af-south-1.amazonaws.com +execute-api.ap-east-1.amazonaws.com +execute-api.ap-northeast-1.amazonaws.com +execute-api.ap-northeast-2.amazonaws.com +execute-api.ap-northeast-3.amazonaws.com +execute-api.ap-south-1.amazonaws.com +execute-api.ap-south-2.amazonaws.com +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.ca-central-1.amazonaws.com +execute-api.eu-central-1.amazonaws.com +execute-api.eu-central-2.amazonaws.com +execute-api.eu-north-1.amazonaws.com +execute-api.eu-south-1.amazonaws.com +execute-api.eu-south-2.amazonaws.com +execute-api.eu-west-1.amazonaws.com +execute-api.eu-west-2.amazonaws.com +execute-api.eu-west-3.amazonaws.com +execute-api.il-central-1.amazonaws.com +execute-api.me-central-1.amazonaws.com +execute-api.me-south-1.amazonaws.com +execute-api.sa-east-1.amazonaws.com +execute-api.us-east-1.amazonaws.com +execute-api.us-east-2.amazonaws.com +execute-api.us-gov-east-1.amazonaws.com +execute-api.us-gov-west-1.amazonaws.com +execute-api.us-west-1.amazonaws.com +execute-api.us-west-2.amazonaws.com + // Amazon CloudFront // Submitted by Donavan Miller // Reference: 54144616-fd49-4435-8535-19c6a601bdb3 cloudfront.net +// Amazon Cognito +// Submitted by AWS Security +// Reference: 7bee1013-f456-47df-bfe8-03c78d946d61 +auth.af-south-1.amazoncognito.com +auth.ap-northeast-1.amazoncognito.com +auth.ap-northeast-2.amazoncognito.com +auth.ap-northeast-3.amazoncognito.com +auth.ap-south-1.amazoncognito.com +auth.ap-southeast-1.amazoncognito.com +auth.ap-southeast-2.amazoncognito.com +auth.ap-southeast-3.amazoncognito.com +auth.ca-central-1.amazoncognito.com +auth.eu-central-1.amazoncognito.com +auth.eu-north-1.amazoncognito.com +auth.eu-south-1.amazoncognito.com +auth.eu-west-1.amazoncognito.com +auth.eu-west-2.amazoncognito.com +auth.eu-west-3.amazoncognito.com +auth.il-central-1.amazoncognito.com +auth.me-south-1.amazoncognito.com +auth.sa-east-1.amazoncognito.com +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-west-1.amazoncognito.com +auth.us-west-1.amazoncognito.com +auth-fips.us-west-1.amazoncognito.com +auth.us-west-2.amazoncognito.com +auth-fips.us-west-2.amazoncognito.com + // Amazon EC2 // Submitted by Luke Wells // Reference: 4c38fa71-58ac-4768-99e5-689c1767e537 @@ -10202,47 +11397,307 @@ cloudfront.net *.compute.amazonaws.com.cn us-east-1.amazonaws.com +// Amazon EMR +// Submitted by AWS Security +// Reference: 597f3f8e-9283-4e48-8e32-7ee25a1ff6ab +emrappui-prod.cn-north-1.amazonaws.com.cn +emrnotebooks-prod.cn-north-1.amazonaws.com.cn +emrstudio-prod.cn-north-1.amazonaws.com.cn +emrappui-prod.cn-northwest-1.amazonaws.com.cn +emrnotebooks-prod.cn-northwest-1.amazonaws.com.cn +emrstudio-prod.cn-northwest-1.amazonaws.com.cn +emrappui-prod.af-south-1.amazonaws.com +emrnotebooks-prod.af-south-1.amazonaws.com +emrstudio-prod.af-south-1.amazonaws.com +emrappui-prod.ap-east-1.amazonaws.com +emrnotebooks-prod.ap-east-1.amazonaws.com +emrstudio-prod.ap-east-1.amazonaws.com +emrappui-prod.ap-northeast-1.amazonaws.com +emrnotebooks-prod.ap-northeast-1.amazonaws.com +emrstudio-prod.ap-northeast-1.amazonaws.com +emrappui-prod.ap-northeast-2.amazonaws.com +emrnotebooks-prod.ap-northeast-2.amazonaws.com +emrstudio-prod.ap-northeast-2.amazonaws.com +emrappui-prod.ap-northeast-3.amazonaws.com +emrnotebooks-prod.ap-northeast-3.amazonaws.com +emrstudio-prod.ap-northeast-3.amazonaws.com +emrappui-prod.ap-south-1.amazonaws.com +emrnotebooks-prod.ap-south-1.amazonaws.com +emrstudio-prod.ap-south-1.amazonaws.com +emrappui-prod.ap-southeast-1.amazonaws.com +emrnotebooks-prod.ap-southeast-1.amazonaws.com +emrstudio-prod.ap-southeast-1.amazonaws.com +emrappui-prod.ap-southeast-2.amazonaws.com +emrnotebooks-prod.ap-southeast-2.amazonaws.com +emrstudio-prod.ap-southeast-2.amazonaws.com +emrappui-prod.ap-southeast-3.amazonaws.com +emrnotebooks-prod.ap-southeast-3.amazonaws.com +emrstudio-prod.ap-southeast-3.amazonaws.com +emrappui-prod.ca-central-1.amazonaws.com +emrnotebooks-prod.ca-central-1.amazonaws.com +emrstudio-prod.ca-central-1.amazonaws.com +emrappui-prod.eu-central-1.amazonaws.com +emrnotebooks-prod.eu-central-1.amazonaws.com +emrstudio-prod.eu-central-1.amazonaws.com +emrappui-prod.eu-north-1.amazonaws.com +emrnotebooks-prod.eu-north-1.amazonaws.com +emrstudio-prod.eu-north-1.amazonaws.com +emrappui-prod.eu-south-1.amazonaws.com +emrnotebooks-prod.eu-south-1.amazonaws.com +emrstudio-prod.eu-south-1.amazonaws.com +emrappui-prod.eu-west-1.amazonaws.com +emrnotebooks-prod.eu-west-1.amazonaws.com +emrstudio-prod.eu-west-1.amazonaws.com +emrappui-prod.eu-west-2.amazonaws.com +emrnotebooks-prod.eu-west-2.amazonaws.com +emrstudio-prod.eu-west-2.amazonaws.com +emrappui-prod.eu-west-3.amazonaws.com +emrnotebooks-prod.eu-west-3.amazonaws.com +emrstudio-prod.eu-west-3.amazonaws.com +emrappui-prod.me-central-1.amazonaws.com +emrnotebooks-prod.me-central-1.amazonaws.com +emrstudio-prod.me-central-1.amazonaws.com +emrappui-prod.me-south-1.amazonaws.com +emrnotebooks-prod.me-south-1.amazonaws.com +emrstudio-prod.me-south-1.amazonaws.com +emrappui-prod.sa-east-1.amazonaws.com +emrnotebooks-prod.sa-east-1.amazonaws.com +emrstudio-prod.sa-east-1.amazonaws.com +emrappui-prod.us-east-1.amazonaws.com +emrnotebooks-prod.us-east-1.amazonaws.com +emrstudio-prod.us-east-1.amazonaws.com +emrappui-prod.us-east-2.amazonaws.com +emrnotebooks-prod.us-east-2.amazonaws.com +emrstudio-prod.us-east-2.amazonaws.com +emrappui-prod.us-gov-east-1.amazonaws.com +emrnotebooks-prod.us-gov-east-1.amazonaws.com +emrstudio-prod.us-gov-east-1.amazonaws.com +emrappui-prod.us-gov-west-1.amazonaws.com +emrnotebooks-prod.us-gov-west-1.amazonaws.com +emrstudio-prod.us-gov-west-1.amazonaws.com +emrappui-prod.us-west-1.amazonaws.com +emrnotebooks-prod.us-west-1.amazonaws.com +emrstudio-prod.us-west-1.amazonaws.com +emrappui-prod.us-west-2.amazonaws.com +emrnotebooks-prod.us-west-2.amazonaws.com +emrstudio-prod.us-west-2.amazonaws.com + +// Amazon Managed Workflows for Apache Airflow +// Submitted by AWS Security +// Reference: 4ab55e6f-90c0-4a8d-b6a0-52ca5dbb1c2e +*.cn-north-1.airflow.amazonaws.com.cn +*.cn-northwest-1.airflow.amazonaws.com.cn +*.ap-northeast-1.airflow.amazonaws.com +*.ap-northeast-2.airflow.amazonaws.com +*.ap-south-1.airflow.amazonaws.com +*.ap-southeast-1.airflow.amazonaws.com +*.ap-southeast-2.airflow.amazonaws.com +*.ca-central-1.airflow.amazonaws.com +*.eu-central-1.airflow.amazonaws.com +*.eu-north-1.airflow.amazonaws.com +*.eu-west-1.airflow.amazonaws.com +*.eu-west-2.airflow.amazonaws.com +*.eu-west-3.airflow.amazonaws.com +*.sa-east-1.airflow.amazonaws.com +*.us-east-1.airflow.amazonaws.com +*.us-east-2.airflow.amazonaws.com +*.us-west-2.airflow.amazonaws.com + // Amazon S3 -// Submitted by Luke Wells -// Reference: d068bd97-f0a9-4838-a6d8-954b622ef4ae +// Submitted by AWS Security +// Reference: 0e801048-08f2-4064-9cb8-e7373e0b57f4 +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 s3.cn-north-1.amazonaws.com.cn +s3-accesspoint.cn-north-1.amazonaws.com.cn +s3-deprecated.cn-north-1.amazonaws.com.cn +s3-object-lambda.cn-north-1.amazonaws.com.cn +s3-website.cn-north-1.amazonaws.com.cn +s3.dualstack.cn-northwest-1.amazonaws.com.cn +s3-accesspoint.dualstack.cn-northwest-1.amazonaws.com.cn +s3.cn-northwest-1.amazonaws.com.cn +s3-accesspoint.cn-northwest-1.amazonaws.com.cn +s3-object-lambda.cn-northwest-1.amazonaws.com.cn +s3-website.cn-northwest-1.amazonaws.com.cn +s3.dualstack.af-south-1.amazonaws.com +s3-accesspoint.dualstack.af-south-1.amazonaws.com +s3-website.dualstack.af-south-1.amazonaws.com +s3.af-south-1.amazonaws.com +s3-accesspoint.af-south-1.amazonaws.com +s3-object-lambda.af-south-1.amazonaws.com +s3-website.af-south-1.amazonaws.com +s3.dualstack.ap-east-1.amazonaws.com +s3-accesspoint.dualstack.ap-east-1.amazonaws.com +s3.ap-east-1.amazonaws.com +s3-accesspoint.ap-east-1.amazonaws.com +s3-object-lambda.ap-east-1.amazonaws.com +s3-website.ap-east-1.amazonaws.com s3.dualstack.ap-northeast-1.amazonaws.com +s3-accesspoint.dualstack.ap-northeast-1.amazonaws.com +s3-website.dualstack.ap-northeast-1.amazonaws.com +s3.ap-northeast-1.amazonaws.com +s3-accesspoint.ap-northeast-1.amazonaws.com +s3-object-lambda.ap-northeast-1.amazonaws.com +s3-website.ap-northeast-1.amazonaws.com s3.dualstack.ap-northeast-2.amazonaws.com +s3-accesspoint.dualstack.ap-northeast-2.amazonaws.com +s3-website.dualstack.ap-northeast-2.amazonaws.com s3.ap-northeast-2.amazonaws.com +s3-accesspoint.ap-northeast-2.amazonaws.com +s3-object-lambda.ap-northeast-2.amazonaws.com s3-website.ap-northeast-2.amazonaws.com +s3.dualstack.ap-northeast-3.amazonaws.com +s3-accesspoint.dualstack.ap-northeast-3.amazonaws.com +s3-website.dualstack.ap-northeast-3.amazonaws.com +s3.ap-northeast-3.amazonaws.com +s3-accesspoint.ap-northeast-3.amazonaws.com +s3-object-lambda.ap-northeast-3.amazonaws.com +s3-website.ap-northeast-3.amazonaws.com s3.dualstack.ap-south-1.amazonaws.com +s3-accesspoint.dualstack.ap-south-1.amazonaws.com +s3-website.dualstack.ap-south-1.amazonaws.com s3.ap-south-1.amazonaws.com +s3-accesspoint.ap-south-1.amazonaws.com +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.ap-south-2.amazonaws.com +s3-accesspoint.ap-south-2.amazonaws.com +s3-object-lambda.ap-south-2.amazonaws.com +s3-website.ap-south-2.amazonaws.com s3.dualstack.ap-southeast-1.amazonaws.com +s3-accesspoint.dualstack.ap-southeast-1.amazonaws.com +s3-website.dualstack.ap-southeast-1.amazonaws.com +s3.ap-southeast-1.amazonaws.com +s3-accesspoint.ap-southeast-1.amazonaws.com +s3-object-lambda.ap-southeast-1.amazonaws.com +s3-website.ap-southeast-1.amazonaws.com s3.dualstack.ap-southeast-2.amazonaws.com +s3-accesspoint.dualstack.ap-southeast-2.amazonaws.com +s3-website.dualstack.ap-southeast-2.amazonaws.com +s3.ap-southeast-2.amazonaws.com +s3-accesspoint.ap-southeast-2.amazonaws.com +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.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.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.ca-central-1.amazonaws.com +s3-accesspoint.dualstack.ca-central-1.amazonaws.com +s3-accesspoint-fips.dualstack.ca-central-1.amazonaws.com +s3-fips.dualstack.ca-central-1.amazonaws.com +s3-website.dualstack.ca-central-1.amazonaws.com s3.ca-central-1.amazonaws.com +s3-accesspoint.ca-central-1.amazonaws.com +s3-accesspoint-fips.ca-central-1.amazonaws.com +s3-fips.ca-central-1.amazonaws.com +s3-object-lambda.ca-central-1.amazonaws.com s3-website.ca-central-1.amazonaws.com s3.dualstack.eu-central-1.amazonaws.com +s3-accesspoint.dualstack.eu-central-1.amazonaws.com +s3-website.dualstack.eu-central-1.amazonaws.com s3.eu-central-1.amazonaws.com +s3-accesspoint.eu-central-1.amazonaws.com +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.eu-central-2.amazonaws.com +s3-accesspoint.eu-central-2.amazonaws.com +s3-object-lambda.eu-central-2.amazonaws.com +s3-website.eu-central-2.amazonaws.com +s3.dualstack.eu-north-1.amazonaws.com +s3-accesspoint.dualstack.eu-north-1.amazonaws.com +s3.eu-north-1.amazonaws.com +s3-accesspoint.eu-north-1.amazonaws.com +s3-object-lambda.eu-north-1.amazonaws.com +s3-website.eu-north-1.amazonaws.com +s3.dualstack.eu-south-1.amazonaws.com +s3-accesspoint.dualstack.eu-south-1.amazonaws.com +s3-website.dualstack.eu-south-1.amazonaws.com +s3.eu-south-1.amazonaws.com +s3-accesspoint.eu-south-1.amazonaws.com +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.eu-south-2.amazonaws.com +s3-accesspoint.eu-south-2.amazonaws.com +s3-object-lambda.eu-south-2.amazonaws.com +s3-website.eu-south-2.amazonaws.com s3.dualstack.eu-west-1.amazonaws.com +s3-accesspoint.dualstack.eu-west-1.amazonaws.com +s3-website.dualstack.eu-west-1.amazonaws.com +s3.eu-west-1.amazonaws.com +s3-accesspoint.eu-west-1.amazonaws.com +s3-deprecated.eu-west-1.amazonaws.com +s3-object-lambda.eu-west-1.amazonaws.com +s3-website.eu-west-1.amazonaws.com s3.dualstack.eu-west-2.amazonaws.com +s3-accesspoint.dualstack.eu-west-2.amazonaws.com s3.eu-west-2.amazonaws.com +s3-accesspoint.eu-west-2.amazonaws.com +s3-object-lambda.eu-west-2.amazonaws.com s3-website.eu-west-2.amazonaws.com s3.dualstack.eu-west-3.amazonaws.com +s3-accesspoint.dualstack.eu-west-3.amazonaws.com +s3-website.dualstack.eu-west-3.amazonaws.com s3.eu-west-3.amazonaws.com +s3-accesspoint.eu-west-3.amazonaws.com +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.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.me-central-1.amazonaws.com +s3-accesspoint.me-central-1.amazonaws.com +s3-object-lambda.me-central-1.amazonaws.com +s3-website.me-central-1.amazonaws.com +s3.dualstack.me-south-1.amazonaws.com +s3-accesspoint.dualstack.me-south-1.amazonaws.com +s3.me-south-1.amazonaws.com +s3-accesspoint.me-south-1.amazonaws.com +s3-object-lambda.me-south-1.amazonaws.com +s3-website.me-south-1.amazonaws.com s3.amazonaws.com +s3-1.amazonaws.com +s3-ap-east-1.amazonaws.com s3-ap-northeast-1.amazonaws.com s3-ap-northeast-2.amazonaws.com +s3-ap-northeast-3.amazonaws.com s3-ap-south-1.amazonaws.com s3-ap-southeast-1.amazonaws.com s3-ap-southeast-2.amazonaws.com s3-ca-central-1.amazonaws.com s3-eu-central-1.amazonaws.com +s3-eu-north-1.amazonaws.com s3-eu-west-1.amazonaws.com s3-eu-west-2.amazonaws.com s3-eu-west-3.amazonaws.com s3-external-1.amazonaws.com +s3-fips-us-gov-east-1.amazonaws.com s3-fips-us-gov-west-1.amazonaws.com +mrap.accesspoint.s3-global.amazonaws.com +s3-me-south-1.amazonaws.com s3-sa-east-1.amazonaws.com s3-us-east-2.amazonaws.com +s3-us-gov-east-1.amazonaws.com s3-us-gov-west-1.amazonaws.com s3-us-west-1.amazonaws.com s3-us-west-2.amazonaws.com @@ -10252,80 +11707,277 @@ s3-website-ap-southeast-2.amazonaws.com s3-website-eu-west-1.amazonaws.com s3-website-sa-east-1.amazonaws.com s3-website-us-east-1.amazonaws.com +s3-website-us-gov-west-1.amazonaws.com s3-website-us-west-1.amazonaws.com s3-website-us-west-2.amazonaws.com s3.dualstack.sa-east-1.amazonaws.com +s3-accesspoint.dualstack.sa-east-1.amazonaws.com +s3-website.dualstack.sa-east-1.amazonaws.com +s3.sa-east-1.amazonaws.com +s3-accesspoint.sa-east-1.amazonaws.com +s3-object-lambda.sa-east-1.amazonaws.com +s3-website.sa-east-1.amazonaws.com s3.dualstack.us-east-1.amazonaws.com +s3-accesspoint.dualstack.us-east-1.amazonaws.com +s3-accesspoint-fips.dualstack.us-east-1.amazonaws.com +s3-fips.dualstack.us-east-1.amazonaws.com +s3-website.dualstack.us-east-1.amazonaws.com +s3.us-east-1.amazonaws.com +s3-accesspoint.us-east-1.amazonaws.com +s3-accesspoint-fips.us-east-1.amazonaws.com +s3-deprecated.us-east-1.amazonaws.com +s3-fips.us-east-1.amazonaws.com +s3-object-lambda.us-east-1.amazonaws.com +s3-website.us-east-1.amazonaws.com 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.us-east-2.amazonaws.com +s3-accesspoint.us-east-2.amazonaws.com +s3-accesspoint-fips.us-east-2.amazonaws.com +s3-deprecated.us-east-2.amazonaws.com +s3-fips.us-east-2.amazonaws.com +s3-object-lambda.us-east-2.amazonaws.com s3-website.us-east-2.amazonaws.com +s3.dualstack.us-gov-east-1.amazonaws.com +s3-accesspoint.dualstack.us-gov-east-1.amazonaws.com +s3-accesspoint-fips.dualstack.us-gov-east-1.amazonaws.com +s3-fips.dualstack.us-gov-east-1.amazonaws.com +s3.us-gov-east-1.amazonaws.com +s3-accesspoint.us-gov-east-1.amazonaws.com +s3-accesspoint-fips.us-gov-east-1.amazonaws.com +s3-fips.us-gov-east-1.amazonaws.com +s3-object-lambda.us-gov-east-1.amazonaws.com +s3-website.us-gov-east-1.amazonaws.com +s3.dualstack.us-gov-west-1.amazonaws.com +s3-accesspoint.dualstack.us-gov-west-1.amazonaws.com +s3-accesspoint-fips.dualstack.us-gov-west-1.amazonaws.com +s3-fips.dualstack.us-gov-west-1.amazonaws.com +s3.us-gov-west-1.amazonaws.com +s3-accesspoint.us-gov-west-1.amazonaws.com +s3-accesspoint-fips.us-gov-west-1.amazonaws.com +s3-fips.us-gov-west-1.amazonaws.com +s3-object-lambda.us-gov-west-1.amazonaws.com +s3-website.us-gov-west-1.amazonaws.com +s3.dualstack.us-west-1.amazonaws.com +s3-accesspoint.dualstack.us-west-1.amazonaws.com +s3-accesspoint-fips.dualstack.us-west-1.amazonaws.com +s3-fips.dualstack.us-west-1.amazonaws.com +s3-website.dualstack.us-west-1.amazonaws.com +s3.us-west-1.amazonaws.com +s3-accesspoint.us-west-1.amazonaws.com +s3-accesspoint-fips.us-west-1.amazonaws.com +s3-fips.us-west-1.amazonaws.com +s3-object-lambda.us-west-1.amazonaws.com +s3-website.us-west-1.amazonaws.com +s3.dualstack.us-west-2.amazonaws.com +s3-accesspoint.dualstack.us-west-2.amazonaws.com +s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com +s3-fips.dualstack.us-west-2.amazonaws.com +s3-website.dualstack.us-west-2.amazonaws.com +s3.us-west-2.amazonaws.com +s3-accesspoint.us-west-2.amazonaws.com +s3-accesspoint-fips.us-west-2.amazonaws.com +s3-deprecated.us-west-2.amazonaws.com +s3-fips.us-west-2.amazonaws.com +s3-object-lambda.us-west-2.amazonaws.com +s3-website.us-west-2.amazonaws.com + +// Amazon SageMaker Notebook Instances +// Submitted by AWS Security +// Reference: fe8c9e94-5a22-486d-8750-991a3a9b13c6 +notebook.af-south-1.sagemaker.aws +notebook.ap-east-1.sagemaker.aws +notebook.ap-northeast-1.sagemaker.aws +notebook.ap-northeast-2.sagemaker.aws +notebook.ap-northeast-3.sagemaker.aws +notebook.ap-south-1.sagemaker.aws +notebook.ap-south-2.sagemaker.aws +notebook.ap-southeast-1.sagemaker.aws +notebook.ap-southeast-2.sagemaker.aws +notebook.ap-southeast-3.sagemaker.aws +notebook.ap-southeast-4.sagemaker.aws +notebook.ca-central-1.sagemaker.aws +notebook.eu-central-1.sagemaker.aws +notebook.eu-central-2.sagemaker.aws +notebook.eu-north-1.sagemaker.aws +notebook.eu-south-1.sagemaker.aws +notebook.eu-south-2.sagemaker.aws +notebook.eu-west-1.sagemaker.aws +notebook.eu-west-2.sagemaker.aws +notebook.eu-west-3.sagemaker.aws +notebook.il-central-1.sagemaker.aws +notebook.me-central-1.sagemaker.aws +notebook.me-south-1.sagemaker.aws +notebook.sa-east-1.sagemaker.aws +notebook.us-east-1.sagemaker.aws +notebook-fips.us-east-1.sagemaker.aws +notebook.us-east-2.sagemaker.aws +notebook-fips.us-east-2.sagemaker.aws +notebook.us-gov-east-1.sagemaker.aws +notebook-fips.us-gov-east-1.sagemaker.aws +notebook.us-gov-west-1.sagemaker.aws +notebook-fips.us-gov-west-1.sagemaker.aws +notebook.us-west-1.sagemaker.aws +notebook.us-west-2.sagemaker.aws +notebook-fips.us-west-2.sagemaker.aws +notebook.cn-north-1.sagemaker.com.cn +notebook.cn-northwest-1.sagemaker.com.cn + +// Amazon SageMaker Studio +// Submitted by AWS Security +// Reference: 057ee397-6bf8-4f20-b807-d7bc145ac980 +studio.af-south-1.sagemaker.aws +studio.ap-east-1.sagemaker.aws +studio.ap-northeast-1.sagemaker.aws +studio.ap-northeast-2.sagemaker.aws +studio.ap-northeast-3.sagemaker.aws +studio.ap-south-1.sagemaker.aws +studio.ap-southeast-1.sagemaker.aws +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-north-1.sagemaker.aws +studio.eu-south-1.sagemaker.aws +studio.eu-west-1.sagemaker.aws +studio.eu-west-2.sagemaker.aws +studio.eu-west-3.sagemaker.aws +studio.il-central-1.sagemaker.aws +studio.me-central-1.sagemaker.aws +studio.me-south-1.sagemaker.aws +studio.sa-east-1.sagemaker.aws +studio.us-east-1.sagemaker.aws +studio.us-east-2.sagemaker.aws +studio.us-gov-east-1.sagemaker.aws +studio-fips.us-gov-east-1.sagemaker.aws +studio.us-gov-west-1.sagemaker.aws +studio-fips.us-gov-west-1.sagemaker.aws +studio.us-west-1.sagemaker.aws +studio.us-west-2.sagemaker.aws +studio.cn-north-1.sagemaker.com.cn +studio.cn-northwest-1.sagemaker.com.cn + +// Analytics on AWS +// Submitted by AWS Security +// Reference: 955f9f40-a495-4e73-ae85-67b77ac9cadd +analytics-gateway.ap-northeast-1.amazonaws.com +analytics-gateway.ap-northeast-2.amazonaws.com +analytics-gateway.ap-south-1.amazonaws.com +analytics-gateway.ap-southeast-1.amazonaws.com +analytics-gateway.ap-southeast-2.amazonaws.com +analytics-gateway.eu-central-1.amazonaws.com +analytics-gateway.eu-west-1.amazonaws.com +analytics-gateway.us-east-1.amazonaws.com +analytics-gateway.us-east-2.amazonaws.com +analytics-gateway.us-west-2.amazonaws.com + +// AWS Amplify +// Submitted by AWS Security +// Reference: 5ecce854-c033-4fc4-a755-1a9916d9a9bb +*.amplifyapp.com + +// AWS App Runner +// Submitted by AWS Security +// Reference: 6828c008-ba5d-442f-ade5-48da4e7c2316 +*.awsapprunner.com // AWS Cloud9 // Submitted by: AWS Security -// Reference: 2b6dfa9a-3a7f-4367-b2e7-0321e77c0d59 +// Reference: 05c44955-977c-4b57-938a-f2af92733f9f +webview-assets.aws-cloud9.af-south-1.amazonaws.com vfs.cloud9.af-south-1.amazonaws.com webview-assets.cloud9.af-south-1.amazonaws.com +webview-assets.aws-cloud9.ap-east-1.amazonaws.com vfs.cloud9.ap-east-1.amazonaws.com webview-assets.cloud9.ap-east-1.amazonaws.com +webview-assets.aws-cloud9.ap-northeast-1.amazonaws.com vfs.cloud9.ap-northeast-1.amazonaws.com webview-assets.cloud9.ap-northeast-1.amazonaws.com +webview-assets.aws-cloud9.ap-northeast-2.amazonaws.com vfs.cloud9.ap-northeast-2.amazonaws.com webview-assets.cloud9.ap-northeast-2.amazonaws.com +webview-assets.aws-cloud9.ap-northeast-3.amazonaws.com vfs.cloud9.ap-northeast-3.amazonaws.com webview-assets.cloud9.ap-northeast-3.amazonaws.com +webview-assets.aws-cloud9.ap-south-1.amazonaws.com vfs.cloud9.ap-south-1.amazonaws.com webview-assets.cloud9.ap-south-1.amazonaws.com +webview-assets.aws-cloud9.ap-southeast-1.amazonaws.com vfs.cloud9.ap-southeast-1.amazonaws.com webview-assets.cloud9.ap-southeast-1.amazonaws.com +webview-assets.aws-cloud9.ap-southeast-2.amazonaws.com vfs.cloud9.ap-southeast-2.amazonaws.com webview-assets.cloud9.ap-southeast-2.amazonaws.com +webview-assets.aws-cloud9.ca-central-1.amazonaws.com vfs.cloud9.ca-central-1.amazonaws.com webview-assets.cloud9.ca-central-1.amazonaws.com +webview-assets.aws-cloud9.eu-central-1.amazonaws.com vfs.cloud9.eu-central-1.amazonaws.com webview-assets.cloud9.eu-central-1.amazonaws.com +webview-assets.aws-cloud9.eu-north-1.amazonaws.com vfs.cloud9.eu-north-1.amazonaws.com webview-assets.cloud9.eu-north-1.amazonaws.com +webview-assets.aws-cloud9.eu-south-1.amazonaws.com vfs.cloud9.eu-south-1.amazonaws.com webview-assets.cloud9.eu-south-1.amazonaws.com +webview-assets.aws-cloud9.eu-west-1.amazonaws.com vfs.cloud9.eu-west-1.amazonaws.com webview-assets.cloud9.eu-west-1.amazonaws.com +webview-assets.aws-cloud9.eu-west-2.amazonaws.com vfs.cloud9.eu-west-2.amazonaws.com webview-assets.cloud9.eu-west-2.amazonaws.com +webview-assets.aws-cloud9.eu-west-3.amazonaws.com vfs.cloud9.eu-west-3.amazonaws.com webview-assets.cloud9.eu-west-3.amazonaws.com +webview-assets.aws-cloud9.me-south-1.amazonaws.com vfs.cloud9.me-south-1.amazonaws.com webview-assets.cloud9.me-south-1.amazonaws.com +webview-assets.aws-cloud9.sa-east-1.amazonaws.com vfs.cloud9.sa-east-1.amazonaws.com webview-assets.cloud9.sa-east-1.amazonaws.com +webview-assets.aws-cloud9.us-east-1.amazonaws.com vfs.cloud9.us-east-1.amazonaws.com webview-assets.cloud9.us-east-1.amazonaws.com +webview-assets.aws-cloud9.us-east-2.amazonaws.com vfs.cloud9.us-east-2.amazonaws.com webview-assets.cloud9.us-east-2.amazonaws.com +webview-assets.aws-cloud9.us-west-1.amazonaws.com vfs.cloud9.us-west-1.amazonaws.com webview-assets.cloud9.us-west-1.amazonaws.com +webview-assets.aws-cloud9.us-west-2.amazonaws.com vfs.cloud9.us-west-2.amazonaws.com webview-assets.cloud9.us-west-2.amazonaws.com // AWS Elastic Beanstalk -// Submitted by Luke Wells -// Reference: aa202394-43a0-4857-b245-8db04549137e +// Submitted by AWS Security +// Reference: bb5a965c-dec3-4967-aa22-e306ad064797 cn-north-1.eb.amazonaws.com.cn cn-northwest-1.eb.amazonaws.com.cn elasticbeanstalk.com +af-south-1.elasticbeanstalk.com +ap-east-1.elasticbeanstalk.com ap-northeast-1.elasticbeanstalk.com ap-northeast-2.elasticbeanstalk.com ap-northeast-3.elasticbeanstalk.com ap-south-1.elasticbeanstalk.com ap-southeast-1.elasticbeanstalk.com ap-southeast-2.elasticbeanstalk.com +ap-southeast-3.elasticbeanstalk.com ca-central-1.elasticbeanstalk.com eu-central-1.elasticbeanstalk.com +eu-north-1.elasticbeanstalk.com +eu-south-1.elasticbeanstalk.com eu-west-1.elasticbeanstalk.com eu-west-2.elasticbeanstalk.com eu-west-3.elasticbeanstalk.com +il-central-1.elasticbeanstalk.com +me-south-1.elasticbeanstalk.com sa-east-1.elasticbeanstalk.com us-east-1.elasticbeanstalk.com us-east-2.elasticbeanstalk.com +us-gov-east-1.elasticbeanstalk.com us-gov-west-1.elasticbeanstalk.com us-west-1.elasticbeanstalk.com us-west-2.elasticbeanstalk.com @@ -11588,7 +13240,7 @@ freemyip.com // Submitted by Daniel A. Maierhofer wien.funkfeuer.at -// Futureweb OG : http://www.futureweb.at +// Futureweb GmbH : https://www.futureweb.at // Submitted by Andreas Schnederle-Wagner *.futurecms.at *.ex.futurecms.at @@ -12095,7 +13747,6 @@ iobb.net // Submitted by Ihor Kolodyuk mel.cloudlets.com.au cloud.interhostsolutions.be -users.scale.virtualcloud.com.br mycloud.by alp1.ae.flow.ch appengine.flow.ch @@ -12119,9 +13770,7 @@ ch.trendhosting.cloud de.trendhosting.cloud jele.club amscompute.com -clicketcloud.com dopaas.com -hidora.com paas.hosted-by-previder.com rag-cloud.hosteur.com rag-cloud-ch.hosteur.com @@ -12436,6 +14085,10 @@ azurestaticapps.net 1.azurestaticapps.net 2.azurestaticapps.net 3.azurestaticapps.net +4.azurestaticapps.net +5.azurestaticapps.net +6.azurestaticapps.net +7.azurestaticapps.net centralus.azurestaticapps.net eastasia.azurestaticapps.net eastus2.azurestaticapps.net @@ -12516,6 +14169,9 @@ sa.ngrok.io us.ngrok.io ngrok.pizza +// Nicolaus Copernicus University in Torun - MSK TORMAN (https://www.man.torun.pl) +torun.pl + // Nimbus Hosting Ltd. : https://www.nimbushosting.co.uk/ // Submitted by Nicholas Ford nh-serv.co.uk @@ -13230,6 +14886,20 @@ bounty-full.com alpha.bounty-full.com beta.bounty-full.com +// Smallregistry by Promopixel SARL: https://www.smallregistry.net +// Former AFNIC's SLDs +// Submitted by Jérôme Lipowicz +aeroport.fr +avocat.fr +chambagri.fr +chirurgiens-dentistes.fr +experts-comptables.fr +medecin.fr +notaires.fr +pharmacien.fr +port.fr +veterinaire.fr + // Small Technology Foundation : https://small-tech.org // Submitted by Aral Balkan small-web.org @@ -13323,6 +14993,10 @@ myspreadshop.co.uk // Submitted by Jacob Lee api.stdlib.com +// Storipress : https://storipress.com +// Submitted by Benno Liu +storipress.app + // Storj Labs Inc. : https://storj.io/ // Submitted by Philip Hutchins storj.farm @@ -13690,6 +15364,8 @@ js.wpenginepowered.com // Submitted by Shahar Talmi wixsite.com editorx.io +wixstudio.io +wix.run // XenonCloud GbR: https://xenoncloud.net // Submitted by Julian Uphoff diff --git a/src/java.base/share/data/tzdata/VERSION b/src/java.base/share/data/tzdata/VERSION index 66bd061e8bcf9..b138ed7fa78f5 100644 --- a/src/java.base/share/data/tzdata/VERSION +++ b/src/java.base/share/data/tzdata/VERSION @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2023c +tzdata2024a diff --git a/src/java.base/share/data/tzdata/africa b/src/java.base/share/data/tzdata/africa index a73405fdb01f2..72b188f074deb 100644 --- a/src/java.base/share/data/tzdata/africa +++ b/src/java.base/share/data/tzdata/africa @@ -53,6 +53,10 @@ # Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94. # https://www.jstor.org/stable/1774359 # +# For the 1911/1912 establishment of standard time in French possessions, see: +# Société Française de Physique, Recueil de constantes physiques (1913), +# page 752, 18b. +# # European-style abbreviations are commonly used along the Mediterranean. # For sub-Saharan Africa abbreviations were less standardized. # Previous editions of this database used WAT, CAT, SAT, and EAT @@ -136,7 +140,7 @@ Zone Atlantic/Cape_Verde -1:34:04 - LMT 1912 Jan 01 2:00u # Praia # Chad # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Africa/Ndjamena 1:00:12 - LMT 1912 # N'Djamena +Zone Africa/Ndjamena 1:00:12 - LMT 1912 Jan 1 # N'Djamena 1:00 - WAT 1979 Oct 14 1:00 1:00 WAST 1980 Mar 8 1:00 - WAT @@ -162,7 +166,7 @@ Zone Africa/Ndjamena 1:00:12 - LMT 1912 # N'Djamena # Inaccessible, Nightingale: uninhabited # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Africa/Abidjan -0:16:08 - LMT 1912 +Zone Africa/Abidjan -0:16:08 - LMT 1912 Jan 1 0:00 - GMT ############################################################################### @@ -308,13 +312,6 @@ Rule Egypt 2007 only - Sep Thu>=1 24:00 0 - # reproduced by other (more accessible) sites[, e.g.,]... # http://elgornal.net/news/news.aspx?id=4699258 -# From Paul Eggert (2014-06-04): -# Sarah El Deeb and Lee Keath of AP report that the Egyptian government says -# the change is because of blackouts in Cairo, even though Ahram Online (cited -# above) says DST had no affect on electricity consumption. There is -# no information about when DST will end this fall. See: -# http://abcnews.go.com/International/wireStory/el-sissi-pushes-egyptians-line-23614833 - # From Steffen Thorsen (2015-04-08): # Egypt will start DST on midnight after Thursday, April 30, 2015. # This is based on a law (no 35) from May 15, 2014 saying it starts the last diff --git a/src/java.base/share/data/tzdata/antarctica b/src/java.base/share/data/tzdata/antarctica index 3de5e726eb4d7..fc7176cd0d57a 100644 --- a/src/java.base/share/data/tzdata/antarctica +++ b/src/java.base/share/data/tzdata/antarctica @@ -103,6 +103,11 @@ # - 2018 Oct 7 4:00 - 2019 Mar 17 3:00 - 2019 Oct 4 3:00 - 2020 Mar 8 3:00 # and now - 2020 Oct 4 0:01 +# From Paul Eggert (2023-12-20): +# Transitions from 2021 on are taken from: +# https://www.timeanddate.com/time/zone/antarctica/casey +# retrieved at various dates. + # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Antarctica/Casey 0 - -00 1969 8:00 - +08 2009 Oct 18 2:00 @@ -116,7 +121,12 @@ Zone Antarctica/Casey 0 - -00 1969 8:00 - +08 2019 Oct 4 3:00 11:00 - +11 2020 Mar 8 3:00 8:00 - +08 2020 Oct 4 0:01 - 11:00 - +11 + 11:00 - +11 2021 Mar 14 0:00 + 8:00 - +08 2021 Oct 3 0:01 + 11:00 - +11 2022 Mar 13 0:00 + 8:00 - +08 2022 Oct 2 0:01 + 11:00 - +11 2023 Mar 9 3:00 + 8:00 - +08 Zone Antarctica/Davis 0 - -00 1957 Jan 13 7:00 - +07 1964 Nov 0 - -00 1969 Feb @@ -263,7 +273,50 @@ Zone Antarctica/Troll 0 - -00 2005 Feb 12 # year-round from 1960/61 to 1992 # Vostok, since 1957-12-16, temporarily closed 1994-02/1994-11 -# See Asia/Urumqi. +# From Craig Mundell (1994-12-15): +# http://quest.arc.nasa.gov/antarctica/QA/computers/Directions,Time,ZIP +# Vostok, which is one of the Russian stations, is set on the same +# time as Moscow, Russia. +# +# From Lee Hotz (2001-03-08): +# I queried the folks at Columbia who spent the summer at Vostok and this is +# what they had to say about time there: +# "in the US Camp (East Camp) we have been on New Zealand (McMurdo) +# time, which is 12 hours ahead of GMT. The Russian Station Vostok was +# 6 hours behind that (although only 2 miles away, i.e. 6 hours ahead +# of GMT). This is a time zone I think two hours east of Moscow. The +# natural time zone is in between the two: 8 hours ahead of GMT." +# +# From Paul Eggert (2001-05-04): +# This seems to be hopelessly confusing, so I asked Lee Hotz about it +# in person. He said that some Antarctic locations set their local +# time so that noon is the warmest part of the day, and that this +# changes during the year and does not necessarily correspond to mean +# solar noon. So the Vostok time might have been whatever the clocks +# happened to be during their visit. So we still don't really know what time +# it is at Vostok. +# +# From Zakhary V. Akulov (2023-12-17 22:00:48 +0700): +# ... from December, 18, 2023 00:00 by my decision the local time of +# the Antarctic research base Vostok will correspond to UTC+5. +# (2023-12-19): We constantly interact with Progress base, with company who +# builds new wintering station, with sledge convoys, with aviation - they all +# use UTC+5. Besides, difference between Moscow time is just 2 hours now, not 4. +# (2023-12-19, in response to the question "Has local time at Vostok +# been UTC+6 ever since 1957, or has it changed before?"): No. At least +# since my antarctic career start, 10 years ago, Vostok base has UTC+7. +# (In response to a 2023-12-18 question "from 02:00 to 00:00 today"): This. +# +# From Paul Eggert (2023-12-18): +# For lack of better info, guess Vostok was at +07 from founding through today, +# except when closed. + +# Zone NAME STDOFF RULES FORMAT [UNTIL] +Zone Antarctica/Vostok 0 - -00 1957 Dec 16 + 7:00 - +07 1994 Feb + 0 - -00 1994 Nov + 7:00 - +07 2023 Dec 18 2:00 + 5:00 - +05 # S Africa - year-round bases # Marion Island, -4653+03752 diff --git a/src/java.base/share/data/tzdata/asia b/src/java.base/share/data/tzdata/asia index 6a048c3ad283e..3a54291919d60 100644 --- a/src/java.base/share/data/tzdata/asia +++ b/src/java.base/share/data/tzdata/asia @@ -678,7 +678,6 @@ Zone Asia/Shanghai 8:05:43 - LMT 1901 8:00 PRC C%sT # Xinjiang time, used by many in western China; represented by Ürümqi / Ürümchi # / Wulumuqi. (Please use Asia/Shanghai if you prefer Beijing time.) -# Vostok base in Antarctica matches this since 1970. Zone Asia/Urumqi 5:50:20 - LMT 1928 6:00 - +06 @@ -2481,18 +2480,33 @@ Zone Asia/Amman 2:23:44 - LMT 1931 # effective December 21st, 2018.... # http://adilet.zan.kz/rus/docs/P1800000817 (russian language). +# From Zhanbolat Raimbekov (2024-01-19): +# Kazakhstan (all parts) switching to UTC+5 on March 1, 2024 +# https://www.gov.kz/memleket/entities/mti/press/news/details/688998?lang=ru +# [in Russian] +# (2024-01-20): https://primeminister.kz/ru/decisions/19012024-20 +# +# From Alexander Krivenyshev (2024-01-19): +# According to a different news and the official web site for the Ministry of +# Trade and Integration of the Republic of Kazakhstan: +# https://en.inform.kz/news/kazakhstan-to-switch-to-single-hour-zone-mar-1-54ad0b/ + # Zone NAME STDOFF RULES FORMAT [UNTIL] # # Almaty (formerly Alma-Ata), representing most locations in Kazakhstan -# This includes KZ-AKM, KZ-ALA, KZ-ALM, KZ-AST, KZ-BAY, KZ-VOS, KZ-ZHA, -# KZ-KAR, KZ-SEV, KZ-PAV, and KZ-YUZ. +# This includes Abai/Abay (ISO 3166-2 code KZ-10), Aqmola/Akmola (KZ-11), +# Almaty (KZ-19), Almaty city (KZ-75), Astana city (KZ-71), +# East Kazkhstan (KZ-63), Jambyl/Zhambyl (KZ-31), Jetisu/Zhetysu (KZ-33), +# Karaganda (KZ-35), North Kazakhstan (KZ-59), Pavlodar (KZ-55), +# Shyumkent city (KZ-79), Turkistan (KZ-61), and Ulytau (KZ-62). Zone Asia/Almaty 5:07:48 - LMT 1924 May 2 # or Alma-Ata 5:00 - +05 1930 Jun 21 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s 5:00 RussiaAsia +05/+06 1992 Jan 19 2:00s 6:00 RussiaAsia +06/+07 2004 Oct 31 2:00s - 6:00 - +06 -# Qyzylorda (aka Kyzylorda, Kizilorda, Kzyl-Orda, etc.) (KZ-KZY) + 6:00 - +06 2024 Mar 1 0:00 + 5:00 - +05 +# Qyzylorda (aka Kyzylorda, Kizilorda, Kzyl-Orda, etc.) (KZ-43) Zone Asia/Qyzylorda 4:21:52 - LMT 1924 May 2 4:00 - +04 1930 Jun 21 5:00 - +05 1981 Apr 1 @@ -2505,8 +2519,7 @@ Zone Asia/Qyzylorda 4:21:52 - LMT 1924 May 2 5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s 6:00 - +06 2018 Dec 21 0:00 5:00 - +05 -# -# Qostanay (aka Kostanay, Kustanay) (KZ-KUS) +# Qostanay (aka Kostanay, Kustanay) (KZ-39) # The 1991/2 rules are unclear partly because of the 1997 Turgai # reorganization. Zone Asia/Qostanay 4:14:28 - LMT 1924 May 2 @@ -2517,9 +2530,9 @@ Zone Asia/Qostanay 4:14:28 - LMT 1924 May 2 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s 5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s - 6:00 - +06 - -# Aqtöbe (aka Aktobe, formerly Aktyubinsk) (KZ-AKT) + 6:00 - +06 2024 Mar 1 0:00 + 5:00 - +05 +# Aqtöbe (aka Aktobe, formerly Aktyubinsk) (KZ-15) Zone Asia/Aqtobe 3:48:40 - LMT 1924 May 2 4:00 - +04 1930 Jun 21 5:00 - +05 1981 Apr 1 @@ -2529,7 +2542,7 @@ Zone Asia/Aqtobe 3:48:40 - LMT 1924 May 2 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s 5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s 5:00 - +05 -# Mangghystaū (KZ-MAN) +# Mangghystaū (KZ-47) # Aqtau was not founded until 1963, but it represents an inhabited region, # so include timestamps before 1963. Zone Asia/Aqtau 3:21:04 - LMT 1924 May 2 @@ -2541,7 +2554,7 @@ Zone Asia/Aqtau 3:21:04 - LMT 1924 May 2 5:00 RussiaAsia +05/+06 1994 Sep 25 2:00s 4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s 5:00 - +05 -# Atyraū (KZ-ATY) is like Mangghystaū except it switched from +# Atyraū (KZ-23) is like Mangghystaū except it switched from # +04/+05 to +05/+06 in spring 1999, not fall 1994. Zone Asia/Atyrau 3:27:44 - LMT 1924 May 2 3:00 - +03 1930 Jun 21 @@ -2552,7 +2565,7 @@ Zone Asia/Atyrau 3:27:44 - LMT 1924 May 2 5:00 RussiaAsia +05/+06 1999 Mar 28 2:00s 4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s 5:00 - +05 -# West Kazakhstan (KZ-ZAP) +# West Kazakhstan (KZ-27) # From Paul Eggert (2016-03-18): # The 1989 transition is from USSR act No. 227 (1989-03-14). Zone Asia/Oral 3:25:24 - LMT 1924 May 2 # or Ural'sk @@ -3450,20 +3463,30 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # From Heba Hamad (2023-03-22): # ... summer time will begin in Palestine from Saturday 04-29-2023, # 02:00 AM by 60 minutes forward. -# -# From Paul Eggert (2023-03-22): +# From Heba Hemad (2023-10-09): +# ... winter time will begin in Palestine from Saturday 10-28-2023, +# 02:00 AM by 60 minutes back. +# +# From Heba Hamad (2024-01-25): +# the summer time for the years 2024,2025 will begin in Palestine +# from Saturday at 02:00 AM by 60 minutes forward as shown below: +# year date +# 2024 2024-04-20 +# 2025 2025-04-12 +# +# From Paul Eggert (2024-01-25): # For now, guess that spring and fall transitions will normally # continue to use 2022's rules, that during DST Palestine will switch # to standard time at 02:00 the last Saturday before Ramadan and back -# to DST at 02:00 the first Saturday after Ramadan, and that +# to DST at 02:00 the second Saturday after Ramadan, and that # if the normal spring-forward or fall-back transition occurs during # Ramadan the former is delayed and the latter advanced. # To implement this, I predicted Ramadan-oriented transition dates for -# 2023 through 2086 by running the following program under GNU Emacs 28.2, +# 2026 through 2086 by running the following program under GNU Emacs 29.2, # with the results integrated by hand into the table below. # Predictions after 2086 are approximated without Ramadan. # -# (let ((islamic-year 1444)) +# (let ((islamic-year 1447)) # (require 'cal-islam) # (while (< islamic-year 1510) # (let ((a (calendar-islamic-to-absolute (list 9 1 islamic-year))) @@ -3472,6 +3495,7 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # (while (/= saturday (mod (setq a (1- a)) 7))) # (while (/= saturday (mod b 7)) # (setq b (1+ b))) +# (setq b (+ 7 b)) # (setq a (calendar-gregorian-from-absolute a)) # (setq b (calendar-gregorian-from-absolute b)) # (insert @@ -3522,84 +3546,84 @@ Rule Palestine 2021 only - Oct 29 1:00 0 - Rule Palestine 2022 only - Mar 27 0:00 1:00 S Rule Palestine 2022 2035 - Oct Sat<=30 2:00 0 - Rule Palestine 2023 only - Apr 29 2:00 1:00 S -Rule Palestine 2024 only - Apr 13 2:00 1:00 S -Rule Palestine 2025 only - Apr 5 2:00 1:00 S +Rule Palestine 2024 only - Apr 20 2:00 1:00 S +Rule Palestine 2025 only - Apr 12 2:00 1:00 S Rule Palestine 2026 2054 - Mar Sat<=30 2:00 1:00 S Rule Palestine 2036 only - Oct 18 2:00 0 - Rule Palestine 2037 only - Oct 10 2:00 0 - Rule Palestine 2038 only - Sep 25 2:00 0 - Rule Palestine 2039 only - Sep 17 2:00 0 - -Rule Palestine 2039 only - Oct 22 2:00 1:00 S -Rule Palestine 2039 2067 - Oct Sat<=30 2:00 0 - Rule Palestine 2040 only - Sep 1 2:00 0 - -Rule Palestine 2040 only - Oct 13 2:00 1:00 S +Rule Palestine 2040 only - Oct 20 2:00 1:00 S +Rule Palestine 2040 2067 - Oct Sat<=30 2:00 0 - Rule Palestine 2041 only - Aug 24 2:00 0 - -Rule Palestine 2041 only - Sep 28 2:00 1:00 S +Rule Palestine 2041 only - Oct 5 2:00 1:00 S Rule Palestine 2042 only - Aug 16 2:00 0 - -Rule Palestine 2042 only - Sep 20 2:00 1:00 S +Rule Palestine 2042 only - Sep 27 2:00 1:00 S Rule Palestine 2043 only - Aug 1 2:00 0 - -Rule Palestine 2043 only - Sep 12 2:00 1:00 S +Rule Palestine 2043 only - Sep 19 2:00 1:00 S Rule Palestine 2044 only - Jul 23 2:00 0 - -Rule Palestine 2044 only - Aug 27 2:00 1:00 S +Rule Palestine 2044 only - Sep 3 2:00 1:00 S Rule Palestine 2045 only - Jul 15 2:00 0 - -Rule Palestine 2045 only - Aug 19 2:00 1:00 S +Rule Palestine 2045 only - Aug 26 2:00 1:00 S Rule Palestine 2046 only - Jun 30 2:00 0 - -Rule Palestine 2046 only - Aug 11 2:00 1:00 S +Rule Palestine 2046 only - Aug 18 2:00 1:00 S Rule Palestine 2047 only - Jun 22 2:00 0 - -Rule Palestine 2047 only - Jul 27 2:00 1:00 S +Rule Palestine 2047 only - Aug 3 2:00 1:00 S Rule Palestine 2048 only - Jun 6 2:00 0 - -Rule Palestine 2048 only - Jul 18 2:00 1:00 S +Rule Palestine 2048 only - Jul 25 2:00 1:00 S Rule Palestine 2049 only - May 29 2:00 0 - -Rule Palestine 2049 only - Jul 3 2:00 1:00 S +Rule Palestine 2049 only - Jul 10 2:00 1:00 S Rule Palestine 2050 only - May 21 2:00 0 - -Rule Palestine 2050 only - Jun 25 2:00 1:00 S +Rule Palestine 2050 only - Jul 2 2:00 1:00 S Rule Palestine 2051 only - May 6 2:00 0 - -Rule Palestine 2051 only - Jun 17 2:00 1:00 S +Rule Palestine 2051 only - Jun 24 2:00 1:00 S Rule Palestine 2052 only - Apr 27 2:00 0 - -Rule Palestine 2052 only - Jun 1 2:00 1:00 S +Rule Palestine 2052 only - Jun 8 2:00 1:00 S Rule Palestine 2053 only - Apr 12 2:00 0 - -Rule Palestine 2053 only - May 24 2:00 1:00 S +Rule Palestine 2053 only - May 31 2:00 1:00 S Rule Palestine 2054 only - Apr 4 2:00 0 - -Rule Palestine 2054 only - May 16 2:00 1:00 S -Rule Palestine 2055 only - May 1 2:00 1:00 S -Rule Palestine 2056 only - Apr 22 2:00 1:00 S -Rule Palestine 2057 only - Apr 7 2:00 1:00 S -Rule Palestine 2058 max - Mar Sat<=30 2:00 1:00 S +Rule Palestine 2054 only - May 23 2:00 1:00 S +Rule Palestine 2055 only - May 8 2:00 1:00 S +Rule Palestine 2056 only - Apr 29 2:00 1:00 S +Rule Palestine 2057 only - Apr 14 2:00 1:00 S +Rule Palestine 2058 only - Apr 6 2:00 1:00 S +Rule Palestine 2059 max - Mar Sat<=30 2:00 1:00 S Rule Palestine 2068 only - Oct 20 2:00 0 - Rule Palestine 2069 only - Oct 12 2:00 0 - Rule Palestine 2070 only - Oct 4 2:00 0 - Rule Palestine 2071 only - Sep 19 2:00 0 - Rule Palestine 2072 only - Sep 10 2:00 0 - -Rule Palestine 2072 only - Oct 15 2:00 1:00 S +Rule Palestine 2072 only - Oct 22 2:00 1:00 S +Rule Palestine 2072 max - Oct Sat<=30 2:00 0 - Rule Palestine 2073 only - Sep 2 2:00 0 - -Rule Palestine 2073 only - Oct 7 2:00 1:00 S +Rule Palestine 2073 only - Oct 14 2:00 1:00 S Rule Palestine 2074 only - Aug 18 2:00 0 - -Rule Palestine 2074 only - Sep 29 2:00 1:00 S +Rule Palestine 2074 only - Oct 6 2:00 1:00 S Rule Palestine 2075 only - Aug 10 2:00 0 - -Rule Palestine 2075 only - Sep 14 2:00 1:00 S -Rule Palestine 2075 max - Oct Sat<=30 2:00 0 - +Rule Palestine 2075 only - Sep 21 2:00 1:00 S Rule Palestine 2076 only - Jul 25 2:00 0 - -Rule Palestine 2076 only - Sep 5 2:00 1:00 S +Rule Palestine 2076 only - Sep 12 2:00 1:00 S Rule Palestine 2077 only - Jul 17 2:00 0 - -Rule Palestine 2077 only - Aug 28 2:00 1:00 S +Rule Palestine 2077 only - Sep 4 2:00 1:00 S Rule Palestine 2078 only - Jul 9 2:00 0 - -Rule Palestine 2078 only - Aug 13 2:00 1:00 S +Rule Palestine 2078 only - Aug 20 2:00 1:00 S Rule Palestine 2079 only - Jun 24 2:00 0 - -Rule Palestine 2079 only - Aug 5 2:00 1:00 S +Rule Palestine 2079 only - Aug 12 2:00 1:00 S Rule Palestine 2080 only - Jun 15 2:00 0 - -Rule Palestine 2080 only - Jul 20 2:00 1:00 S +Rule Palestine 2080 only - Jul 27 2:00 1:00 S Rule Palestine 2081 only - Jun 7 2:00 0 - -Rule Palestine 2081 only - Jul 12 2:00 1:00 S +Rule Palestine 2081 only - Jul 19 2:00 1:00 S Rule Palestine 2082 only - May 23 2:00 0 - -Rule Palestine 2082 only - Jul 4 2:00 1:00 S +Rule Palestine 2082 only - Jul 11 2:00 1:00 S Rule Palestine 2083 only - May 15 2:00 0 - -Rule Palestine 2083 only - Jun 19 2:00 1:00 S +Rule Palestine 2083 only - Jun 26 2:00 1:00 S Rule Palestine 2084 only - Apr 29 2:00 0 - -Rule Palestine 2084 only - Jun 10 2:00 1:00 S +Rule Palestine 2084 only - Jun 17 2:00 1:00 S Rule Palestine 2085 only - Apr 21 2:00 0 - -Rule Palestine 2085 only - Jun 2 2:00 1:00 S +Rule Palestine 2085 only - Jun 9 2:00 1:00 S Rule Palestine 2086 only - Apr 13 2:00 0 - -Rule Palestine 2086 only - May 18 2:00 1:00 S +Rule Palestine 2086 only - May 25 2:00 1:00 S # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Gaza 2:17:52 - LMT 1900 Oct @@ -3627,7 +3651,7 @@ Zone Asia/Hebron 2:20:23 - LMT 1900 Oct # Philippines -# From Paul Eggert (2018-11-18): +# From Paul Eggert (2024-01-21): # The Spanish initially used American (west-of-Greenwich) time. # It is unknown what time Manila kept when the British occupied it from # 1762-10-06 through 1764-04; for now assume it kept American time. @@ -3635,7 +3659,7 @@ Zone Asia/Hebron 2:20:23 - LMT 1900 Oct # Philippines, issued a proclamation announcing that 1844-12-30 was to # be immediately followed by 1845-01-01; see R.H. van Gent's # History of the International Date Line -# https://www.staff.science.uu.nl/~gent0113/idl/idl_philippines.htm +# https://webspace.science.uu.nl/~gent0113/idl/idl_philippines.htm # The rest of the data entries are from Shanks & Pottenger. # From Jesper Nørgaard Welen (2006-04-26): @@ -4062,7 +4086,8 @@ Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 # The English-language name of Vietnam's most populous city is "Ho Chi Minh # City"; use Ho_Chi_Minh below to avoid a name of more than 14 characters. -# From Paul Eggert (2022-07-27) after a 2014 heads-up from Trần Ngọc Quân: +# From Paul Eggert (2024-01-14) after a 2014 heads-up from Trần Ngọc Quân +# and a 2024-01-14 heads-up from Đoàn Trần Công Danh: # Trần Tiến Bình's authoritative book "Lịch Việt Nam: thế kỷ XX-XXI (1901-2100)" # (Nhà xuất bản Văn Hoá - Thông Tin, Hanoi, 2005), pp 49-50, # is quoted verbatim in: @@ -4092,14 +4117,35 @@ Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 # # Trần cites the following sources; it's unclear which supplied the info above. # -# Hoàng Xuân Hãn: "Lịch và lịch Việt Nam". Tập san Khoa học Xã hội, -# No. 9, Paris, February 1982. +# Hoàng Xuân Hãn: "Lịch và lịch Việt Nam". Tập san Khoa học Xã hội, +# No. 9, Paris, February 1982. +# +# Lê Thành Lân: "Lịch và niên biểu lịch sử hai mươi thế kỷ (0001-2010)", +# NXB Thống kê, Hanoi, 2000. # -# Lê Thành Lân: "Lịch và niên biểu lịch sử hai mươi thế kỷ (0001-2010)", -# NXB Thống kê, Hanoi, 2000. +# Lê Thành Lân: "Lịch hai thế kỷ (1802-2010) và các lịch vĩnh cửu", +# NXB Thuận Hoá, Huế, 1995. # -# Lê Thành Lân: "Lịch hai thế kỷ (1802-2010) và các lịch vĩnh cửu", -# NXB Thuận Hoá, Huế, 1995. +# Here is the decision for the September 1945 transition: +# Võ Nguyên Giáp, Việt Nam Dân Quốc Công Báo, No. 1 (1945-09-29), page 13 +# http://baochi.nlv.gov.vn/baochi/cgi-bin/baochi?a=d&d=JwvzO19450929.2.5&dliv=none +# It says that on 1945-09-01 at 24:00, Vietnam moved back two hours, to +07. +# It also mentions a 1945-03-29 decree (by a Japanese Goveror-General) +# to set the time zone to +09, but does not say whether that decree +# merely legalized an earlier change to +09. +# +# July 1955 transition: +# Ngô Đình Diệm, Công Báo Việt Nam, No. 92 (1955-07-02), page 1780-1781 +# Ordinance (Dụ) No. 46 (1955-06-25) +# http://ddsnext.crl.edu/titles/32341#?c=0&m=29&s=0&cv=4&r=0&xywh=-89%2C342%2C1724%2C1216 +# It says that on 1955-07-01 at 01:00, South Vietnam moved back 1 hour (to +07). +# +# December 1959 transition: +# Ngô Đình Diệm, Công Báo Việt Nam Cộng Hòa, 1960 part 1 (1960-01-02), page 62 +# Decree (Sắc lệnh) No. 362-TTP (1959-12-30) +# http://ddsnext.crl.edu/titles/32341#?c=0&m=138&s=0&cv=793&r=0&xywh=-54%2C1504%2C1705%2C1202 +# It says that on 1959-12-31 at 23:00, South Vietnam moved forward 1 hour (to +08). + # Zone NAME STDOFF RULES FORMAT [UNTIL] #STDOFF 7:06:30.13 @@ -4107,9 +4153,9 @@ Zone Asia/Ho_Chi_Minh 7:06:30 - LMT 1906 Jul 1 7:06:30 - PLMT 1911 May 1 # Phù Liễn MT 7:00 - +07 1942 Dec 31 23:00 8:00 - +08 1945 Mar 14 23:00 - 9:00 - +09 1945 Sep 2 + 9:00 - +09 1945 Sep 1 24:00 7:00 - +07 1947 Apr 1 - 8:00 - +08 1955 Jul 1 + 8:00 - +08 1955 Jul 1 01:00 7:00 - +07 1959 Dec 31 23:00 8:00 - +08 1975 Jun 13 7:00 - +07 diff --git a/src/java.base/share/data/tzdata/australasia b/src/java.base/share/data/tzdata/australasia index 893d7055eaba4..624735be652d2 100644 --- a/src/java.base/share/data/tzdata/australasia +++ b/src/java.base/share/data/tzdata/australasia @@ -414,8 +414,14 @@ Zone Antarctica/Macquarie 0 - -00 1899 Nov # Please note that there will not be any daylight savings time change # in Fiji for 2022-2023.... # https://www.facebook.com/FijianGovernment/posts/pfbid0mmWVTYmTibn66ybpFda75pDcf34SSpoSaskJW5gXwaKo5Sgc7273Q4fXWc6kQV6Hl + +# From Almaz Mingaleev (2023-10-06): +# Cabinet approved the suspension of Daylight Saving and appropriate +# legislative changes will be considered including the repeal of the +# Daylight Saving Act 1998 +# https://www.fiji.gov.fj/Media-Centre/Speeches/English/CABINET-DECISIONS-3-OCTOBER-2023 # -# From Paul Eggert (2022-10-27): +# From Paul Eggert (2023-10-06): # For now, assume DST is suspended indefinitely. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S @@ -437,11 +443,11 @@ Zone Pacific/Fiji 11:55:44 - LMT 1915 Oct 26 # Suva # French Polynesia # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Pacific/Gambier -8:59:48 - LMT 1912 Oct # Rikitea +Zone Pacific/Gambier -8:59:48 - LMT 1912 Oct 1 # Rikitea -9:00 - -09 -Zone Pacific/Marquesas -9:18:00 - LMT 1912 Oct +Zone Pacific/Marquesas -9:18:00 - LMT 1912 Oct 1 -9:30 - -0930 -Zone Pacific/Tahiti -9:58:16 - LMT 1912 Oct # Papeete +Zone Pacific/Tahiti -9:58:16 - LMT 1912 Oct 1 # Papeete -10:00 - -10 # Clipperton (near North America) is administered from French Polynesia; # it is uninhabited. @@ -819,7 +825,7 @@ Zone Pacific/Apia 12:33:04 - LMT 1892 Jul 5 # Solomon Is # excludes Bougainville, for which see Papua New Guinea # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Pacific/Guadalcanal 10:39:48 - LMT 1912 Oct # Honiara +Zone Pacific/Guadalcanal 10:39:48 - LMT 1912 Oct 1 # Honiara 11:00 - +11 # Tokelau @@ -980,6 +986,10 @@ Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila # Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94. # https://www.jstor.org/stable/1774359 # +# For the 1911/1912 establishment of standard time in French possessions, see: +# Société Française de Physique, Recueil de constantes physiques (1913), +# page 752, 18b. +# # A reliable and entertaining source about time zones is # Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997). # @@ -2056,7 +2066,7 @@ Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila # ordaining - by a masterpiece of diplomatic flattery - that # the Fourth of July should be celebrated twice in that year." # This happened in 1892, according to the Evening News (Sydney) of 1892-07-20. -# https://www.staff.science.uu.nl/~gent0113/idl/idl.htm +# https://webspace.science.uu.nl/~gent0113/idl/idl_alaska_samoa.htm # Although Shanks & Pottenger says they both switched to UT -11:30 # in 1911, and to -11 in 1950. many earlier sources give -11 diff --git a/src/java.base/share/data/tzdata/backward b/src/java.base/share/data/tzdata/backward index c0746d6dd1bc8..7ddc6cc3d93b0 100644 --- a/src/java.base/share/data/tzdata/backward +++ b/src/java.base/share/data/tzdata/backward @@ -228,7 +228,6 @@ Link America/Puerto_Rico America/Tortola Link Pacific/Port_Moresby Antarctica/DumontDUrville Link Pacific/Auckland Antarctica/McMurdo Link Asia/Riyadh Antarctica/Syowa -Link Asia/Urumqi Antarctica/Vostok Link Europe/Berlin Arctic/Longyearbyen Link Asia/Riyadh Asia/Aden Link Asia/Qatar Asia/Bahrain diff --git a/src/java.base/share/data/tzdata/etcetera b/src/java.base/share/data/tzdata/etcetera index 8ae294f524a60..27147715ef6a5 100644 --- a/src/java.base/share/data/tzdata/etcetera +++ b/src/java.base/share/data/tzdata/etcetera @@ -28,7 +28,7 @@ # These entries are for uses not otherwise covered by the tz database. # Their main practical use is for platforms like Android that lack -# support for POSIX-style TZ strings. On such platforms these entries +# support for POSIX.1-2017-style TZ strings. On such platforms these entries # can be useful if the timezone database is wrong or if a ship or # aircraft at sea is not in a timezone. diff --git a/src/java.base/share/data/tzdata/europe b/src/java.base/share/data/tzdata/europe index 446d2e1e658fa..18865f33b6c59 100644 --- a/src/java.base/share/data/tzdata/europe +++ b/src/java.base/share/data/tzdata/europe @@ -1013,9 +1013,34 @@ Zone Europe/Sofia 1:33:16 - LMT 1880 # Czech Republic (Czechia) # Slovakia # -# From Paul Eggert (2018-04-15): -# The source for Czech data is: Kdy začíná a končí letní čas. 2018-04-15. +# From Ivan Benovic (2024-01-30): +# https://www.slov-lex.sk/pravne-predpisy/SK/ZZ/1946/54/ +# (This is an official link to the Czechoslovak Summer Time Act of +# March 8, 1946 that authorizes the Czechoslovak government to set the +# exact dates of change to summer time and back to Central European Time. +# The act also implicitly confirms Central European Time as the +# official time zone of Czechoslovakia and currently remains in force +# in both the Czech Republic and Slovakia.) +# https://www.psp.cz/eknih/1945pns/tisky/t0216_00.htm +# (This is a link to the original legislative proposal dating back to +# February 22, 1946. The accompanying memorandum to the proposal says +# that an advisory committee on European railroad transportation that +# met in Brussels in October 1945 decided that the change of time +# should be carried out in all participating countries in a strictly +# coordinated manner....) +# +# From Paul Eggert (2024-01-30): +# The source for Czech data is: Kdy začíná a končí letní čas. # https://kalendar.beda.cz/kdy-zacina-a-konci-letni-cas +# Its main text disagrees with its quoted sources only in 1918, +# where the main text says spring and autumn transitions +# occurred at 02:00 and 03:00 respectively (as usual), +# whereas the 1918 source "Oznámení o zavedení letního času v roce 1918" +# says transitions were at 01:00 and 02:00 respectively. +# As the 1918 source appears to be a humorous piece, and it is +# unlikely that Prague would have disagreed with its neighbors by an hour, +# go with the main text for now. +# # We know of no English-language name for historical Czech winter time; # abbreviate it as "GMT", as it happened to be GMT. # @@ -1146,6 +1171,23 @@ Zone Atlantic/Faroe -0:27:04 - LMT 1908 Jan 11 # Tórshavn # 2. The shift *from* DST in 2023 happens as normal, but coincides with the # shift to UTC-02 normaltime (people will not change their clocks here). # 3. After this, DST is still observed, but as -02/-01 instead of -03/-02. +# +# From Múte Bourup Egede via Jógvan Svabo Samuelsen (2023-03-15): +# Greenland will not switch to Daylight Saving Time this year, 2023, +# because the standard time for Greenland will change from UTC -3 to UTC -2. +# However, Greenland will change to Daylight Saving Time again in 2024 +# and onwards. + +# From a contributor who wishes to remain anonymous for now (2023-10-29): +# https://www.dr.dk/nyheder/seneste/i-nat-skal-uret-stilles-en-time-tilbage-men-foerste-gang-sker-det-ikke-i-groenland +# with a link to that page: +# https://naalakkersuisut.gl/Nyheder/2023/10/2710_sommertid +# ... Ittoqqortoormiit joins the time of Nuuk at March 2024. +# What would mean that America/Scoresbysund would either be in -01 year round +# or in -02/-01 like America/Nuuk, but no longer in -01/+00. +# +# From Paul Eggert (2023-10-29): +# For now, assume it will be like America/Nuuk. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Thule 1991 1992 - Mar lastSun 2:00 1:00 D @@ -1166,10 +1208,12 @@ Zone America/Danmarkshavn -1:14:40 - LMT 1916 Jul 28 Zone America/Scoresbysund -1:27:52 - LMT 1916 Jul 28 # Ittoqqortoormiit -2:00 - -02 1980 Apr 6 2:00 -2:00 C-Eur -02/-01 1981 Mar 29 - -1:00 EU -01/+00 + -1:00 EU -01/+00 2024 Mar 31 + -2:00 EU -02/-01 Zone America/Nuuk -3:26:56 - LMT 1916 Jul 28 # Godthåb -3:00 - -03 1980 Apr 6 2:00 - -3:00 EU -03/-02 2023 Oct 29 1:00u + -3:00 EU -03/-02 2023 Mar 26 1:00u + -2:00 - -02 2023 Oct 29 1:00u -2:00 EU -02/-01 Zone America/Thule -4:35:08 - LMT 1916 Jul 28 # Pituffik -4:00 Thule A%sT @@ -3734,11 +3778,7 @@ Zone Europe/Istanbul 1:55:52 - LMT 1880 # and not at 3:00 as would have been under EU rules. # This is why I have set the change to EU rules into May 1996, # so that the change in March is stil covered by the Ukraine rule. -# The next change in October 1996 happened under EU rules.... -# TZ database holds three other zones for Ukraine.... I have not yet -# worked out the consequences for these three zones, as we (me and my -# US colleague David Cochrane) are still trying to get more -# information upon these local deviations from Kiev rules. +# The next change in October 1996 happened under EU rules. # # From Paul Eggert (2022-08-27): # For now, assume that Ukraine's zones all followed the same rules, diff --git a/src/java.base/share/data/tzdata/iso3166.tab b/src/java.base/share/data/tzdata/iso3166.tab index cea17732dd138..7fa350ecbe3db 100644 --- a/src/java.base/share/data/tzdata/iso3166.tab +++ b/src/java.base/share/data/tzdata/iso3166.tab @@ -26,17 +26,22 @@ # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. # -# From Paul Eggert (2022-11-18): +# From Paul Eggert (2023-09-06): # This file contains a table of two-letter country codes. Columns are # separated by a single tab. Lines beginning with '#' are comments. # All text uses UTF-8 encoding. The columns of the table are as follows: # # 1. ISO 3166-1 alpha-2 country code, current as of -# ISO 3166-1 N1087 (2022-09-02). See: Updates on ISO 3166-1 -# https://isotc.iso.org/livelink/livelink/Open/16944257 -# 2. The usual English name for the coded region, -# chosen so that alphabetic sorting of subsets produces helpful lists. -# This is not the same as the English name in the ISO 3166 tables. +# ISO/TC 46 N1108 (2023-04-05). See: ISO/TC 46 Documents +# https://www.iso.org/committee/48750.html?view=documents +# 2. The usual English name for the coded region. This sometimes +# departs from ISO-listed names, sometimes so that sorted subsets +# of names are useful (e.g., "Samoa (American)" and "Samoa +# (western)" rather than "American Samoa" and "Samoa"), +# sometimes to avoid confusion among non-experts (e.g., +# "Czech Republic" and "Turkey" rather than "Czechia" and "Türkiye"), +# and sometimes to omit needless detail or churn (e.g., "Netherlands" +# rather than "Netherlands (the)" or "Netherlands (Kingdom of the)"). # # The table is sorted by country code. # diff --git a/src/java.base/share/data/tzdata/leapseconds b/src/java.base/share/data/tzdata/leapseconds index 89ce8b89cd28f..8e7df3de984fb 100644 --- a/src/java.base/share/data/tzdata/leapseconds +++ b/src/java.base/share/data/tzdata/leapseconds @@ -26,13 +26,10 @@ # This file is in the public domain. # This file is generated automatically from the data in the public-domain -# NIST format leap-seconds.list file, which can be copied from -# -# or . -# The NIST file is used instead of its IERS upstream counterpart +# NIST/IERS format leap-seconds.list file, which can be copied from # -# because under US law the NIST file is public domain -# whereas the IERS file's copyright and license status is unclear. +# or, in a variant with different comments, from +# . # For more about leap-seconds.list, please see # The NTP Timescale and Leap Seconds # . @@ -95,11 +92,11 @@ Leap 2016 Dec 31 23:59:60 + S # Any additional leap seconds will come after this. # This Expires line is commented out for now, # so that pre-2020a zic implementations do not reject this file. -#Expires 2023 Dec 28 00:00:00 +#Expires 2024 Dec 28 00:00:00 # POSIX timestamps for the data in this file: -#updated 1467936000 (2016-07-08 00:00:00 UTC) -#expires 1703721600 (2023-12-28 00:00:00 UTC) +#updated 1704708379 (2024-01-08 10:06:19 UTC) +#expires 1735344000 (2024-12-28 00:00:00 UTC) -# Updated through IERS Bulletin C65 -# File expires on: 28 December 2023 +# Updated through IERS Bulletin C (https://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat) +# File expires on 28 December 2024 diff --git a/src/java.base/share/data/tzdata/northamerica b/src/java.base/share/data/tzdata/northamerica index e240cf35103c4..a8b2ef3f7fa5f 100644 --- a/src/java.base/share/data/tzdata/northamerica +++ b/src/java.base/share/data/tzdata/northamerica @@ -1,3 +1,4 @@ +# # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -1290,6 +1291,10 @@ Zone America/Menominee -5:50:27 - LMT 1885 Sep 18 12:00 # # [PDF] (1914-03) # +# For the 1911/1912 establishment of standard time in French possessions, see: +# Société Française de Physique, Recueil de constantes physiques (1913), +# page 752, 18b. +# # See the 'europe' file for Greenland. # Canada @@ -1376,7 +1381,7 @@ Zone America/Menominee -5:50:27 - LMT 1885 Sep 18 12:00 # From Paul Eggert (2014-10-18): # H. David Matthews and Mary Vincent's map # "It's about TIME", _Canadian Geographic_ (September-October 1998) -# http://www.canadiangeographic.ca/Magazine/SO98/alacarte.asp +# https://web.archive.org/web/19990827055050/https://canadiangeographic.ca/SO98/geomap.htm # contains detailed boundaries for regions observing nonstandard # time and daylight saving time arrangements in Canada circa 1998. # @@ -1475,7 +1480,7 @@ Rule StJohns 1989 2006 - Apr Sun>=1 0:01 1:00 D Rule StJohns 2007 2011 - Mar Sun>=8 0:01 1:00 D Rule StJohns 2007 2010 - Nov Sun>=1 0:01 0 S # -# St John's has an apostrophe, but Posix file names can't have apostrophes. +# St John's has an apostrophe, but POSIX file names can't have apostrophes. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/St_Johns -3:30:52 - LMT 1884 -3:30:52 StJohns N%sT 1918 @@ -1664,6 +1669,15 @@ Zone America/Moncton -4:19:08 - LMT 1883 Dec 9 # Some cities in the United States have pushed the deadline back # three weeks and will change over from daylight saving in October. +# From Chris Walton (2024-01-09): +# The [Toronto] changes in 1947, 1948, and 1949 took place at 2:00 a.m. local +# time instead of midnight.... Toronto Daily Star - ... +# April 2, 1947 - Page 39 ... April 7, 1948 - Page 13 ... +# April 2, 1949 - Page 1 ... April 7, 1949 - Page 24 ... +# November 25, 1949 - Page 52 ... April 21, 1950 - Page 14 ... +# September 19, 1950 - Page 46 ... September 20, 1950 - Page 3 ... +# November 24, 1950 - Page 21 + # From Arthur David Olson (2010-07-17): # # "Standard Time and Time Zones in Canada" appeared in @@ -1725,13 +1739,9 @@ Rule Toronto 1927 1937 - Sep Sun>=25 2:00 0 S Rule Toronto 1928 1937 - Apr Sun>=25 2:00 1:00 D Rule Toronto 1938 1940 - Apr lastSun 2:00 1:00 D Rule Toronto 1938 1939 - Sep lastSun 2:00 0 S -Rule Toronto 1945 1946 - Sep lastSun 2:00 0 S -Rule Toronto 1946 only - Apr lastSun 2:00 1:00 D -Rule Toronto 1947 1949 - Apr lastSun 0:00 1:00 D -Rule Toronto 1947 1948 - Sep lastSun 0:00 0 S -Rule Toronto 1949 only - Nov lastSun 0:00 0 S -Rule Toronto 1950 1973 - Apr lastSun 2:00 1:00 D -Rule Toronto 1950 only - Nov lastSun 2:00 0 S +Rule Toronto 1945 1948 - Sep lastSun 2:00 0 S +Rule Toronto 1946 1973 - Apr lastSun 2:00 1:00 D +Rule Toronto 1949 1950 - Nov lastSun 2:00 0 S Rule Toronto 1951 1956 - Sep lastSun 2:00 0 S # Shanks & Pottenger say Toronto ended DST a week early in 1971, # namely on 1971-10-24, but Mark Brader wrote (2003-05-31) that this @@ -3454,7 +3464,7 @@ Zone America/Jamaica -5:07:10 - LMT 1890 # Kingston # Martinique # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Martinique -4:04:20 - LMT 1890 # Fort-de-France - -4:04:20 - FFMT 1911 May # Fort-de-France MT + -4:04:20 - FFMT 1911 May 1 # Fort-de-France MT -4:00 - AST 1980 Apr 6 -4:00 1:00 ADT 1980 Sep 28 -4:00 - AST @@ -3561,7 +3571,7 @@ Zone America/Puerto_Rico -4:24:25 - LMT 1899 Mar 28 12:00 # San Juan # St Pierre and Miquelon # There are too many St Pierres elsewhere, so we'll use 'Miquelon'. # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone America/Miquelon -3:44:40 - LMT 1911 May 15 # St Pierre +Zone America/Miquelon -3:44:40 - LMT 1911 Jun 15 # St Pierre -4:00 - AST 1980 May -3:00 - -03 1987 -3:00 Canada -03/-02 diff --git a/src/java.base/share/data/tzdata/southamerica b/src/java.base/share/data/tzdata/southamerica index 4024e7180cdb9..d77acc088570b 100644 --- a/src/java.base/share/data/tzdata/southamerica +++ b/src/java.base/share/data/tzdata/southamerica @@ -1593,8 +1593,11 @@ Zone Atlantic/Stanley -3:51:24 - LMT 1890 -3:00 - -03 # French Guiana +# For the 1911/1912 establishment of standard time in French possessions, see: +# Société Française de Physique, Recueil de constantes physiques (1913), +# page 752, 18b. # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone America/Cayenne -3:29:20 - LMT 1911 Jul +Zone America/Cayenne -3:29:20 - LMT 1911 Jul 1 -4:00 - -04 1967 Oct -3:00 - -03 @@ -1720,6 +1723,12 @@ Rule Para 2010 2012 - Apr Sun>=8 0:00 0 - # From Carlos Raúl Perasso (2014-02-28): # Decree 1264 can be found at: # http://www.presidencia.gov.py/archivos/documentos/DECRETO1264_ey9r8zai.pdf +# +# From Paul Eggert (2023-07-26): +# Transition dates are now set by Law No. 7115, not by presidential decree. +# https://www.abc.com.py/politica/2023/07/12/promulgacion-el-cambio-de-hora-sera-por-ley/ +# From Carlos Raúl Perasso (2023-07-27): +# http://silpy.congreso.gov.py/descarga/ley-144138 Rule Para 2013 max - Mar Sun>=22 0:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] diff --git a/src/java.base/share/data/tzdata/zone.tab b/src/java.base/share/data/tzdata/zone.tab index 3edb0d61c8099..0a01e8777dd25 100644 --- a/src/java.base/share/data/tzdata/zone.tab +++ b/src/java.base/share/data/tzdata/zone.tab @@ -71,7 +71,7 @@ AR -3124-06411 America/Argentina/Cordoba Argentina (most areas: CB, CC, CN, ER, AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) AR -2649-06513 America/Argentina/Tucuman Tucuman (TM) -AR -2828-06547 America/Argentina/Catamarca Catamarca (CT); Chubut (CH) +AR -2828-06547 America/Argentina/Catamarca Catamarca (CT), Chubut (CH) AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) @@ -110,7 +110,7 @@ BN +0456+11455 Asia/Brunei BO -1630-06809 America/La_Paz BQ +120903-0681636 America/Kralendijk BR -0351-03225 America/Noronha Atlantic islands -BR -0127-04829 America/Belem Para (east); Amapa +BR -0127-04829 America/Belem Para (east), Amapa BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) BR -0803-03454 America/Recife Pernambuco BR -0712-04812 America/Araguaina Tocantins @@ -130,21 +130,21 @@ BT +2728+08939 Asia/Thimphu BW -2439+02555 Africa/Gaborone BY +5354+02734 Europe/Minsk BZ +1730-08812 America/Belize -CA +4734-05243 America/St_Johns Newfoundland; Labrador (southeast) -CA +4439-06336 America/Halifax Atlantic - NS (most areas); PE +CA +4734-05243 America/St_Johns Newfoundland, Labrador (SE) +CA +4439-06336 America/Halifax Atlantic - NS (most areas), PE CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) -CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) +CA +4339-07923 America/Toronto Eastern - ON & QC (most areas) CA +6344-06828 America/Iqaluit Eastern - NU (most areas) -CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) -CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba +CA +484531-0913718 America/Atikokan EST - ON (Atikokan), NU (Coral H) +CA +4953-09709 America/Winnipeg Central - ON (west), Manitoba CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +624900-0920459 America/Rankin_Inlet Central - NU (central) CA +5024-10439 America/Regina CST - SK (most areas) CA +5017-10750 America/Swift_Current CST - SK (midwest) -CA +5333-11328 America/Edmonton Mountain - AB; BC (E); NT (E); SK (W) +CA +5333-11328 America/Edmonton Mountain - AB, BC(E), NT(E), SK(W) CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) CA +682059-1334300 America/Inuvik Mountain - NT (west) CA +4906-11631 America/Creston MST - BC (Creston) @@ -230,8 +230,8 @@ HT +1832-07220 America/Port-au-Prince HU +4730+01905 Europe/Budapest ID -0610+10648 Asia/Jakarta Java, Sumatra ID -0002+10920 Asia/Pontianak Borneo (west, central) -ID -0507+11924 Asia/Makassar Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west) -ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya); Malukus/Moluccas +ID -0507+11924 Asia/Makassar Borneo (east, south), Sulawesi/Celebes, Bali, Nusa Tengarra, Timor (west) +ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya), Malukus/Moluccas IE +5320-00615 Europe/Dublin IL +314650+0351326 Asia/Jerusalem IM +5409-00428 Europe/Isle_of_Man @@ -378,7 +378,7 @@ RU +4310+13156 Asia/Vladivostok MSK+07 - Amur River RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky RU +5934+15048 Asia/Magadan MSK+08 - Magadan RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island -RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); N Kuril Is +RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E), N Kuril Is RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea RW -0157+03004 Africa/Kigali @@ -441,7 +441,7 @@ US +470659-1011757 America/North_Dakota/Center Central - ND (Oliver) US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) US +394421-1045903 America/Denver Mountain (most areas) -US +433649-1161209 America/Boise Mountain - ID (south); OR (east) +US +433649-1161209 America/Boise Mountain - ID (south), OR (east) US +332654-1120424 America/Phoenix MST - AZ (except Navajo) US +340308-1181434 America/Los_Angeles Pacific US +611305-1495401 America/Anchorage Alaska (most areas) diff --git a/src/java.base/share/legal/public_suffix.md b/src/java.base/share/legal/public_suffix.md index 24924b6968add..493f3b1680dfb 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/88467c960d6cdad2ca1623e892e5e17506bc269f/public_suffix_list.dat. +https://raw.githubusercontent.com/publicsuffix/list/b5bf572c52988dbe9d865b8f090ea819024a9936/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.1 b/src/java.base/share/man/java.1 index c981746c9b87e..32cc16fb08fa7 100644 --- a/src/java.base/share/man/java.1 +++ b/src/java.base/share/man/java.1 @@ -1,4 +1,4 @@ -.\" Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved. +.\" Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. .\" DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. .\" .\" This code is free software; you can redistribute it and/or modify it @@ -1446,6 +1446,17 @@ usage by individual \f[V]CallSite\f[R], individual virtual memory region and its committed regions. .RE .TP +\f[V]-XX:TrimNativeHeapInterval=\f[R]\f[I]millis\f[R] +Interval, in ms, at which the JVM will trim the native heap. +Lower values will reclaim memory more eagerly at the cost of higher +overhead. +A value of 0 (default) disables native heap trimming. +Native heap trimming is performed in a dedicated thread. +.RS +.PP +This option is only supported on Linux with GNU C Library (glibc). +.RE +.TP \f[V]-XX:+NeverActAsServerClassMachine\f[R] Enable the \[dq]Client VM emulation\[dq] mode which only uses the C1 JIT compiler, a 32Mb CodeCache and the Serial GC. @@ -1565,6 +1576,15 @@ Specifies the path and name of the class data sharing (CDS) archive file See \f[B]Application Class Data Sharing\f[R]. .RE .TP +\f[V]-XX:+VerifySharedSpaces\f[R] +If this option is specified, the JVM will load a CDS archive file only +if it passes an integrity check based on CRC32 checksums. +The purpose of this flag is to check for unintentional damage to CDS +archive files in transmission or storage. +To guarantee the security and proper operation of CDS, the user must +ensure that the CDS archive files used by Java applications cannot be +modified without proper authorization. +.TP \f[V]-XX:SharedArchiveConfigFile=\f[R]\f[I]shared_config_file\f[R] Specifies additional shared data added to the archive file. .TP diff --git a/src/java.base/share/native/libfallbackLinker/fallbackLinker.c b/src/java.base/share/native/libfallbackLinker/fallbackLinker.c index 7f554d497372c..86cbb2e853ff9 100644 --- a/src/java.base/share/native/libfallbackLinker/fallbackLinker.c +++ b/src/java.base/share/native/libfallbackLinker/fallbackLinker.c @@ -40,12 +40,29 @@ static jclass LibFallback_class; static jmethodID LibFallback_doUpcall_ID; static const char* LibFallback_doUpcall_sig = "(JJLjava/lang/invoke/MethodHandle;)V"; -JNIEXPORT void JNICALL +#define CHECK_NULL(expr) \ + if (expr == NULL) { \ + return JNI_FALSE; \ + } + +JNIEXPORT jboolean JNICALL Java_jdk_internal_foreign_abi_fallback_LibFallback_init(JNIEnv* env, jclass cls) { - (*env)->GetJavaVM(env, &VM); - LibFallback_class = (*env)->FindClass(env, "jdk/internal/foreign/abi/fallback/LibFallback"); + jint result = (*env)->GetJavaVM(env, &VM); + if (result != 0) { + return JNI_FALSE; + } + + jclass LibFallback_class_local = (*env)->FindClass(env, "jdk/internal/foreign/abi/fallback/LibFallback"); + CHECK_NULL(LibFallback_class_local) + + LibFallback_class = (*env)->NewGlobalRef(env, LibFallback_class_local); + CHECK_NULL(LibFallback_class) + LibFallback_doUpcall_ID = (*env)->GetStaticMethodID(env, LibFallback_class, "doUpcall", LibFallback_doUpcall_sig); + CHECK_NULL(LibFallback_doUpcall_ID) + + return JNI_TRUE; } JNIEXPORT jlong JNICALL diff --git a/src/java.base/share/native/libverify/check_code.c b/src/java.base/share/native/libverify/check_code.c index a0c427a7e4b23..d1ebd3d5b94e7 100644 --- a/src/java.base/share/native/libverify/check_code.c +++ b/src/java.base/share/native/libverify/check_code.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -81,6 +81,7 @@ #include #include #include +#include #include "jni.h" #include "jni_util.h" @@ -1195,7 +1196,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) } } if (opcode == JVM_OPC_tableswitch) { - keys = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]) + 1; + keys = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]) + 1; delta = 1; } else { keys = _ck_ntohl(lpc[1]); /* number of pairs */ @@ -1677,11 +1678,14 @@ static int instruction_length(unsigned char *iptr, unsigned char *end) switch (instruction) { case JVM_OPC_tableswitch: { int *lpc = (int *)UCALIGN(iptr + 1); - int index; + int64_t low, high, index; if (lpc + 2 >= (int *)end) { return -1; /* do not read pass the end */ } - index = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]); + low = _ck_ntohl(lpc[1]); + high = _ck_ntohl(lpc[2]); + index = high - low; + // The value of low must be less than or equal to high - i.e. index >= 0 if ((index < 0) || (index > 65535)) { return -1; /* illegal */ } else { 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 3257b5bf32e59..3b09bd259ceec 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,10 +25,15 @@ package sun.nio.fs; -import java.nio.file.attribute.*; -import java.util.concurrent.TimeUnit; -import java.util.Set; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.nio.file.attribute.GroupPrincipal; +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.Set; +import java.util.concurrent.TimeUnit; /** * Unix implementation of PosixFileAttributes. @@ -52,6 +57,7 @@ class UnixFileAttributes private long st_ctime_sec; private long st_ctime_nsec; private long st_birthtime_sec; + private long st_birthtime_nsec; // created lazily private volatile UserPrincipal owner; @@ -158,7 +164,7 @@ public FileTime lastAccessTime() { @Override public FileTime creationTime() { if (UnixNativeDispatcher.birthtimeSupported()) { - return FileTime.from(st_birthtime_sec, TimeUnit.SECONDS); + return toFileTime(st_birthtime_sec, st_birthtime_nsec); } else { // return last modified when birth time not supported return lastModifiedTime(); diff --git a/src/java.base/unix/native/libjava/FileDescriptor_md.c b/src/java.base/unix/native/libjava/FileDescriptor_md.c index 54268f10a9182..095249bbcf2ad 100644 --- a/src/java.base/unix/native/libjava/FileDescriptor_md.c +++ b/src/java.base/unix/native/libjava/FileDescriptor_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ Java_java_io_FileDescriptor_initIDs(JNIEnv *env, jclass fdClass) { */ JNIEXPORT void JNICALL -Java_java_io_FileDescriptor_sync(JNIEnv *env, jobject this) { +Java_java_io_FileDescriptor_sync0(JNIEnv *env, jobject this) { FD fd = THIS_FD(this); if (IO_Sync(fd) == -1) { JNU_ThrowByName(env, "java/io/SyncFailedException", "sync failed"); diff --git a/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c b/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c index 56a72fab1db6b..a54d578254748 100644 --- a/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c +++ b/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c @@ -485,18 +485,28 @@ void unix_getUserInfo(JNIEnv* env, jobject jinfo, uid_t uid) { } /* - * The following functions are common on Solaris, Linux and AIX. + * The following functions are for Linux */ -#if defined (__linux__) || defined(_AIX) +#if defined (__linux__) /* - * Returns the children of the requested pid and optionally each parent and - * start time. - * Reads /proc and accumulates any process who parent pid matches. - * The resulting pids are stored into the array of longs. + * Return pids of active processes, and optionally parent pids and + * start times for each process. + * For a specific non-zero pid, only the direct children are returned. + * If the pid is zero, all active processes are returned. + * Reads /proc and accumulates any process following the rules above. + * The resulting pids are stored into an array of longs named jarray. * The number of pids is returned if they all fit. - * If the array is too short, the negative of the desired length is returned. + * If the parentArray is non-null, store also the parent pid. + * In this case the parentArray must have the same length as the result pid array. + * Of course in the case of a given non-zero pid all entries in the parentArray + * will contain this pid, so this array does only make sense in the case of a given + * zero pid. + * If the jstimesArray is non-null, store also the start time of the pid. + * In this case the jstimesArray must have the same length as the result pid array. + * If the array(s) (is|are) too short, excess pids are not stored and + * the desired length is returned. */ jint unix_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray, jlongArray jparentArray, jlongArray jstimesArray) { @@ -607,7 +617,7 @@ jint unix_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray, return count; } -#endif // defined (__linux__) || defined(_AIX) +#endif // defined (__linux__) /* * The following functions are for AIX. 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 230de04c079f4..4766a8834729f 100644 --- a/src/java.base/unix/native/libjava/java_props_md.c +++ b/src/java.base/unix/native/libjava/java_props_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,6 +238,11 @@ static int ParseLocale(JNIEnv* env, int cat, char ** std_language, char ** std_s *std_language = "en"; if (language != NULL && mapLookup(language_names, language, std_language) == 0) { *std_language = malloc(strlen(language)+1); + if (*std_language == NULL) { + free(encoding_variant); + JNU_ThrowOutOfMemoryError(env, NULL); + return 0; + } strcpy(*std_language, language); } } @@ -246,6 +251,11 @@ static int ParseLocale(JNIEnv* env, int cat, char ** std_language, char ** std_s if (std_country != NULL && country != NULL) { if (mapLookup(country_names, country, std_country) == 0) { *std_country = malloc(strlen(country)+1); + if (*std_country == NULL) { + free(encoding_variant); + JNU_ThrowOutOfMemoryError(env, NULL); + return 0; + } strcpy(*std_country, country); } } diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c index 4db86234b23a8..fff524e03ae97 100644 --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c @@ -263,7 +263,11 @@ tcp_ping4(JNIEnv *env, SOCKETADDRESS *sa, SOCKETADDRESS *netif, jint timeout, // set TTL if (ttl > 0) { - setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); + if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) { + NET_ThrowNew(env, errno, "setsockopt IP_TTL failed"); + close(fd); + return JNI_FALSE; + } } // A network interface was specified, so let's bind to it. @@ -349,11 +353,19 @@ ping4(JNIEnv *env, jint fd, SOCKETADDRESS *sa, SOCKETADDRESS *netif, struct timeval tv = { 0, 0 }; const size_t plen = ICMP_MINLEN + sizeof(tv); - setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0) { + NET_ThrowNew(env, errno, "setsockopt SO_RCVBUF failed"); + close(fd); + return JNI_FALSE; + } // sets the ttl (max number of hops) if (ttl > 0) { - setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); + if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) { + NET_ThrowNew(env, errno, "setsockopt IP_TTL failed"); + close(fd); + return JNI_FALSE; + } } // a specific interface was specified, so let's bind the socket diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c index a28b2f99be0f2..bad7872c179fd 100644 --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -463,12 +463,16 @@ tcp_ping6(JNIEnv *env, SOCKETADDRESS *sa, SOCKETADDRESS *netif, jint timeout, // set TTL if (ttl > 0) { - setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); + if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) { + NET_ThrowNew(env, errno, "setsockopt IPV6_UNICAST_HOPS failed"); + close(fd); + return JNI_FALSE; + } } // A network interface was specified, so let's bind to it. if (netif != NULL) { - if (bind(fd, &netif->sa, sizeof(struct sockaddr_in6)) <0) { + if (bind(fd, &netif->sa, sizeof(struct sockaddr_in6)) < 0) { NET_ThrowNew(env, errno, "Can't bind socket"); close(fd); return JNI_FALSE; @@ -557,11 +561,19 @@ ping6(JNIEnv *env, jint fd, SOCKETADDRESS *sa, SOCKETADDRESS *netif, setsockopt(fd, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sizeof(int)); #endif - setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0) { + NET_ThrowNew(env, errno, "setsockopt SO_RCVBUF failed"); + close(fd); + return JNI_FALSE; + } // sets the ttl (max number of hops) if (ttl > 0) { - setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); + if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) { + NET_ThrowNew(env, errno, "setsockopt IPV6_UNICAST_HOPS failed"); + close(fd); + return JNI_FALSE; + } } // a specific interface was specified, so let's bind the socket 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 9d812de5c88e4..7be6d9a69fee6 100644 --- a/src/java.base/unix/native/libnet/net_util_md.c +++ b/src/java.base/unix/native/libnet/net_util_md.c @@ -615,7 +615,9 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg, } if (sotype == SOCK_DGRAM) { - setsockopt(fd, level, SO_REUSEPORT, arg, len); + if (setsockopt(fd, level, SO_REUSEPORT, arg, len) < 0) { + return -1; + } } } #endif diff --git a/src/java.base/unix/native/libnio/MappedMemoryUtils.c b/src/java.base/unix/native/libnio/MappedMemoryUtils.c index 4c9b72e51ad3d..cdd8edff22a6c 100644 --- a/src/java.base/unix/native/libnio/MappedMemoryUtils.c +++ b/src/java.base/unix/native/libnio/MappedMemoryUtils.c @@ -33,10 +33,6 @@ #include #include -#ifdef _AIX -#include -#endif - /* Output type for mincore(2) */ #ifdef __linux__ typedef unsigned char mincore_vec_t; @@ -44,16 +40,6 @@ typedef unsigned char mincore_vec_t; typedef char mincore_vec_t; #endif -#ifdef _AIX -static long calculate_number_of_pages_in_range(void* address, size_t len, size_t pagesize) { - uintptr_t address_unaligned = (uintptr_t) address; - uintptr_t address_aligned = address_unaligned & (~(pagesize - 1)); - size_t len2 = len + (address_unaligned - address_aligned); - long numPages = (len2 + pagesize - 1) / pagesize; - return numPages; -} -#endif - JNIEXPORT jboolean JNICALL Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, jlong len, jlong numPages) @@ -64,15 +50,6 @@ Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong addres void *a = (void *) jlong_to_ptr(address); mincore_vec_t* vec = NULL; -#ifdef _AIX - /* See JDK-8186665 */ - size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); - if ((long)pagesize == -1) { - return JNI_FALSE; - } - numPages = (jlong) calculate_number_of_pages_in_range(a, len, pagesize); -#endif - /* Include space for one sentinel byte at the end of the buffer * to catch overflows. */ vec = (mincore_vec_t*) malloc(numPages + 1); diff --git a/src/java.base/unix/native/libnio/ch/UnixFileDispatcherImpl.c b/src/java.base/unix/native/libnio/ch/UnixFileDispatcherImpl.c index 37412e1e5f800..a24f0503e5579 100644 --- a/src/java.base/unix/native/libnio/ch/UnixFileDispatcherImpl.c +++ b/src/java.base/unix/native/libnio/ch/UnixFileDispatcherImpl.c @@ -45,6 +45,11 @@ #define fstatvfs64 fstatvfs #endif +#if defined(__linux__) +#include +#include +#endif + #include "jni.h" #include "nio.h" #include "nio_util.h" @@ -169,7 +174,7 @@ Java_sun_nio_ch_UnixFileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject if (fstat64(fd, &fbuf) < 0) return handle(env, -1, "Size failed"); -#ifdef BLKGETSIZE64 +#if defined(__linux__) if (S_ISBLK(fbuf.st_mode)) { uint64_t size; if (ioctl(fd, BLKGETSIZE64, &size) < 0) diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index 90c0a52d7e815..6d933be4e6e8f 100644 --- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -51,6 +51,7 @@ #ifdef __linux__ #include +#include // makedev macros #endif #if defined(__linux__) || defined(_AIX) @@ -71,6 +72,98 @@ #define readdir64 readdir #endif +#if defined(__linux__) +// Account for the case where we compile on a system without statx +// support. We still want to ensure we can call statx at runtime +// if the runtime glibc version supports it (>= 2.28). We do this +// by defining binary compatible statx structs in this file and +// not relying on included headers. + +#ifndef __GLIBC__ +// Alpine doesn't know these types, define them +typedef unsigned int __uint32_t; +typedef unsigned short __uint16_t; +typedef unsigned long int __uint64_t; +#endif + +/* + * Timestamp structure for the timestamps in struct statx. + */ +struct my_statx_timestamp { + int64_t tv_sec; + __uint32_t tv_nsec; + int32_t __reserved; +}; + +/* + * struct statx used by statx system call on >= glibc 2.28 + * systems + */ +struct my_statx +{ + __uint32_t stx_mask; + __uint32_t stx_blksize; + __uint64_t stx_attributes; + __uint32_t stx_nlink; + __uint32_t stx_uid; + __uint32_t stx_gid; + __uint16_t stx_mode; + __uint16_t __statx_pad1[1]; + __uint64_t stx_ino; + __uint64_t stx_size; + __uint64_t stx_blocks; + __uint64_t stx_attributes_mask; + struct my_statx_timestamp stx_atime; + struct my_statx_timestamp stx_btime; + struct my_statx_timestamp stx_ctime; + struct my_statx_timestamp stx_mtime; + __uint32_t stx_rdev_major; + __uint32_t stx_rdev_minor; + __uint32_t stx_dev_major; + __uint32_t stx_dev_minor; + __uint64_t __statx_pad2[14]; +}; + +// statx masks, flags, constants + +#ifndef AT_SYMLINK_NOFOLLOW +#define AT_SYMLINK_NOFOLLOW 0x100 +#endif + +#ifndef AT_STATX_SYNC_AS_STAT +#define AT_STATX_SYNC_AS_STAT 0x0000 +#endif + +#ifndef AT_EMPTY_PATH +#define AT_EMPTY_PATH 0x1000 +#endif + +#ifndef STATX_BASIC_STATS +#define STATX_BASIC_STATS 0x000007ffU +#endif + +#ifndef STATX_BTIME +#define STATX_BTIME 0x00000800U +#endif + +#ifndef STATX_ALL +#define STATX_ALL (STATX_BTIME | STATX_BASIC_STATS) +#endif + +#ifndef AT_FDCWD +#define AT_FDCWD -100 +#endif + +#ifndef RTLD_DEFAULT +#define RTLD_DEFAULT RTLD_LOCAL +#endif + +#define NO_FOLLOW_SYMLINK 1 +#define FOLLOW_SYMLINK 0 + +#endif // __linux__ + + #include "jni.h" #include "jni_util.h" #include "jlong.h" @@ -117,9 +210,12 @@ static jfieldID attrs_st_mtime_nsec; static jfieldID attrs_st_ctime_sec; static jfieldID attrs_st_ctime_nsec; -#ifdef _DARWIN_FEATURE_64_BIT_INODE +#if defined(_DARWIN_FEATURE_64_BIT_INODE) || defined(__linux__) static jfieldID attrs_st_birthtime_sec; #endif +#if defined(__linux__) // Linux has nsec granularity if supported +static jfieldID attrs_st_birthtime_nsec; +#endif static jfieldID attrs_f_frsize; static jfieldID attrs_f_blocks; @@ -143,6 +239,10 @@ typedef int futimesat_func(int, const char *, const struct timeval *); typedef int futimens_func(int, const struct timespec *); typedef int lutimes_func(const char *, const struct timeval *); typedef DIR* fdopendir_func(int); +#if defined(__linux__) +typedef int statx_func(int dirfd, const char *restrict pathname, int flags, + unsigned int mask, struct my_statx *restrict statxbuf); +#endif static openat64_func* my_openat64_func = NULL; static fstatat64_func* my_fstatat64_func = NULL; @@ -152,6 +252,9 @@ static futimesat_func* my_futimesat_func = NULL; static futimens_func* my_futimens_func = NULL; static lutimes_func* my_lutimes_func = NULL; static fdopendir_func* my_fdopendir_func = NULL; +#if defined(__linux__) +static statx_func* my_statx_func = NULL; +#endif /** * fstatat missing from glibc on Linux. @@ -177,6 +280,13 @@ static int fstatat64_wrapper(int dfd, const char *path, } #endif +#if defined(__linux__) +static int statx_wrapper(int dirfd, const char *restrict pathname, int flags, + unsigned int mask, struct my_statx *restrict statxbuf) { + return (*my_statx_func)(dirfd, pathname, flags, mask, statxbuf); +} +#endif + /** * Call this to throw an internal UnixException when a system/library * call fails @@ -229,10 +339,14 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) attrs_st_ctime_nsec = (*env)->GetFieldID(env, clazz, "st_ctime_nsec", "J"); CHECK_NULL_RETURN(attrs_st_ctime_nsec, 0); -#ifdef _DARWIN_FEATURE_64_BIT_INODE +#if defined(_DARWIN_FEATURE_64_BIT_INODE) || defined(__linux__) attrs_st_birthtime_sec = (*env)->GetFieldID(env, clazz, "st_birthtime_sec", "J"); CHECK_NULL_RETURN(attrs_st_birthtime_sec, 0); #endif +#if defined (__linux__) // Linux has nsec granularity + attrs_st_birthtime_nsec = (*env)->GetFieldID(env, clazz, "st_birthtime_nsec", "J"); + CHECK_NULL_RETURN(attrs_st_birthtime_nsec, 0); +#endif clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes"); CHECK_NULL_RETURN(clazz, 0); @@ -314,6 +428,12 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) #ifdef _DARWIN_FEATURE_64_BIT_INODE capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_BIRTHTIME; #endif +#if defined(__linux__) + my_statx_func = (statx_func*) dlsym(RTLD_DEFAULT, "statx"); + if (my_statx_func != NULL) { + capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_BIRTHTIME; + } +#endif /* supports extended attributes */ @@ -490,10 +610,37 @@ Java_sun_nio_fs_UnixNativeDispatcher_write0(JNIEnv* env, jclass this, jint fd, return (jint)n; } +#if defined(__linux__) +/** + * Copy statx members into sun.nio.fs.UnixFileAttributes + */ +static void copy_statx_attributes(JNIEnv* env, struct my_statx* buf, jobject attrs) { + (*env)->SetIntField(env, attrs, attrs_st_mode, (jint)buf->stx_mode); + (*env)->SetLongField(env, attrs, attrs_st_ino, (jlong)buf->stx_ino); + (*env)->SetIntField(env, attrs, attrs_st_nlink, (jint)buf->stx_nlink); + (*env)->SetIntField(env, attrs, attrs_st_uid, (jint)buf->stx_uid); + (*env)->SetIntField(env, attrs, attrs_st_gid, (jint)buf->stx_gid); + (*env)->SetLongField(env, attrs, attrs_st_size, (jlong)buf->stx_size); + (*env)->SetLongField(env, attrs, attrs_st_atime_sec, (jlong)buf->stx_atime.tv_sec); + (*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->stx_mtime.tv_sec); + (*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->stx_ctime.tv_sec); + (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->stx_btime.tv_sec); + (*env)->SetLongField(env, attrs, attrs_st_birthtime_nsec, (jlong)buf->stx_btime.tv_nsec); + (*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->stx_atime.tv_nsec); + (*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->stx_mtime.tv_nsec); + (*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->stx_ctime.tv_nsec); + // convert statx major:minor to dev_t using makedev + dev_t dev = makedev(buf->stx_dev_major, buf->stx_dev_minor); + dev_t rdev = makedev(buf->stx_rdev_major, buf->stx_rdev_minor); + (*env)->SetLongField(env, attrs, attrs_st_dev, (jlong)dev); + (*env)->SetLongField(env, attrs, attrs_st_rdev, (jlong)rdev); +} +#endif + /** * Copy stat64 members into sun.nio.fs.UnixFileAttributes */ -static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) { +static void copy_stat64_attributes(JNIEnv* env, struct stat64* buf, jobject attrs) { (*env)->SetIntField(env, attrs, attrs_st_mode, (jint)buf->st_mode); (*env)->SetLongField(env, attrs, attrs_st_ino, (jlong)buf->st_ino); (*env)->SetLongField(env, attrs, attrs_st_dev, (jlong)buf->st_dev); @@ -508,6 +655,7 @@ static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) { #ifdef _DARWIN_FEATURE_64_BIT_INODE (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->st_birthtime); + // rely on default value of 0 for st_birthtime_nsec field on Darwin #endif #ifndef MACOSX @@ -528,10 +676,25 @@ Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this, int err; struct stat64 buf; const char* path = (const char*)jlong_to_ptr(pathAddress); - +#if defined(__linux__) + struct my_statx statx_buf; + int flags = AT_STATX_SYNC_AS_STAT; + unsigned int mask = STATX_ALL; + + if (my_statx_func != NULL) { + // Prefer statx over stat64 on Linux if it's available + RESTARTABLE(statx_wrapper(AT_FDCWD, path, flags, mask, &statx_buf), err); + if (err == 0) { + copy_statx_attributes(env, &statx_buf, attrs); + return 0; + } else { + return errno; + } + } +#endif RESTARTABLE(stat64(path, &buf), err); if (err == 0) { - prepAttributes(env, &buf, attrs); + copy_stat64_attributes(env, &buf, attrs); return 0; } else { return errno; @@ -545,12 +708,28 @@ Java_sun_nio_fs_UnixNativeDispatcher_lstat0(JNIEnv* env, jclass this, int err; struct stat64 buf; const char* path = (const char*)jlong_to_ptr(pathAddress); - +#if defined(__linux__) + struct my_statx statx_buf; + int flags = AT_STATX_SYNC_AS_STAT | AT_SYMLINK_NOFOLLOW; + unsigned int mask = STATX_ALL; + + if (my_statx_func != NULL) { + // Prefer statx over stat64 on Linux if it's available + RESTARTABLE(statx_wrapper(AT_FDCWD, path, flags, mask, &statx_buf), err); + if (err == 0) { + copy_statx_attributes(env, &statx_buf, attrs); + } else { + throwUnixException(env, errno); + } + // statx was available, so return now + return; + } +#endif RESTARTABLE(lstat64(path, &buf), err); if (err == -1) { throwUnixException(env, errno); } else { - prepAttributes(env, &buf, attrs); + copy_stat64_attributes(env, &buf, attrs); } } @@ -560,12 +739,29 @@ Java_sun_nio_fs_UnixNativeDispatcher_fstat0(JNIEnv* env, jclass this, jint fd, { int err; struct stat64 buf; - +#if defined(__linux__) + struct my_statx statx_buf; + int flags = AT_EMPTY_PATH | AT_STATX_SYNC_AS_STAT; + unsigned int mask = STATX_ALL; + + if (my_statx_func != NULL) { + // statx supports FD use via dirfd iff pathname is an empty string and the + // AT_EMPTY_PATH flag is specified in flags + RESTARTABLE(statx_wrapper((int)fd, "", flags, mask, &statx_buf), err); + if (err == 0) { + copy_statx_attributes(env, &statx_buf, attrs); + } else { + throwUnixException(env, errno); + } + // statx was available, so return now + return; + } +#endif RESTARTABLE(fstat64((int)fd, &buf), err); if (err == -1) { throwUnixException(env, errno); } else { - prepAttributes(env, &buf, attrs); + copy_stat64_attributes(env, &buf, attrs); } } @@ -576,6 +772,26 @@ Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd int err; struct stat64 buf; const char* path = (const char*)jlong_to_ptr(pathAddress); +#if defined(__linux__) + struct my_statx statx_buf; + int flags = AT_STATX_SYNC_AS_STAT; + unsigned int mask = STATX_ALL; + + if (my_statx_func != NULL) { + // Prefer statx over stat64 on Linux if it's available + if (((int)flag & AT_SYMLINK_NOFOLLOW) > 0) { // flag set in java code + flags |= AT_SYMLINK_NOFOLLOW; + } + RESTARTABLE(statx_wrapper((int)dfd, path, flags, mask, &statx_buf), err); + if (err == 0) { + copy_statx_attributes(env, &statx_buf, attrs); + } else { + throwUnixException(env, errno); + } + // statx was available, so return now + return; + } +#endif if (my_fstatat64_func == NULL) { JNU_ThrowInternalError(env, "should not reach here"); @@ -585,7 +801,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd if (err == -1) { throwUnixException(env, errno); } else { - prepAttributes(env, &buf, attrs); + copy_stat64_attributes(env, &buf, attrs); } } diff --git a/src/java.base/windows/native/libjava/FileDescriptor_md.c b/src/java.base/windows/native/libjava/FileDescriptor_md.c index cae8e395ff0d7..f0a20cf0553f9 100644 --- a/src/java.base/windows/native/libjava/FileDescriptor_md.c +++ b/src/java.base/windows/native/libjava/FileDescriptor_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ Java_java_io_FileDescriptor_initIDs(JNIEnv *env, jclass fdClass) { */ JNIEXPORT void JNICALL -Java_java_io_FileDescriptor_sync(JNIEnv *env, jobject this) { +Java_java_io_FileDescriptor_sync0(JNIEnv *env, jobject this) { FD fd = THIS_FD(this); if (IO_Sync(fd) == -1) { JNU_ThrowByName(env, "java/io/SyncFailedException", "sync failed"); diff --git a/src/java.base/windows/native/libjava/canonicalize_md.c b/src/java.base/windows/native/libjava/canonicalize_md.c index 1ec990ff5a439..ecfdf63d09162 100644 --- a/src/java.base/windows/native/libjava/canonicalize_md.c +++ b/src/java.base/windows/native/libjava/canonicalize_md.c @@ -138,7 +138,8 @@ lastErrorReportable() || (errval == ERROR_BAD_NET_NAME) || (errval == ERROR_ACCESS_DENIED) || (errval == ERROR_NETWORK_UNREACHABLE) - || (errval == ERROR_NETWORK_ACCESS_DENIED)) { + || (errval == ERROR_NETWORK_ACCESS_DENIED) + || (errval == ERROR_NO_MORE_FILES)) { return 0; } return 1; diff --git a/src/java.base/windows/native/libjli/cmdtoargs.c b/src/java.base/windows/native/libjli/cmdtoargs.c index 9bbbdaf986529..548e70b9bbf7e 100644 --- a/src/java.base/windows/native/libjli/cmdtoargs.c +++ b/src/java.base/windows/native/libjli/cmdtoargs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -324,6 +324,10 @@ class Vector { bool check() { // "pgmname" rest of cmdline ie. pgmname + 2 double quotes + space + cmdline from windows char* cptr = (char*) malloc(strlen(argv[0]) + sizeof(char) * 3 + strlen(cmdline) + 1); + if (cptr == NULL) { + printf("*** cannot allocate memory\n"); + doabort(); + } _snprintf(cptr, MAX_PATH, "\"%s\" %s", argv[0], cmdline); JLI_CmdToArgs(cptr); free(cptr); diff --git a/src/java.base/windows/native/libnet/DefaultProxySelector.c b/src/java.base/windows/native/libnet/DefaultProxySelector.c index 6b91874eda1d3..06bc70114f335 100644 --- a/src/java.base/windows/native/libnet/DefaultProxySelector.c +++ b/src/java.base/windows/native/libnet/DefaultProxySelector.c @@ -239,7 +239,7 @@ Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env, if (use_auto_proxy) { WCHAR url[MAX_STR_LEN]; /* Create url for WinHttpGetProxyForUrl */ - _snwprintf(url, sizeof(url) - 1, L"%s://%s", lpProto, lpHost); + swprintf(url, MAX_STR_LEN, L"%s://%s", lpProto, lpHost); /* Get proxy for URL from Windows */ use_auto_proxy = WinHttpGetProxyForUrl(session, &url[0], &auto_proxy_options, &proxy_info); if (use_auto_proxy) { diff --git a/src/java.base/windows/native/libnet/Inet4AddressImpl.c b/src/java.base/windows/native/libnet/Inet4AddressImpl.c index 97f3ef4e8e11c..0e2d6a3455f43 100644 --- a/src/java.base/windows/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/windows/native/libnet/Inet4AddressImpl.c @@ -232,7 +232,11 @@ tcp_ping4(JNIEnv *env, SOCKETADDRESS *sa, SOCKETADDRESS *netif, jint timeout, // set TTL if (ttl > 0) { - setsockopt(fd, IPPROTO_IP, IP_TTL, (const char *)&ttl, sizeof(ttl)); + if (setsockopt(fd, IPPROTO_IP, IP_TTL, (const char *)&ttl, sizeof(ttl)) == SOCKET_ERROR) { + NET_ThrowNew(env, WSAGetLastError(), "setsockopt IP_TTL failed"); + closesocket(fd); + return JNI_FALSE; + } } // A network interface was specified, so let's bind to it. diff --git a/src/java.base/windows/native/libnet/Inet6AddressImpl.c b/src/java.base/windows/native/libnet/Inet6AddressImpl.c index 324024c842ec2..244e2fefa9b1f 100644 --- a/src/java.base/windows/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/windows/native/libnet/Inet6AddressImpl.c @@ -310,7 +310,11 @@ tcp_ping6(JNIEnv *env, SOCKETADDRESS *sa, SOCKETADDRESS *netif, jint timeout, // set TTL if (ttl > 0) { - setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char *)&ttl, sizeof(ttl)); + if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char *)&ttl, sizeof(ttl)) == SOCKET_ERROR) { + NET_ThrowNew(env, WSAGetLastError(), "setsockopt IPV6_UNICAST_HOPS failed"); + closesocket(fd); + return JNI_FALSE; + } } // A network interface was specified, so let's bind to it. diff --git a/src/java.base/windows/native/libnio/ch/DatagramChannelImpl.c b/src/java.base/windows/native/libnio/ch/DatagramChannelImpl.c index 25c0370f66e86..54a4133a3b226 100644 --- a/src/java.base/windows/native/libnio/ch/DatagramChannelImpl.c +++ b/src/java.base/windows/native/libnio/ch/DatagramChannelImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,7 +89,7 @@ Java_sun_nio_ch_DatagramChannelImpl_disconnect0(JNIEnv *env, jclass clazz, rv = connect((SOCKET)fd, &sa.sa, sa_len); if (rv == SOCKET_ERROR) { - handleSocketError(env, WSAGetLastError()); + NET_ThrowNew(env, WSAGetLastError(), "connect"); } else { /* Disable WSAECONNRESET errors as socket is no longer connected */ BOOL enable = FALSE; @@ -136,7 +136,10 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jclass clazz, } } else if (theErr == WSAEWOULDBLOCK) { return IOS_UNAVAILABLE; - } else return handleSocketError(env, theErr); + } else { + NET_ThrowNew(env, theErr, "recvfrom"); + return IOS_THROWN; + } } } while (retry); @@ -160,7 +163,8 @@ Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jclass clazz, if (theErr == WSAEWOULDBLOCK) { return IOS_UNAVAILABLE; } - return handleSocketError(env, (jint)WSAGetLastError()); + NET_ThrowNew(env, (jint)WSAGetLastError(), "sendto"); + return IOS_THROWN; } return rv; } diff --git a/src/java.base/windows/native/libnio/ch/IOUtil.c b/src/java.base/windows/native/libnio/ch/IOUtil.c index 511fcdcadb260..850c237d9e908 100644 --- a/src/java.base/windows/native/libnio/ch/IOUtil.c +++ b/src/java.base/windows/native/libnio/ch/IOUtil.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -149,8 +149,7 @@ Java_sun_nio_ch_IOUtil_configureBlocking(JNIEnv *env, jclass clazz, } result = ioctlsocket(fd, FIONBIO, &argp); if (result == SOCKET_ERROR) { - int error = WSAGetLastError(); - handleSocketError(env, (jint)error); + NET_ThrowNew(env, WSAGetLastError(), "ioctlsocket"); } } diff --git a/src/java.base/windows/native/libnio/ch/Net.c b/src/java.base/windows/native/libnio/ch/Net.c index 41a08666d42cd..3ccdbcc4752c6 100644 --- a/src/java.base/windows/native/libnio/ch/Net.c +++ b/src/java.base/windows/native/libnio/ch/Net.c @@ -77,12 +77,6 @@ static void setConnectionReset(SOCKET s, BOOL enable) { NULL, 0, &bytesReturned, NULL, NULL); } -jint handleSocketError(JNIEnv *env, int errorValue) -{ - NET_ThrowNew(env, errorValue, NULL); - return IOS_THROWN; -} - static jclass isa_class; /* java.net.InetSocketAddress */ static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */ @@ -162,7 +156,7 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, if (s != INVALID_SOCKET) { SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0); - /* IPV6_V6ONLY is true by default */ + /* Attempt to disable IPV6_V6ONLY to ensure dual-socket support; ignore errors */ if (domain == AF_INET6) { int opt = 0; setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, @@ -392,7 +386,7 @@ Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); } if (n == SOCKET_ERROR) { - handleSocketError(env, WSAGetLastError()); + NET_ThrowNew(env, WSAGetLastError(), "getsockopt"); return IOS_THROWN; } @@ -436,7 +430,7 @@ Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, n = setsockopt(fdval(env, fdo), level, opt, parg, arglen); } if (n == SOCKET_ERROR) - handleSocketError(env, WSAGetLastError()); + NET_ThrowNew(env, WSAGetLastError(), "setsocketopt"); } JNIEXPORT jint JNICALL @@ -467,7 +461,7 @@ Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobjec if (n == SOCKET_ERROR) { if (join && (WSAGetLastError() == WSAENOPROTOOPT)) return IOS_UNAVAILABLE; - handleSocketError(env, WSAGetLastError()); + NET_ThrowNew(env, WSAGetLastError(), "setsocketopt"); } return 0; } @@ -489,7 +483,7 @@ Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, j if (n == SOCKET_ERROR) { if (block && (WSAGetLastError() == WSAENOPROTOOPT)) return IOS_UNAVAILABLE; - handleSocketError(env, WSAGetLastError()); + NET_ThrowNew(env, WSAGetLastError(), "setsockopt"); } return 0; } @@ -542,7 +536,7 @@ Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobjec } if (n == SOCKET_ERROR) { - handleSocketError(env, WSAGetLastError()); + NET_ThrowNew(env, WSAGetLastError(), "setsockopt"); } return 0; } @@ -554,7 +548,7 @@ Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, j int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE; int n = setGroupSourceReqOption(env, fdo, opt, group, index, source); if (n == SOCKET_ERROR) { - handleSocketError(env, WSAGetLastError()); + NET_ThrowNew(env, WSAGetLastError(), "setsocketopt to block or unblock source"); } return 0; } @@ -571,7 +565,7 @@ Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint i n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&(in.s_addr), arglen); if (n == SOCKET_ERROR) { - handleSocketError(env, WSAGetLastError()); + NET_ThrowNew(env, WSAGetLastError(), "setsockopt"); } } @@ -584,7 +578,7 @@ Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo) n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen); if (n == SOCKET_ERROR) { - handleSocketError(env, WSAGetLastError()); + NET_ThrowNew(env, WSAGetLastError(), "getsockopt"); return IOS_THROWN; } return ntohl(in.s_addr); @@ -600,7 +594,7 @@ Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint i n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&(index), arglen); if (n == SOCKET_ERROR) { - handleSocketError(env, WSAGetLastError()); + NET_ThrowNew(env, WSAGetLastError(), "setsockopt"); } } @@ -613,7 +607,7 @@ Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo) n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen); if (n == SOCKET_ERROR) { - handleSocketError(env, WSAGetLastError()); + NET_ThrowNew(env, WSAGetLastError(), "getsockopt"); return -1; } return (jint)index; @@ -631,12 +625,12 @@ Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) { JNIEXPORT jint JNICALL Java_sun_nio_ch_Net_available(JNIEnv *env, jclass cl, jobject fdo) { - int count = 0; - if (NET_SocketAvailable(fdval(env, fdo), &count) != 0) { - handleSocketError(env, WSAGetLastError()); + u_long arg; + if (ioctlsocket((SOCKET) fdval(env, fdo), FIONREAD, &arg) == SOCKET_ERROR) { + NET_ThrowNew(env, WSAGetLastError(), "ioctlsocket"); return IOS_THROWN; } - return (jint) count; + return (jint) arg; } JNIEXPORT jint JNICALL @@ -667,7 +661,7 @@ Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlo /* save last winsock error */ if (rv == SOCKET_ERROR) { - handleSocketError(env, WSAGetLastError()); + NET_ThrowNew(env, WSAGetLastError(), "select"); return IOS_THROWN; } else if (rv >= 0) { rv = 0; @@ -707,7 +701,7 @@ Java_sun_nio_ch_Net_pollConnect(JNIEnv* env, jclass this, jobject fdo, jlong tim result = select(fd+1, 0, &wr, &ex, (timeout >= 0) ? &t : NULL); if (result == SOCKET_ERROR) { - handleSocketError(env, WSAGetLastError()); + NET_ThrowNew(env, WSAGetLastError(), "select"); return JNI_FALSE; } else if (result == 0) { return JNI_FALSE; @@ -727,7 +721,7 @@ Java_sun_nio_ch_Net_pollConnect(JNIEnv* env, jclass this, jobject fdo, jlong tim NET_ThrowNew(env, lastError, "getsockopt"); } } else if (optError != NO_ERROR) { - handleSocketError(env, optError); + NET_ThrowNew(env, optError, "getsockopt"); } return JNI_FALSE; } diff --git a/src/java.base/windows/native/libnio/ch/UnixDomainSockets.c b/src/java.base/windows/native/libnio/ch/UnixDomainSockets.c index aaf8996155cbc..bc185b3aa185b 100644 --- a/src/java.base/windows/native/libnio/ch/UnixDomainSockets.c +++ b/src/java.base/windows/native/libnio/ch/UnixDomainSockets.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,6 +118,9 @@ Java_sun_nio_ch_UnixDomainSockets_init(JNIEnv *env, jclass cl) if (result == SOCKET_ERROR) { if (GetLastError() == WSAENOBUFS) { infoPtr = (LPWSAPROTOCOL_INFOW)malloc(len); + if (infoPtr == NULL) { + return JNI_FALSE; + } result = WSAEnumProtocolsW(0, infoPtr, &len); if (result == SOCKET_ERROR) { free(infoPtr); @@ -158,7 +161,8 @@ Java_sun_nio_ch_UnixDomainSockets_socket0(JNIEnv *env, jclass cl) { SOCKET s = WSASocketW(PF_UNIX, SOCK_STREAM, 0, &provider, 0, WSA_FLAG_OVERLAPPED); if (s == INVALID_SOCKET) { - return handleSocketError(env, WSAGetLastError()); + NET_ThrowNew(env, WSAGetLastError(), "WSASocketW"); + return IOS_THROWN; } SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0); return (int)s; diff --git a/src/java.base/windows/native/libnio/ch/WindowsAsynchronousServerSocketChannelImpl.c b/src/java.base/windows/native/libnio/ch/WindowsAsynchronousServerSocketChannelImpl.c index 340bbb9c8decc..2c6de95ac65f4 100644 --- a/src/java.base/windows/native/libnio/ch/WindowsAsynchronousServerSocketChannelImpl.c +++ b/src/java.base/windows/native/libnio/ch/WindowsAsynchronousServerSocketChannelImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,7 +131,9 @@ Java_sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl_updateAcceptContext(J SOCKET s1 = (SOCKET)jlong_to_ptr(listenSocket); SOCKET s2 = (SOCKET)jlong_to_ptr(acceptSocket); - setsockopt(s2, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&s1, sizeof(s1)); + if (setsockopt(s2, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&s1, sizeof(s1)) == SOCKET_ERROR) { + JNU_ThrowIOExceptionWithLastError(env, "setsockopt failed"); + } } diff --git a/src/java.base/windows/native/libnio/ch/WindowsAsynchronousSocketChannelImpl.c b/src/java.base/windows/native/libnio/ch/WindowsAsynchronousSocketChannelImpl.c index 6b1fa64e70861..b325c34c9d851 100644 --- a/src/java.base/windows/native/libnio/ch/WindowsAsynchronousSocketChannelImpl.c +++ b/src/java.base/windows/native/libnio/ch/WindowsAsynchronousSocketChannelImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -123,7 +123,9 @@ Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_updateConnectContext(JNIEnv jlong socket) { SOCKET s = (SOCKET)jlong_to_ptr(socket); - setsockopt(s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0); + if (setsockopt(s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == SOCKET_ERROR) { + JNU_ThrowIOExceptionWithLastError(env, "setsockopt failed"); + } } diff --git a/src/java.base/windows/native/libnio/ch/nio_util.h b/src/java.base/windows/native/libnio/ch/nio_util.h index a4506d93d217d..b90e0ac63d5c2 100644 --- a/src/java.base/windows/native/libnio/ch/nio_util.h +++ b/src/java.base/windows/native/libnio/ch/nio_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,6 @@ jlong handleval(JNIEnv *env, jobject fdo); jint convertReturnVal(JNIEnv *env, jint n, jboolean r); jlong convertLongReturnVal(JNIEnv *env, jlong n, jboolean r); jboolean purgeOutstandingICMP(JNIEnv *env, jclass clazz, jint fd); -jint handleSocketError(JNIEnv *env, int errorValue); #ifdef _WIN64 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 8a86b86f80ee5..dab893252cfdb 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java @@ -338,20 +338,10 @@ public void paint(final Graphics g, final JComponent c) { } // performs icon and text rect calculations - final String text; - final Icon icon = b.getIcon(); - final View v = (View)c.getClientProperty(BasicHTML.propertyKey); - if (v != null && icon == null) { - // use zero insets for HTML without an icon - // since layout only handles text calculations - text = layoutAndGetText(g, b, aquaBorder, new Insets(0,0,0,0), - viewRect, iconRect, textRect); - } else { - text = layoutAndGetText(g, b, aquaBorder, i, viewRect, iconRect, textRect); - } + final String text = layoutAndGetText(g, b, aquaBorder, i, viewRect, iconRect, textRect); // Paint the Icon - if (icon != null) { + if (b.getIcon() != null) { paintIcon(g, b, iconRect); } @@ -360,6 +350,7 @@ public void paint(final Graphics g, final JComponent c) { } if (text != null && !text.isEmpty()) { + final View v = (View)c.getClientProperty(BasicHTML.propertyKey); if (v != null) { v.paint(g, textRect); } else { diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java index 67c8f184eccbe..d4526324c585a 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java @@ -36,6 +36,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.annotation.Native; +import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashSet; @@ -63,6 +64,7 @@ import javax.swing.JList; import javax.swing.JTree; import javax.swing.KeyStroke; +import javax.swing.tree.TreePath; import sun.awt.AWTAccessor; import sun.lwawt.LWWindowPeer; @@ -757,14 +759,75 @@ private static Object[] getChildrenAndRolesImpl(Accessible a, Component c, int w return new Object[]{childrenAndRoles.get(whichChildren * 2), childrenAndRoles.get((whichChildren * 2) + 1)}; } + private static Accessible createAccessibleTreeNode(JTree t, TreePath p) { + Accessible a = null; + + try { + Class accessibleJTreeNodeClass = Class.forName("javax.swing.JTree$AccessibleJTree$AccessibleJTreeNode"); + Constructor constructor = accessibleJTreeNodeClass.getConstructor(t.getAccessibleContext().getClass(), JTree.class, TreePath.class, Accessible.class); + constructor.setAccessible(true); + a = ((Accessible) constructor.newInstance(t.getAccessibleContext(), t, p, null)); + } catch (Exception e) { + e.printStackTrace(); + } + + return a; + } + // This method is called from the native // Each child takes up three entries in the array: one for itself, one for its role, and one for the recursion level private static Object[] getChildrenAndRolesRecursive(final Accessible a, final Component c, final int whichChildren, final boolean allowIgnored, final int level) { if (a == null) return null; return invokeAndWait(new Callable() { public Object[] call() throws Exception { - ArrayList currentLevelChildren = new ArrayList(); ArrayList allChildren = new ArrayList(); + + Accessible at = null; + if (a instanceof CAccessible) { + at = CAccessible.getSwingAccessible(a); + } else { + at = a; + } + + if (at instanceof JTree) { + JTree tree = ((JTree) at); + + if (whichChildren == JAVA_AX_ALL_CHILDREN) { + int count = tree.getRowCount(); + for (int i = 0; i < count; i++) { + TreePath path = tree.getPathForRow(i); + Accessible an = createAccessibleTreeNode(tree, path); + if (an != null) { + AccessibleContext ac = an.getAccessibleContext(); + if (ac != null) { + allChildren.add(an); + allChildren.add(ac.getAccessibleRole());; + allChildren.add(String.valueOf((tree.isRootVisible() ? path.getPathCount() : path.getPathCount() - 1))); + } + } + } + } + + if (whichChildren == JAVA_AX_SELECTED_CHILDREN) { + int count = tree.getSelectionCount(); + for (int i = 0; i < count; i++) { + TreePath path = tree.getSelectionPaths()[i]; + Accessible an = createAccessibleTreeNode(tree, path); + if (an != null) { + AccessibleContext ac = an.getAccessibleContext(); + if (ac != null) { + allChildren.add(an); + allChildren.add(ac.getAccessibleRole()); + allChildren.add(String.valueOf((tree.isRootVisible() ? path.getPathCount() : path.getPathCount() - 1))); + } + } + } + } + + return allChildren.toArray(); + } + + ArrayList currentLevelChildren = new ArrayList(); ArrayList parentStack = new ArrayList(); parentStack.add(a); ArrayList indexses = new ArrayList(); diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java index 6fcdc07fefe45..779423bc28fc0 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java @@ -185,6 +185,12 @@ public void propertyChange(PropertyChangeEvent e) { if (newValue != null && !newValue.equals(oldValue)) { valueChanged(ptr); } + + // Notify native side to handle check box style menuitem + if (parentRole == AccessibleRole.POPUP_MENU && newValue != null + && ((AccessibleState)newValue) == AccessibleState.FOCUSED) { + menuItemSelected(ptr); + } } // Do send radio button state changes to native side @@ -192,6 +198,12 @@ public void propertyChange(PropertyChangeEvent e) { if (newValue != null && !newValue.equals(oldValue)) { valueChanged(ptr); } + + // Notify native side to handle radio button style menuitem + if (parentRole == AccessibleRole.POPUP_MENU && newValue != null + && ((AccessibleState)newValue) == AccessibleState.FOCUSED) { + menuItemSelected(ptr); + } } // Do send toggle button state changes to native side 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 01aff8987aea9..625494efc999f 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java @@ -45,6 +45,7 @@ import javax.print.attribute.standard.MediaSize; import javax.print.attribute.standard.MediaSizeName; import javax.print.attribute.standard.PageRanges; +import javax.print.attribute.standard.Sides; import javax.print.attribute.Attribute; import sun.java2d.*; @@ -684,6 +685,24 @@ private Rectangle2D getPageFormatArea(PageFormat page) { return pageFormatArea; } + private int getSides() { + return (this.sidesAttr == null) ? -1 : this.sidesAttr.getValue(); + } + + private void setSides(int sides) { + if (attributes == null) { + return; + } + + final Sides[] sidesTable = new Sides[] {Sides.ONE_SIDED, Sides.TWO_SIDED_LONG_EDGE, Sides.TWO_SIDED_SHORT_EDGE}; + + if (sides >= 0 && sides < sidesTable.length) { + Sides s = sidesTable[sides]; + attributes.add(s); + this.sidesAttr = s; + } + } + private boolean cancelCheck() { // This is called from the native side. diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m index 2c1c4a5e46752..9cbd48bf843fb 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m @@ -37,6 +37,10 @@ #import "GeomUtilities.h" #import "JNIUtilities.h" +#define ONE_SIDED 0 +#define TWO_SIDED_LONG_EDGE 1 +#define TWO_SIDED_SHORT_EDGE 2 + static jclass sjc_Paper = NULL; static jclass sjc_PageFormat = NULL; static jclass sjc_CPrinterJob = NULL; @@ -351,6 +355,24 @@ static void javaPageFormatToNSPrintInfo(JNIEnv* env, jobject srcPrintJob, jobjec [dstPrintInfo setPrinter:printer]; } +static jint duplexModeToSides(PMDuplexMode duplexMode) { + switch(duplexMode) { + case kPMDuplexNone: return ONE_SIDED; + case kPMDuplexTumble: return TWO_SIDED_SHORT_EDGE; + case kPMDuplexNoTumble: return TWO_SIDED_LONG_EDGE; + default: return -1; + } +} + +static PMDuplexMode sidesToDuplexMode(jint sides) { + switch(sides) { + case ONE_SIDED: return kPMDuplexNone; + case TWO_SIDED_SHORT_EDGE: return kPMDuplexTumble; + case TWO_SIDED_LONG_EDGE: return kPMDuplexNoTumble; + default: return kPMDuplexNone; + } +} + static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject dstPrinterJob, jobject dstPageable) { GET_CPRINTERJOB_CLASS(); @@ -360,6 +382,7 @@ static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject d DECLARE_METHOD(jm_setPageRangeAttribute, sjc_CPrinterJob, "setPageRangeAttribute", "(IIZ)V"); DECLARE_METHOD(jm_setPrintToFile, sjc_CPrinterJob, "setPrintToFile", "(Z)V"); DECLARE_METHOD(jm_setDestinationFile, sjc_CPrinterJob, "setDestinationFile", "(Ljava/lang/String;)V"); + DECLARE_METHOD(jm_setSides, sjc_CPrinterJob, "setSides", "(I)V"); // get the selected printer's name, and set the appropriate PrintService on the Java side NSString *name = [[src printer] name]; @@ -420,6 +443,12 @@ static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject d jFirstPage, jLastPage, isRangeSet); // AWT_THREADING Safe (known object) CHECK_EXCEPTION(); + PMDuplexMode duplexSetting; + if (PMGetDuplex(src.PMPrintSettings, &duplexSetting) == noErr) { + jint sides = duplexModeToSides(duplexSetting); + (*env)->CallVoidMethod(env, dstPrinterJob, jm_setSides, sides); // AWT_THREADING Safe (known object) + CHECK_EXCEPTION(); + } } } @@ -438,6 +467,8 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj DECLARE_METHOD(jm_getNumberOfPages, jc_Pageable, "getNumberOfPages", "()I"); DECLARE_METHOD(jm_getPageFormat, sjc_CPrinterJob, "getPageFormatFromAttributes", "()Ljava/awt/print/PageFormat;"); DECLARE_METHOD(jm_getDestinationFile, sjc_CPrinterJob, "getDestinationFile", "()Ljava/lang/String;"); + DECLARE_METHOD(jm_getSides, sjc_CPrinterJob, "getSides", "()I"); + NSMutableDictionary* printingDictionary = [dst dictionary]; @@ -496,6 +527,17 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj } else { [dst setJobDisposition:NSPrintSpoolJob]; } + + jint sides = (*env)->CallIntMethod(env, srcPrinterJob, jm_getSides); + CHECK_EXCEPTION(); + + if (sides >= 0) { + PMDuplexMode duplexMode = sidesToDuplexMode(sides); + PMPrintSettings printSettings = dst.PMPrintSettings; + if (PMSetDuplex(printSettings, duplexMode) == noErr) { + [dst updateFromPMPrintSettings]; + } + } } /* diff --git a/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java b/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java index a207d69c3551a..6447e654f600e 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -32,6 +32,7 @@ import java.io.InputStreamReader; import java.net.URL; import java.net.URLClassLoader; +import java.security.AccessController; import java.util.ArrayList; import java.util.Objects; @@ -40,6 +41,7 @@ import javax.sound.midi.spi.SoundbankReader; import sun.reflect.misc.ReflectUtil; +import sun.security.action.GetBooleanAction; /** * JarSoundbankReader is used to read soundbank object from jar files. @@ -48,12 +50,15 @@ */ public final class JARSoundbankReader extends SoundbankReader { - /* - * Name of the system property that enables the Jar soundbank loading - * true if jar sound bank is allowed to be loaded - * default is false + /** + * Value of the system property that enables the Jar soundbank loading + * {@code true} if jar sound bank is allowed to be loaded default is + * {@code false}. */ - private final static String JAR_SOUNDBANK_ENABLED = "jdk.sound.jarsoundbank"; + @SuppressWarnings("removal") + private static final boolean JAR_SOUNDBANK_ENABLED = + AccessController.doPrivileged( + new GetBooleanAction("jdk.sound.jarsoundbank")); private static boolean isZIP(URL url) { boolean ok = false; @@ -78,7 +83,7 @@ private static boolean isZIP(URL url) { public Soundbank getSoundbank(URL url) throws InvalidMidiDataException, IOException { Objects.requireNonNull(url); - if (!Boolean.getBoolean(JAR_SOUNDBANK_ENABLED) || !isZIP(url)) + if (!JAR_SOUNDBANK_ENABLED || !isZIP(url)) return null; ArrayList soundbanks = new ArrayList<>(); 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 2618d0ecaed4f..ced1e634dbbb2 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -560,7 +560,7 @@ public BufferedImage createCompatibleDestImage (BufferedImage src, "Destination ColorSpace is undefined"); } ICC_Profile destProfile = profileList[nProfiles - 1]; - cs = new ICC_ColorSpace(destProfile); + cs = createCompatibleColorSpace(destProfile); } else { /* non-ICC case */ int nSpaces = CSList.length; @@ -570,6 +570,25 @@ public BufferedImage createCompatibleDestImage (BufferedImage src, return createCompatibleDestImage(src, destCM, cs); } + private static ColorSpace createCompatibleColorSpace(ICC_Profile profile) { + if (profile == ICC_Profile.getInstance(ColorSpace.CS_sRGB)) { + return ColorSpace.getInstance(ColorSpace.CS_sRGB); + } + if (profile == ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB)) { + return ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB); + } + if (profile == ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ)) { + return ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); + } + if (profile == ICC_Profile.getInstance(ColorSpace.CS_PYCC)) { + return ColorSpace.getInstance(ColorSpace.CS_PYCC); + } + if (profile == ICC_Profile.getInstance(ColorSpace.CS_GRAY)) { + return ColorSpace.getInstance(ColorSpace.CS_GRAY); + } + return new ICC_ColorSpace(profile); + } + private BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM, ColorSpace destCS) { diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicButtonUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicButtonUI.java index a334fe4f39022..c7c036e859fa6 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicButtonUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,6 @@ package javax.swing.plaf.basic; -import sun.awt.AppContext; -import sun.swing.SwingUtilities2; import java.awt.AWTKeyStroke; import java.awt.Component; import java.awt.Dimension; @@ -61,6 +59,9 @@ import javax.swing.plaf.UIResource; import javax.swing.text.View; +import sun.awt.AppContext; +import sun.swing.SwingUtilities2; + /** * BasicButton implementation * @@ -598,15 +599,7 @@ public Component.BaselineResizeBehavior getBaselineResizeBehavior( private String layout(AbstractButton b, FontMetrics fm, int width, int height) { - Insets i; - - final View v = (View)b.getClientProperty(BasicHTML.propertyKey); - if (v != null) { - i = new Insets(0, 0, 0, 0); - } else { - i = b.getInsets(); - } - + Insets i = b.getInsets(); viewRect.x = i.left; viewRect.y = i.top; viewRect.width = width - (i.right + viewRect.x); diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthGraphicsUtils.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthGraphicsUtils.java index 586b280120e96..487a90d51199a 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthGraphicsUtils.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthGraphicsUtils.java @@ -24,8 +24,6 @@ */ package javax.swing.plaf.synth; -import sun.swing.MenuItemLayoutHelper; -import sun.swing.SwingUtilities2; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; @@ -37,13 +35,15 @@ import javax.swing.ButtonModel; import javax.swing.Icon; -import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.SwingUtilities; import javax.swing.plaf.basic.BasicHTML; import javax.swing.text.View; +import sun.swing.MenuItemLayoutHelper; +import sun.swing.SwingUtilities2; + /** * Wrapper for primitive graphics calls. * @@ -392,19 +392,10 @@ public void paintText(SynthContext ss, Graphics g, String text, FontMetrics fm = SwingUtilities2.getFontMetrics(c, g); Insets insets = SynthLookAndFeel.getPaintingInsets(ss, paintInsets); - final View v = (View)c.getClientProperty(BasicHTML.propertyKey); - - if (c instanceof JButton && v != null) { - paintViewR.x = 0; - paintViewR.y = 0; - paintViewR.width = c.getWidth(); - paintViewR.height = c.getHeight(); - } else { - paintViewR.x = insets.left; - paintViewR.y = insets.top; - paintViewR.width = c.getWidth() - (insets.left + insets.right); - paintViewR.height = c.getHeight() - (insets.top + insets.bottom); - } + paintViewR.x = insets.left; + paintViewR.y = insets.top; + paintViewR.width = c.getWidth() - (insets.left + insets.right); + paintViewR.height = c.getHeight() - (insets.top + insets.bottom); paintIconR.x = paintIconR.y = paintIconR.width = paintIconR.height = 0; paintTextR.x = paintTextR.y = paintTextR.width = paintTextR.height = 0; @@ -430,6 +421,7 @@ public void paintText(SynthContext ss, Graphics g, String text, } if (text != null) { + View v = (View) c.getClientProperty(BasicHTML.propertyKey); if (v != null) { v.paint(g, paintTextR); } else { diff --git a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java index 259b63ed8eebc..05f45cc6bb0dc 100644 --- a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java +++ b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,10 @@ import java.io.*; import java.lang.*; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; /** * RTFParser is a subclass of AbstractFilter which understands basic RTF syntax @@ -69,6 +73,11 @@ abstract class RTFParser extends AbstractFilter private final int S_inblob = 6; // in a \bin blob + // For fcharset control word + protected CharsetDecoder decoder = null; + private byte[] ba = new byte[2]; + protected ByteBuffer decoderBB = ByteBuffer.wrap(ba); + /** Implemented by subclasses to interpret a parameter-less RTF keyword. * The keyword is passed without the leading '/' or any delimiting * whitespace. */ @@ -100,6 +109,9 @@ public void handleText(char ch) rtfSpecialsTable['\\'] = true; } + // Defined for replacement character + static final char REPLACEMENT_CHAR = '\uFFFD'; + public RTFParser() { currentCharacters = new StringBuffer(); @@ -109,6 +121,9 @@ public RTFParser() //warnings = System.out; specialsTable = rtfSpecialsTable; + // Initialize byte buffer for CharsetDecoder + decoderBB.clear(); + decoderBB.limit(1); } // TODO: Handle wrapup at end of file correctly. @@ -182,6 +197,9 @@ public void write(char ch) } state = S_backslashed; } else { + // SBCS: ASCII character + // DBCS: Non lead byte + ch = decode(ch); currentCharacters.append(ch); } break; @@ -301,7 +319,9 @@ public void write(char ch) if (Character.digit(ch, 16) != -1) { pendingCharacter = pendingCharacter * 16 + Character.digit(ch, 16); - ch = translationTable[pendingCharacter]; + // Use translationTable if decoder is not defined + ch = decoder == null ? translationTable[pendingCharacter] + : decode((char)pendingCharacter); if (ch != 0) handleText(ch); } @@ -360,4 +380,37 @@ public void close() super.close(); } + // For fcharset control word + private char[] ca = new char[1]; + private CharBuffer decoderCB = CharBuffer.wrap(ca); + + private char decode(char ch) { + if (decoder == null) return ch; + decoderBB.put((byte) ch); + decoderBB.rewind(); + decoderCB.clear(); + CoderResult cr = decoder.decode(decoderBB, decoderCB, false); + if (cr.isUnderflow()) { + if (decoderCB.position() == 1) { + // Converted to Unicode (including replacement character) + decoder.reset(); + decoderBB.clear(); + decoderBB.limit(1); + return ca[0]; + } else { + // Detected lead byte + decoder.reset(); + decoderBB.limit(2); + decoderBB.position(1); + return 0; // Skip write operation if return value is 0 + } + } else { + // Fallback, should not be called + decoder.reset(); + decoderBB.clear(); + decoderBB.limit(1); + return REPLACEMENT_CHAR; + } + } + } diff --git a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java index 9128a71ed01e9..60cfd585c732e 100644 --- a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java +++ b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,11 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.StreamTokenizer; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CodingErrorAction; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Dictionary; @@ -87,6 +92,10 @@ class RTFReader extends RTFParser /** This Dictionary maps Integer font numbers to String font names. */ Dictionary fontTable; + /** This Dictionary maps Integer font numbers to Charset font charset. */ + Dictionary fcharsetTable; + /** This Dictionary maps String font charset to String code page. */ + static Dictionary fcharsetToCP = null; /** This array maps color indices to Color objects. */ Color[] colorTable; /** This Map maps character style numbers to Style objects. */ @@ -133,6 +142,7 @@ class RTFReader extends RTFParser textKeywords.put("emspace", "\u2003"); textKeywords.put("endash", "\u2013"); textKeywords.put("enspace", "\u2002"); + textKeywords.put("line", "\n"); textKeywords.put("ldblquote", "\u201C"); textKeywords.put("lquote", "\u2018"); textKeywords.put("ltrmark", "\u200E"); @@ -159,7 +169,50 @@ class RTFReader extends RTFParser defineCharacterSet("ansicpg", latin1TranslationTable); } -/* TODO: per-font font encodings ( \fcharset control word ) ? */ + /** + * Windows font charset + */ + private static final int ANSI_CHARSET = 0; + private static final int DEFAULT_CHARSET = 1; + private static final int SYMBOL_CHARSET = 2; + private static final int MAC_CHARSET = 77; + private static final int SHIFTJIS_CHARSET = 128; + private static final int HANGUL_CHARSET = 129; + private static final int JOHAB_CHARSET = 130; + private static final int GB2312_CHARSET = 134; + private static final int CHINESEBIG5_CHARSET = 136; + private static final int GREEK_CHARSET = 161; + private static final int TURKISH_CHARSET = 162; + private static final int VIETNAMESE_CHARSET = 163; + private static final int HEBREW_CHARSET = 177; + private static final int ARABIC_CHARSET = 178; + private static final int BALTIC_CHARSET = 186; + private static final int RUSSIAN_CHARSET = 204; + private static final int THAI_CHARSET = 222; + private static final int EASTEUROPE_CHARSET = 238; + private static final int OEM_CHARSET = 255; + + static { + fcharsetToCP = new Hashtable(); + fcharsetToCP.put("fcharset" + ANSI_CHARSET, "windows-1252"); + fcharsetToCP.put("fcharset" + SHIFTJIS_CHARSET, "ms932"); + fcharsetToCP.put("fcharset" + HANGUL_CHARSET, "ms949"); + fcharsetToCP.put("fcharset" + JOHAB_CHARSET, "ms1361"); + fcharsetToCP.put("fcharset" + GB2312_CHARSET, "ms936"); + fcharsetToCP.put("fcharset" + CHINESEBIG5_CHARSET, "ms950"); + fcharsetToCP.put("fcharset" + GREEK_CHARSET, "windows-1253"); + fcharsetToCP.put("fcharset" + TURKISH_CHARSET, "windows-1254"); + fcharsetToCP.put("fcharset" + VIETNAMESE_CHARSET, "windows-1258"); + fcharsetToCP.put("fcharset" + HEBREW_CHARSET, "windows-1255"); + fcharsetToCP.put("fcharset" + ARABIC_CHARSET, "windows-1256"); + fcharsetToCP.put("fcharset" + BALTIC_CHARSET, "windows-1257"); + fcharsetToCP.put("fcharset" + RUSSIAN_CHARSET, "windows-1251"); + fcharsetToCP.put("fcharset" + THAI_CHARSET, "ms874"); + fcharsetToCP.put("fcharset" + EASTEUROPE_CHARSET, "windows-1250"); + } + + // Defined for replacement character + private static final String REPLACEMENT_CHAR = "\uFFFD"; /** * Creates a new RTFReader instance. Text will be sent to @@ -174,6 +227,7 @@ public RTFReader(StyledDocument destination) target = destination; parserState = new Hashtable(); fontTable = new Hashtable(); + fcharsetTable = new Hashtable(); rtfversion = -1; @@ -762,6 +816,25 @@ public boolean handleKeyword(String keyword, int parameter) nextFontNumber = parameter; return true; } + // For fcharset control word + if (keyword.equals("fcharset")) { + String fcharset = keyword+parameter; + String csName = fcharsetToCP.get(fcharset); + Charset cs; + if (csName != null) { + try { + cs = Charset.forName(csName); + } catch (IllegalArgumentException iae) { + // Fallback, should not be called + cs = ISO_8859_1; + } + } else { + // Fallback, fcharset control word number is not defined + cs = ISO_8859_1; + } + fcharsetTable.put(nextFontNumber, cs); + return true; + } return false; } @@ -1216,6 +1289,25 @@ public boolean handleKeyword(String keyword, int parameter) if (keyword.equals("f")) { parserState.put(keyword, Integer.valueOf(parameter)); + + // Check lead byte is stored or not + if (decoderBB.position() == 1) { + handleText(REPLACEMENT_CHAR); + } + // Reset decoder byte buffer + decoderBB.clear(); + decoderBB.limit(1); + // Check fcharset is used or not + Charset cs = fcharsetTable.get(parameter); + if (cs != null) { + decoder = cs.newDecoder(); + decoder.onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + } else { + // fcharset is not used, use translationTable + decoder = null; + } + return true; } if (keyword.equals("cf")) { @@ -1610,6 +1702,12 @@ public boolean handleKeyword(String keyword) if (keyword.equals("par")) { // warnings.println("Ending paragraph."); + // Check lead byte is stored or not + if (decoderBB.position() == 1) { + handleText(REPLACEMENT_CHAR); + decoderBB.clear(); + decoderBB.limit(1); + } endParagraph(); return true; } diff --git a/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java b/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java index 54d80f6033bbd..a8a342af262a7 100644 --- a/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java +++ b/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java @@ -557,6 +557,7 @@ Renderer init(final int pix_boundsX, final int pix_boundsY, final int pix_boundsWidth, final int pix_boundsHeight, final int windingRule) { + this.rdrCtx.doRender = true; this.windingRule = windingRule; // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY diff --git a/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java b/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java index d599c7d035f0b..b258f4e25d823 100644 --- a/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java +++ b/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java @@ -78,6 +78,8 @@ static RendererContext createContext() { final MarlinCache cache; // flag indicating the shape is stroked (1) or filled (0) int stroking = 0; + // flag indicating to render the shape + boolean doRender = false; // flag indicating to clip the shape boolean doClip = false; // flag indicating if the path is closed or not (in advance) to handle properly caps @@ -169,6 +171,7 @@ void dispose() { stats.totalOffHeap = 0L; } stroking = 0; + doRender = false; doClip = false; closedPath = false; clipInvScale = 0.0d; diff --git a/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java b/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java index eb8969f2d7125..59f93ed7d6db7 100644 --- a/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java +++ b/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -170,25 +170,34 @@ Stroker init(final DPathConsumer2D pc2d, miterScaledLimit = miterLimit * lineWidth2; this.miterLimitSq = miterScaledLimit * miterScaledLimit; - final double limitMin = ((this.rdrCtx.clipInvScale == 0.0d) ? JOIN_ERROR - : (JOIN_ERROR * this.rdrCtx.clipInvScale)) - + lineWidth2; - - this.joinLimitMinSq = limitMin * limitMin; + if (rdrCtx.doRender) { + final double limitMin = ((this.rdrCtx.clipInvScale == 0.0d) ? JOIN_ERROR + : (JOIN_ERROR * this.rdrCtx.clipInvScale)) + + lineWidth2; + this.joinLimitMinSq = limitMin * limitMin; + } else { + // createStrokedShape(): disable limit checks: + this.joinLimitMinSq = 0.0; + } } else if (joinStyle == JOIN_ROUND) { - // chord: s = 2 r * sin( phi / 2) - // height: h = 2 r * sin( phi / 4)^2 - // small angles (phi < 90): - // h = s^2 / (8 r) - // so s^2 = (8 h * r) - - // height max (note ROUND_JOIN_ERROR = 8 * JOIN_ERROR) - final double limitMin = ((this.rdrCtx.clipInvScale == 0.0d) ? ROUND_JOIN_ERROR - : (ROUND_JOIN_ERROR * this.rdrCtx.clipInvScale)); - - // chord limit (s^2): - this.joinLimitMinSq = limitMin * this.lineWidth2; + if (rdrCtx.doRender) { + // chord: s = 2 r * sin( phi / 2) + // height: h = 2 r * sin( phi / 4)^2 + // small angles (phi < 90): + // h = s^2 / (8 r) + // so s^2 = (8 h * r) + + // height max (note ROUND_JOIN_ERROR = 8 * JOIN_ERROR) + final double limitMin = ((this.rdrCtx.clipInvScale == 0.0d) ? ROUND_JOIN_ERROR + : (ROUND_JOIN_ERROR * this.rdrCtx.clipInvScale)); + + // chord limit (s^2): + this.joinLimitMinSq = limitMin * this.lineWidth2; + } else { + // createStrokedShape(): disable limit checks: + this.joinLimitMinSq = 0.0; + } } this.prev = CLOSE; diff --git a/src/java.desktop/share/classes/sun/java2d/marlin/Version.java b/src/java.desktop/share/classes/sun/java2d/marlin/Version.java index a9ecec5863f4b..76bdbe59338c0 100644 --- a/src/java.desktop/share/classes/sun/java2d/marlin/Version.java +++ b/src/java.desktop/share/classes/sun/java2d/marlin/Version.java @@ -27,7 +27,7 @@ public final class Version { - private static final String VERSION = "marlin-0.9.4.6-Unsafe-OpenJDK"; + private static final String VERSION = "marlin-0.9.4.6.1-Unsafe-OpenJDK"; public static String getVersion() { return VERSION; diff --git a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java index b1b3d00209fa2..b86d5b88a2ad4 100644 --- a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java +++ b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java @@ -1080,6 +1080,8 @@ public PrintService[] run() { return false; } + this.attributes = attributes; + if (!service.equals(newService)) { try { setPrintService(newService); diff --git a/src/java.desktop/share/classes/sun/swing/CachedPainter.java b/src/java.desktop/share/classes/sun/swing/CachedPainter.java index ae69dd29cc63b..cee78c507f98b 100644 --- a/src/java.desktop/share/classes/sun/swing/CachedPainter.java +++ b/src/java.desktop/share/classes/sun/swing/CachedPainter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -314,8 +314,9 @@ public int getHeight(ImageObserver observer) { @Override public Image getResolutionVariant(double destWidth, double destHeight) { - int w = (int) Math.ceil(destWidth); - int h = (int) Math.ceil(destHeight); + int w = (int) Math.floor(destWidth + 0.5); + int h = (int) Math.floor(destHeight + 0.5); + return getImage(PainterMultiResolutionCachedImage.class, c, baseWidth, baseHeight, w, h, args); } diff --git a/src/java.desktop/share/legal/freetype.md b/src/java.desktop/share/legal/freetype.md index d602abbe5ae67..6bcb4976fd201 100644 --- a/src/java.desktop/share/legal/freetype.md +++ b/src/java.desktop/share/legal/freetype.md @@ -1,4 +1,4 @@ -## The FreeType Project: Freetype v2.13.0 +## The FreeType Project: Freetype v2.13.2 ### FreeType Notice diff --git a/src/java.desktop/share/legal/harfbuzz.md b/src/java.desktop/share/legal/harfbuzz.md index e2ed76aa7c6aa..3ae73d215b046 100644 --- a/src/java.desktop/share/legal/harfbuzz.md +++ b/src/java.desktop/share/legal/harfbuzz.md @@ -1,9 +1,7 @@ -## Harfbuzz v7.2.0 +## Harfbuzz v8.2.2 ### Harfbuzz License -https://github.com/harfbuzz/harfbuzz/blob/7.2.0/COPYING -
 
 HarfBuzz is licensed under the so-called "Old MIT" license.  Details follow.
@@ -14,6 +12,7 @@ Copyright © 2010-2023  Google, Inc.
 Copyright © 2018-2020  Ebrahim Byagowi
 Copyright © 2004-2013  Red Hat, Inc.
 Copyright © 2019  Facebook, Inc.
+Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
 Copyright © 2007  Chris Wilson
 Copyright © 2018-2019 Adobe Inc.
 Copyright © 2006-2023 Behdad Esfahbod
@@ -72,6 +71,15 @@ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+---------------------------------
+The below license applies to the following files:
+libharfbuzz/hb-unicode-emoji-table.hh
+
+© 2023 Unicode®, Inc.
+Unicode and the Unicode Logo are registered trademarks of Unicode, Inc.
+in the U.S. and other countries.
+For terms of use, see https://www.unicode.org/terms_of_use.html
+
 
### AUTHORS File Information diff --git a/src/java.desktop/share/legal/libpng.md b/src/java.desktop/share/legal/libpng.md index f11cfe580ce97..f420ccd94ed2e 100644 --- a/src/java.desktop/share/legal/libpng.md +++ b/src/java.desktop/share/legal/libpng.md @@ -1,4 +1,4 @@ -## libpng v1.6.39 +## libpng v1.6.40 ### libpng License
@@ -9,8 +9,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
 PNG Reference Library License version 2
 ---------------------------------------
 
-Copyright (c) 1995-2022 The PNG Reference Library Authors.
-Copyright (c) 2018-2022 Cosmin Truta
+Copyright (c) 1995-2023 The PNG Reference Library Authors.
+Copyright (c) 2018-2023 Cosmin Truta
 Copyright (c) 1998-2018 Glenn Randers-Pehrson
 Copyright (c) 1996-1997 Andreas Dilger
 Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -175,6 +175,7 @@ Authors, for copyright and licensing purposes.
  * Mike Klein
  * Pascal Massimino
  * Paul Schmidt
+ * Philippe Antoine
  * Qiang Zhou
  * Sam Bushell
  * Samuel Williams
@@ -193,6 +194,7 @@ Authors, for copyright and licensing purposes.
    - Matt Sarett
    - Mike Klein
    - Sami Boukortt
+   - Wan-Teh Chang
 
 The build projects, the build scripts, the test scripts, and other
 files in the "ci", "projects", "scripts" and "tests" directories, have
diff --git a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c
index 8f5f66fe09f99..21ac280f0fb0b 100644
--- a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c
+++ b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -548,7 +548,8 @@ Java_sun_font_FreetypeFontScaler_createScalerContextNative(
     if ((aa != TEXT_AA_ON) && (fm != TEXT_FM_ON) &&
         !context->doBold && !context->doItalize &&
         (context->transform.yx == 0) && (context->transform.xy == 0) &&
-        (context->transform.xx > 0) && (context->transform.yy > 0))
+        (context->transform.xx > 0) && (context->transform.yy > 0) &&
+        (context->transform.xx == context->transform.yy))
     {
         context->useSbits = 1;
     }
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h
index c13a3ef42880c..4375c7a6ff34f 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h
@@ -661,36 +661,12 @@ FT_BEGIN_HEADER
    * not) instructions in a certain way so that all TrueType fonts look like
    * they do in a Windows ClearType (DirectWrite) environment.  See [1] for a
    * technical overview on what this means.  See `ttinterp.h` for more
-   * details on the LEAN option.
+   * details on this option.
    *
-   * There are three possible values.
-   *
-   * Value 1:
-   *   This value is associated with the 'Infinality' moniker, contributed by
-   *   an individual nicknamed Infinality with the goal of making TrueType
-   *   fonts render better than on Windows.  A high amount of configurability
-   *   and flexibility, down to rules for single glyphs in fonts, but also
-   *   very slow.  Its experimental and slow nature and the original
-   *   developer losing interest meant that this option was never enabled in
-   *   default builds.
-   *
-   *   The corresponding interpreter version is v38.
-   *
-   * Value 2:
-   *   The new default mode for the TrueType driver.  The Infinality code
-   *   base was stripped to the bare minimum and all configurability removed
-   *   in the name of speed and simplicity.  The configurability was mainly
-   *   aimed at legacy fonts like 'Arial', 'Times New Roman', or 'Courier'.
-   *   Legacy fonts are fonts that modify vertical stems to achieve clean
-   *   black-and-white bitmaps.  The new mode focuses on applying a minimal
-   *   set of rules to all fonts indiscriminately so that modern and web
-   *   fonts render well while legacy fonts render okay.
-   *
-   *   The corresponding interpreter version is v40.
-   *
-   * Value 3:
-   *   Compile both, making both v38 and v40 available (the latter is the
-   *   default).
+   * The new default mode focuses on applying a minimal set of rules to all
+   * fonts indiscriminately so that modern and web fonts render well while
+   * legacy fonts render okay.  The corresponding interpreter version is v40.
+   * The so-called Infinality mode (v38) is no longer available in FreeType.
    *
    * By undefining these, you get rendering behavior like on Windows without
    * ClearType, i.e., Windows XP without ClearType enabled and Win9x
@@ -705,9 +681,7 @@ FT_BEGIN_HEADER
    * [1]
    * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx
    */
-/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING  1         */
-#define TT_CONFIG_OPTION_SUBPIXEL_HINTING  2
-/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING  ( 1 | 2 ) */
+#define TT_CONFIG_OPTION_SUBPIXEL_HINTING
 
 
   /**************************************************************************
@@ -977,21 +951,14 @@ FT_BEGIN_HEADER
 
 
   /*
-   * The next three macros are defined if native TrueType hinting is
+   * The next two macros are defined if native TrueType hinting is
    * requested by the definitions above.  Don't change this.
    */
 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
 #define  TT_USE_BYTECODE_INTERPRETER
-
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-#if TT_CONFIG_OPTION_SUBPIXEL_HINTING & 1
-#define  TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-#endif
-
-#if TT_CONFIG_OPTION_SUBPIXEL_HINTING & 2
 #define  TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
 #endif
-#endif
 #endif
 
 
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h
index 3c9d2ae59a414..f65148a902eac 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h
@@ -111,13 +111,13 @@
 
 #include 
 
-#define FT_FILE     FILE
-#define ft_fclose   fclose
-#define ft_fopen    fopen
-#define ft_fread    fread
-#define ft_fseek    fseek
-#define ft_ftell    ftell
-#define ft_sprintf  sprintf
+#define FT_FILE      FILE
+#define ft_fclose    fclose
+#define ft_fopen     fopen
+#define ft_fread     fread
+#define ft_fseek     fseek
+#define ft_ftell     ftell
+#define ft_snprintf  snprintf
 
 
   /**************************************************************************
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h b/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h
index efff74fe399e3..92acf3794a7e8 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h
@@ -102,61 +102,25 @@ FT_BEGIN_HEADER
    */
 
 
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*                                                                       */
-  /*                        B A S I C   T Y P E S                          */
-  /*                                                                       */
-  /*************************************************************************/
-  /*************************************************************************/
-
-
   /**************************************************************************
    *
    * @section:
-   *   base_interface
+   *   font_testing_macros
    *
    * @title:
-   *   Base Interface
+   *   Font Testing Macros
    *
    * @abstract:
-   *   The FreeType~2 base font interface.
+   *   Macros to test various properties of fonts.
    *
    * @description:
-   *   This section describes the most important public high-level API
-   *   functions of FreeType~2.
+   *   Macros to test the most important font properties.
    *
-   * @order:
-   *   FT_Library
-   *   FT_Face
-   *   FT_Size
-   *   FT_GlyphSlot
-   *   FT_CharMap
-   *   FT_Encoding
-   *   FT_ENC_TAG
-   *
-   *   FT_FaceRec
-   *
-   *   FT_FACE_FLAG_SCALABLE
-   *   FT_FACE_FLAG_FIXED_SIZES
-   *   FT_FACE_FLAG_FIXED_WIDTH
-   *   FT_FACE_FLAG_HORIZONTAL
-   *   FT_FACE_FLAG_VERTICAL
-   *   FT_FACE_FLAG_COLOR
-   *   FT_FACE_FLAG_SFNT
-   *   FT_FACE_FLAG_CID_KEYED
-   *   FT_FACE_FLAG_TRICKY
-   *   FT_FACE_FLAG_KERNING
-   *   FT_FACE_FLAG_MULTIPLE_MASTERS
-   *   FT_FACE_FLAG_VARIATION
-   *   FT_FACE_FLAG_GLYPH_NAMES
-   *   FT_FACE_FLAG_EXTERNAL_STREAM
-   *   FT_FACE_FLAG_HINTER
-   *   FT_FACE_FLAG_SVG
-   *   FT_FACE_FLAG_SBIX
-   *   FT_FACE_FLAG_SBIX_OVERLAY
+   *   It is recommended to use these high-level macros instead of directly
+   *   testing the corresponding flags, which are scattered over various
+   *   structures.
    *
+   * @order:
    *   FT_HAS_HORIZONTAL
    *   FT_HAS_VERTICAL
    *   FT_HAS_KERNING
@@ -176,21 +140,59 @@ FT_BEGIN_HEADER
    *   FT_IS_NAMED_INSTANCE
    *   FT_IS_VARIATION
    *
-   *   FT_STYLE_FLAG_BOLD
-   *   FT_STYLE_FLAG_ITALIC
+   */
+
+
+  /**************************************************************************
+   *
+   * @section:
+   *   library_setup
    *
-   *   FT_SizeRec
-   *   FT_Size_Metrics
+   * @title:
+   *   Library Setup
    *
-   *   FT_GlyphSlotRec
-   *   FT_Glyph_Metrics
-   *   FT_SubGlyph
+   * @abstract:
+   *   Functions to start and end the usage of the FreeType library.
    *
-   *   FT_Bitmap_Size
+   * @description:
+   *   Functions to start and end the usage of the FreeType library.
+   *
+   *   Note that @FT_Library_Version and @FREETYPE_XXX are of limited use
+   *   because even a new release of FreeType with only documentation
+   *   changes increases the version number.
    *
+   * @order:
+   *   FT_Library
    *   FT_Init_FreeType
    *   FT_Done_FreeType
    *
+   *   FT_Library_Version
+   *   FREETYPE_XXX
+   *
+   */
+
+
+  /**************************************************************************
+   *
+   * @section:
+   *   face_creation
+   *
+   * @title:
+   *   Face Creation
+   *
+   * @abstract:
+   *   Functions to manage fonts.
+   *
+   * @description:
+   *   The functions and structures collected in this section operate on
+   *   fonts globally.
+   *
+   * @order:
+   *   FT_Face
+   *   FT_FaceRec
+   *   FT_FACE_FLAG_XXX
+   *   FT_STYLE_FLAG_XXX
+   *
    *   FT_New_Face
    *   FT_Done_Face
    *   FT_Reference_Face
@@ -198,10 +200,36 @@ FT_BEGIN_HEADER
    *   FT_Face_Properties
    *   FT_Open_Face
    *   FT_Open_Args
+   *   FT_OPEN_XXX
    *   FT_Parameter
    *   FT_Attach_File
    *   FT_Attach_Stream
    *
+   */
+
+
+  /**************************************************************************
+   *
+   * @section:
+   *   sizing_and_scaling
+   *
+   * @title:
+   *   Sizing and Scaling
+   *
+   * @abstract:
+   *   Functions to manage font sizes.
+   *
+   * @description:
+   *   The functions and structures collected in this section are related to
+   *   selecting and manipulating the size of a font globally.
+   *
+   * @order:
+   *   FT_Size
+   *   FT_SizeRec
+   *   FT_Size_Metrics
+   *
+   *   FT_Bitmap_Size
+   *
    *   FT_Set_Char_Size
    *   FT_Set_Pixel_Sizes
    *   FT_Request_Size
@@ -209,44 +237,37 @@ FT_BEGIN_HEADER
    *   FT_Size_Request_Type
    *   FT_Size_RequestRec
    *   FT_Size_Request
+   *
    *   FT_Set_Transform
    *   FT_Get_Transform
-   *   FT_Load_Glyph
-   *   FT_Get_Char_Index
-   *   FT_Get_First_Char
-   *   FT_Get_Next_Char
-   *   FT_Load_Char
    *
-   *   FT_OPEN_MEMORY
-   *   FT_OPEN_STREAM
-   *   FT_OPEN_PATHNAME
-   *   FT_OPEN_DRIVER
-   *   FT_OPEN_PARAMS
-   *
-   *   FT_LOAD_DEFAULT
-   *   FT_LOAD_RENDER
-   *   FT_LOAD_MONOCHROME
-   *   FT_LOAD_LINEAR_DESIGN
-   *   FT_LOAD_NO_SCALE
-   *   FT_LOAD_NO_HINTING
-   *   FT_LOAD_NO_BITMAP
-   *   FT_LOAD_SBITS_ONLY
-   *   FT_LOAD_NO_AUTOHINT
-   *   FT_LOAD_COLOR
-   *
-   *   FT_LOAD_VERTICAL_LAYOUT
-   *   FT_LOAD_IGNORE_TRANSFORM
-   *   FT_LOAD_FORCE_AUTOHINT
-   *   FT_LOAD_NO_RECURSE
-   *   FT_LOAD_PEDANTIC
-   *
-   *   FT_LOAD_TARGET_NORMAL
-   *   FT_LOAD_TARGET_LIGHT
-   *   FT_LOAD_TARGET_MONO
-   *   FT_LOAD_TARGET_LCD
-   *   FT_LOAD_TARGET_LCD_V
+   */
+
+
+  /**************************************************************************
+   *
+   * @section:
+   *   glyph_retrieval
+   *
+   * @title:
+   *   Glyph Retrieval
+   *
+   * @abstract:
+   *   Functions to manage glyphs.
+   *
+   * @description:
+   *   The functions and structures collected in this section operate on
+   *   single glyphs, of which @FT_Load_Glyph is most important.
    *
+   * @order:
+   *   FT_GlyphSlot
+   *   FT_GlyphSlotRec
+   *   FT_Glyph_Metrics
+   *
+   *   FT_Load_Glyph
+   *   FT_LOAD_XXX
    *   FT_LOAD_TARGET_MODE
+   *   FT_LOAD_TARGET_XXX
    *
    *   FT_Render_Glyph
    *   FT_Render_Mode
@@ -254,34 +275,121 @@ FT_BEGIN_HEADER
    *   FT_Kerning_Mode
    *   FT_Get_Track_Kerning
    *
+   */
+
+
+  /**************************************************************************
+   *
+   * @section:
+   *   character_mapping
+   *
+   * @title:
+   *   Character Mapping
+   *
+   * @abstract:
+   *   Functions to manage character-to-glyph maps.
+   *
+   * @description:
+   *   This section holds functions and structures that are related to
+   *   mapping character input codes to glyph indices.
+   *
+   *   Note that for many scripts the simplistic approach used by FreeType
+   *   of mapping a single character to a single glyph is not valid or
+   *   possible!  In general, a higher-level library like HarfBuzz or ICU
+   *   should be used for handling text strings.
+   *
+   * @order:
+   *   FT_CharMap
    *   FT_CharMapRec
+   *   FT_Encoding
+   *   FT_ENC_TAG
+   *
    *   FT_Select_Charmap
    *   FT_Set_Charmap
    *   FT_Get_Charmap_Index
    *
+   *   FT_Get_Char_Index
+   *   FT_Get_First_Char
+   *   FT_Get_Next_Char
+   *   FT_Load_Char
+   *
+   */
+
+
+  /**************************************************************************
+   *
+   * @section:
+   *   information_retrieval
+   *
+   * @title:
+   *   Information Retrieval
+   *
+   * @abstract:
+   *   Functions to retrieve font and glyph information.
+   *
+   * @description:
+   *   Functions to retrieve font and glyph information.  Only some very
+   *   basic data is covered; see also the chapter on the format-specific
+   *   API for more.
+   *
+   *
+   * @order:
    *   FT_Get_Name_Index
    *   FT_Get_Glyph_Name
    *   FT_Get_Postscript_Name
    *   FT_Get_FSType_Flags
+   *   FT_FSTYPE_XXX
    *   FT_Get_SubGlyph_Info
+   *   FT_SUBGLYPH_FLAG_XXX
+   *
+   */
+
+
+  /**************************************************************************
+   *
+   * @section:
+   *   other_api_data
+   *
+   * @title:
+   *   Other API Data
+   *
+   * @abstract:
+   *   Other structures, enumerations, and macros.
    *
+   * @description:
+   *   Other structures, enumerations, and macros.  Deprecated functions are
+   *   also listed here.
+   *
+   * @order:
    *   FT_Face_Internal
    *   FT_Size_Internal
    *   FT_Slot_Internal
    *
-   *   FT_FACE_FLAG_XXX
-   *   FT_STYLE_FLAG_XXX
-   *   FT_OPEN_XXX
-   *   FT_LOAD_XXX
-   *   FT_LOAD_TARGET_XXX
-   *   FT_SUBGLYPH_FLAG_XXX
-   *   FT_FSTYPE_XXX
+   *   FT_SubGlyph
    *
    *   FT_HAS_FAST_GLYPHS
+   *   FT_Face_CheckTrueTypePatents
+   *   FT_Face_SetUnpatentedHinting
    *
    */
 
 
+  /*************************************************************************/
+  /*************************************************************************/
+  /*                                                                       */
+  /*                        B A S I C   T Y P E S                          */
+  /*                                                                       */
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /**************************************************************************
+   *
+   * @section:
+   *   glyph_retrieval
+   *
+   */
+
   /**************************************************************************
    *
    * @struct:
@@ -349,6 +457,13 @@ FT_BEGIN_HEADER
   } FT_Glyph_Metrics;
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   sizing_and_scaling
+   *
+   */
+
   /**************************************************************************
    *
    * @struct:
@@ -409,6 +524,13 @@ FT_BEGIN_HEADER
   /*************************************************************************/
   /*************************************************************************/
 
+  /**************************************************************************
+   *
+   * @section:
+   *   library_setup
+   *
+   */
+
   /**************************************************************************
    *
    * @type:
@@ -483,7 +605,7 @@ FT_BEGIN_HEADER
   /**************************************************************************
    *
    * @section:
-   *   base_interface
+   *   face_creation
    *
    */
 
@@ -519,6 +641,13 @@ FT_BEGIN_HEADER
   typedef struct FT_FaceRec_*  FT_Face;
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   sizing_and_scaling
+   *
+   */
+
   /**************************************************************************
    *
    * @type:
@@ -551,6 +680,13 @@ FT_BEGIN_HEADER
   typedef struct FT_SizeRec_*  FT_Size;
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   glyph_retrieval
+   *
+   */
+
   /**************************************************************************
    *
    * @type:
@@ -570,6 +706,13 @@ FT_BEGIN_HEADER
   typedef struct FT_GlyphSlotRec_*  FT_GlyphSlot;
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   character_mapping
+   *
+   */
+
   /**************************************************************************
    *
    * @type:
@@ -877,6 +1020,13 @@ FT_BEGIN_HEADER
   /*************************************************************************/
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   other_api_data
+   *
+   */
+
   /**************************************************************************
    *
    * @type:
@@ -892,6 +1042,13 @@ FT_BEGIN_HEADER
   typedef struct FT_Face_InternalRec_*  FT_Face_Internal;
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   face_creation
+   *
+   */
+
   /**************************************************************************
    *
    * @struct:
@@ -918,7 +1075,7 @@ FT_BEGIN_HEADER
    *     If we have the third named instance of face~4, say, `face_index` is
    *     set to 0x00030004.
    *
-   *     Bit 31 is always zero (this is, `face_index` is always a positive
+   *     Bit 31 is always zero (that is, `face_index` is always a positive
    *     value).
    *
    *     [Since 2.9] Changing the design coordinates with
@@ -936,7 +1093,7 @@ FT_BEGIN_HEADER
    *
    *     [Since 2.6.1] Bits 16-30 hold the number of named instances
    *     available for the current face if we have a GX or OpenType variation
-   *     (sub)font.  Bit 31 is always zero (this is, `style_flags` is always
+   *     (sub)font.  Bit 31 is always zero (that is, `style_flags` is always
    *     a positive value).  Note that a variation font has always at least
    *     one named instance, namely the default instance.
    *
@@ -1002,7 +1159,7 @@ FT_BEGIN_HEADER
    *     Note that the bounding box might be off by (at least) one pixel for
    *     hinted fonts.  See @FT_Size_Metrics for further discussion.
    *
-   *     Note that the bounding box does not vary in OpenType variable fonts
+   *     Note that the bounding box does not vary in OpenType variation fonts
    *     and should only be used in relation to the default instance.
    *
    *   units_per_EM ::
@@ -1090,9 +1247,9 @@ FT_BEGIN_HEADER
 
     FT_Generic        generic;
 
-    /*# The following member variables (down to `underline_thickness`) */
-    /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size    */
-    /*# for bitmap fonts.                                              */
+    /* The following member variables (down to `underline_thickness`) */
+    /* are only relevant to scalable outlines; cf. @FT_Bitmap_Size    */
+    /* for bitmap fonts.                                              */
     FT_BBox           bbox;
 
     FT_UShort         units_per_EM;
@@ -1110,7 +1267,7 @@ FT_BEGIN_HEADER
     FT_Size           size;
     FT_CharMap        charmap;
 
-    /*@private begin */
+    /* private fields, internal to FreeType */
 
     FT_Driver         driver;
     FT_Memory         memory;
@@ -1123,8 +1280,6 @@ FT_BEGIN_HEADER
 
     FT_Face_Internal  internal;
 
-    /*@private end */
-
   } FT_FaceRec;
 
 
@@ -1207,13 +1362,13 @@ FT_BEGIN_HEADER
    *     successfully; in all other cases you get an
    *     `FT_Err_Invalid_Argument` error.
    *
-   *     Note that CID-keyed fonts that are in an SFNT wrapper (this is, all
+   *     Note that CID-keyed fonts that are in an SFNT wrapper (that is, all
    *     OpenType/CFF fonts) don't have this flag set since the glyphs are
    *     accessed in the normal way (using contiguous indices); the
    *     'CID-ness' isn't visible to the application.
    *
    *   FT_FACE_FLAG_TRICKY ::
-   *     The face is 'tricky', this is, it always needs the font format's
+   *     The face is 'tricky', that is, it always needs the font format's
    *     native hinting engine to get a reasonable result.  A typical example
    *     is the old Chinese font `mingli.ttf` (but not `mingliu.ttc`) that
    *     uses TrueType bytecode instructions to move and scale all of its
@@ -1235,8 +1390,8 @@ FT_BEGIN_HEADER
    *   FT_FACE_FLAG_VARIATION ::
    *     [Since 2.9] Set if the current face (or named instance) has been
    *     altered with @FT_Set_MM_Design_Coordinates,
-   *     @FT_Set_Var_Design_Coordinates, or @FT_Set_Var_Blend_Coordinates.
-   *     This flag is unset by a call to @FT_Set_Named_Instance.
+   *     @FT_Set_Var_Design_Coordinates, @FT_Set_Var_Blend_Coordinates, or
+   *     @FT_Set_MM_WeightVector to select a non-default instance.
    *
    *   FT_FACE_FLAG_SVG ::
    *     [Since 2.12] The face has an 'SVG~' OpenType table.
@@ -1272,6 +1427,13 @@ FT_BEGIN_HEADER
 #define FT_FACE_FLAG_SBIX_OVERLAY      ( 1L << 18 )
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   font_testing_macros
+   *
+   */
+
   /**************************************************************************
    *
    * @macro:
@@ -1381,6 +1543,13 @@ FT_BEGIN_HEADER
           ( !!( (face)->face_flags & FT_FACE_FLAG_FIXED_SIZES ) )
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   other_api_data
+   *
+   */
+
   /**************************************************************************
    *
    * @macro:
@@ -1393,6 +1562,13 @@ FT_BEGIN_HEADER
 #define FT_HAS_FAST_GLYPHS( face )  0
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   font_testing_macros
+   *
+   */
+
   /**************************************************************************
    *
    * @macro:
@@ -1451,8 +1627,8 @@ FT_BEGIN_HEADER
    *
    * @description:
    *   A macro that returns true whenever a face object has been altered by
-   *   @FT_Set_MM_Design_Coordinates, @FT_Set_Var_Design_Coordinates, or
-   *   @FT_Set_Var_Blend_Coordinates.
+   *   @FT_Set_MM_Design_Coordinates, @FT_Set_Var_Design_Coordinates,
+   *   @FT_Set_Var_Blend_Coordinates, or @FT_Set_MM_WeightVector.
    *
    * @since:
    *   2.9
@@ -1628,6 +1804,13 @@ FT_BEGIN_HEADER
           ( !!( (face)->face_flags & FT_FACE_FLAG_SBIX_OVERLAY ) )
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   face_creation
+   *
+   */
+
   /**************************************************************************
    *
    * @enum:
@@ -1654,6 +1837,13 @@ FT_BEGIN_HEADER
 #define FT_STYLE_FLAG_BOLD    ( 1 << 1 )
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   other_api_data
+   *
+   */
+
   /**************************************************************************
    *
    * @type:
@@ -1666,6 +1856,13 @@ FT_BEGIN_HEADER
   typedef struct FT_Size_InternalRec_*  FT_Size_Internal;
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   sizing_and_scaling
+   *
+   */
+
   /**************************************************************************
    *
    * @struct:
@@ -1817,6 +2014,13 @@ FT_BEGIN_HEADER
   } FT_SizeRec;
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   other_api_data
+   *
+   */
+
   /**************************************************************************
    *
    * @struct:
@@ -1848,6 +2052,13 @@ FT_BEGIN_HEADER
   typedef struct FT_Slot_InternalRec_*  FT_Slot_Internal;
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   glyph_retrieval
+   *
+   */
+
   /**************************************************************************
    *
    * @struct:
@@ -2092,6 +2303,13 @@ FT_BEGIN_HEADER
   /*************************************************************************/
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   library_setup
+   *
+   */
+
   /**************************************************************************
    *
    * @function:
@@ -2149,6 +2367,13 @@ FT_BEGIN_HEADER
   FT_Done_FreeType( FT_Library  library );
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   face_creation
+   *
+   */
+
   /**************************************************************************
    *
    * @enum:
@@ -2451,7 +2676,7 @@ FT_BEGIN_HEADER
    *   Each new face object created with this function also owns a default
    *   @FT_Size object, accessible as `face->size`.
    *
-   *   One @FT_Library instance can have multiple face objects, this is,
+   *   One @FT_Library instance can have multiple face objects, that is,
    *   @FT_Open_Face and its siblings can be called multiple times using the
    *   same `library` argument.
    *
@@ -2650,6 +2875,13 @@ FT_BEGIN_HEADER
   FT_Done_Face( FT_Face  face );
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   sizing_and_scaling
+   *
+   */
+
   /**************************************************************************
    *
    * @function:
@@ -2679,7 +2911,7 @@ FT_BEGIN_HEADER
    *   silently uses outlines if there is no bitmap for a given glyph index.
    *
    *   For GX and OpenType variation fonts, a bitmap strike makes sense only
-   *   if the default instance is active (this is, no glyph variation takes
+   *   if the default instance is active (that is, no glyph variation takes
    *   place); otherwise, FreeType simply ignores bitmap strikes.  The same
    *   is true for all named instances that are different from the default
    *   instance.
@@ -2942,6 +3174,13 @@ FT_BEGIN_HEADER
                       FT_UInt  pixel_height );
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   glyph_retrieval
+   *
+   */
+
   /**************************************************************************
    *
    * @function:
@@ -2976,7 +3215,7 @@ FT_BEGIN_HEADER
    *   glyph may be transformed.  See @FT_Set_Transform for the details.
    *
    *   For subsetted CID-keyed fonts, `FT_Err_Invalid_Argument` is returned
-   *   for invalid CID values (this is, for CID values that don't have a
+   *   for invalid CID values (that is, for CID values that don't have a
    *   corresponding glyph in the font).  See the discussion of the
    *   @FT_FACE_FLAG_CID_KEYED flag for more details.
    *
@@ -2990,6 +3229,13 @@ FT_BEGIN_HEADER
                  FT_Int32  load_flags );
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   character_mapping
+   *
+   */
+
   /**************************************************************************
    *
    * @function:
@@ -3033,6 +3279,13 @@ FT_BEGIN_HEADER
                 FT_Int32  load_flags );
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   glyph_retrieval
+   *
+   */
+
   /**************************************************************************
    *
    * @enum:
@@ -3172,10 +3425,11 @@ FT_BEGIN_HEADER
    *
    *     [Since 2.12] If the glyph index maps to an entry in the face's
    *     'SVG~' table, load the associated SVG document from this table and
-   *     set the `format` field of @FT_GlyphSlotRec to @FT_GLYPH_FORMAT_SVG.
-   *     Note that FreeType itself can't render SVG documents; however, the
-   *     library provides hooks to seamlessly integrate an external renderer.
-   *     See sections @ot_svg_driver and @svg_fonts for more.
+   *     set the `format` field of @FT_GlyphSlotRec to @FT_GLYPH_FORMAT_SVG
+   *     ([since 2.13.1] provided @FT_LOAD_NO_SVG is not set).  Note that
+   *     FreeType itself can't render SVG documents; however, the library
+   *     provides hooks to seamlessly integrate an external renderer.  See
+   *     sections @ot_svg_driver and @svg_fonts for more.
    *
    *     [Since 2.10, experimental] If the glyph index maps to an entry in
    *     the face's 'COLR' table with a 'CPAL' palette table (as defined in
@@ -3189,6 +3443,9 @@ FT_BEGIN_HEADER
    *     @FT_Palette_Select instead of setting @FT_LOAD_COLOR for rendering
    *     so that the client application can handle blending by itself.
    *
+   *   FT_LOAD_NO_SVG ::
+   *     [Since 2.13.1] Ignore SVG glyph data when loading.
+   *
    *   FT_LOAD_COMPUTE_METRICS ::
    *     [Since 2.6.1] Compute glyph metrics from the glyph data, without the
    *     use of bundled metrics tables (for example, the 'hdmx' table in
@@ -3254,6 +3511,7 @@ FT_BEGIN_HEADER
 #define FT_LOAD_COLOR                        ( 1L << 20 )
 #define FT_LOAD_COMPUTE_METRICS              ( 1L << 21 )
 #define FT_LOAD_BITMAP_METRICS_ONLY          ( 1L << 22 )
+#define FT_LOAD_NO_SVG                       ( 1L << 24 )
 
   /* */
 
@@ -3372,6 +3630,13 @@ FT_BEGIN_HEADER
           FT_STATIC_CAST( FT_Render_Mode, ( (x) >> 16 ) & 15 )
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   sizing_and_scaling
+   *
+   */
+
   /**************************************************************************
    *
    * @function:
@@ -3447,6 +3712,13 @@ FT_BEGIN_HEADER
                     FT_Vector*  delta );
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   glyph_retrieval
+   *
+   */
+
   /**************************************************************************
    *
    * @enum:
@@ -3841,6 +4113,13 @@ FT_BEGIN_HEADER
                         FT_Fixed*  akerning );
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   character_mapping
+   *
+   */
+
   /**************************************************************************
    *
    * @function:
@@ -4057,6 +4336,13 @@ FT_BEGIN_HEADER
                     FT_UInt   *agindex );
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   face_creation
+   *
+   */
+
   /**************************************************************************
    *
    * @function:
@@ -4155,6 +4441,13 @@ FT_BEGIN_HEADER
                       FT_Parameter*  properties );
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   information_retrieval
+   *
+   */
+
   /**************************************************************************
    *
    * @function:
@@ -4266,9 +4559,10 @@ FT_BEGIN_HEADER
    *
    *   [Since 2.9] Special PostScript names for named instances are only
    *   returned if the named instance is set with @FT_Set_Named_Instance (and
-   *   the font has corresponding entries in its 'fvar' table).  If
-   *   @FT_IS_VARIATION returns true, the algorithmically derived PostScript
-   *   name is provided, not looking up special entries for named instances.
+   *   the font has corresponding entries in its 'fvar' table or is the
+   *   default named instance).  If @FT_IS_VARIATION returns true, the
+   *   algorithmically derived PostScript name is provided, not looking up
+   *   special entries for named instances.
    */
   FT_EXPORT( const char* )
   FT_Get_Postscript_Name( FT_Face  face );
@@ -4900,32 +5194,10 @@ FT_BEGIN_HEADER
   /**************************************************************************
    *
    * @section:
-   *   version
-   *
-   * @title:
-   *   FreeType Version
-   *
-   * @abstract:
-   *   Functions and macros related to FreeType versions.
-   *
-   * @description:
-   *   Note that those functions and macros are of limited use because even a
-   *   new release of FreeType with only documentation changes increases the
-   *   version number.
-   *
-   * @order:
-   *   FT_Library_Version
-   *
-   *   FREETYPE_MAJOR
-   *   FREETYPE_MINOR
-   *   FREETYPE_PATCH
-   *
-   *   FT_Face_CheckTrueTypePatents
-   *   FT_Face_SetUnpatentedHinting
+   *   library_setup
    *
    */
 
-
   /**************************************************************************
    *
    * @enum:
@@ -4950,7 +5222,7 @@ FT_BEGIN_HEADER
    */
 #define FREETYPE_MAJOR  2
 #define FREETYPE_MINOR  13
-#define FREETYPE_PATCH  0
+#define FREETYPE_PATCH  2
 
 
   /**************************************************************************
@@ -4992,6 +5264,13 @@ FT_BEGIN_HEADER
                       FT_Int      *apatch );
 
 
+  /**************************************************************************
+   *
+   * @section:
+   *   other_api_data
+   *
+   */
+
   /**************************************************************************
    *
    * @function:
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftchapters.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftchapters.h
index 6a9733ad7c142..7566fbd10f83d 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftchapters.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftchapters.h
@@ -31,9 +31,28 @@
    *   Core API
    *
    * @sections:
-   *   version
    *   basic_types
-   *   base_interface
+   *   library_setup
+   *   face_creation
+   *   font_testing_macros
+   *   sizing_and_scaling
+   *   glyph_retrieval
+   *   character_mapping
+   *   information_retrieval
+   *   other_api_data
+   *
+   */
+
+
+  /**************************************************************************
+   *
+   * @chapter:
+   *   extended_api
+   *
+   * @title:
+   *   Extended API
+   *
+   * @sections:
    *   glyph_variants
    *   color_management
    *   layer_management
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h
index f90946fd17d3c..7af7465bc768e 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h
@@ -134,7 +134,7 @@ FT_BEGIN_HEADER
    *   each being rounded to the nearest pixel edge, taking care of overshoot
    *   suppression at small sizes, stem darkening, and scaling.
    *
-   *   Hstems (this is, hint values defined in the font to help align
+   *   Hstems (that is, hint values defined in the font to help align
    *   horizontal features) that fall within a blue zone are said to be
    *   'captured' and are aligned to that zone.  Uncaptured stems are moved
    *   in one of four ways, top edge up or down, bottom edge up or down.
@@ -446,7 +446,7 @@ FT_BEGIN_HEADER
    *   at smaller sizes.
    *
    *   For the auto-hinter, stem-darkening is experimental currently and thus
-   *   switched off by default (this is, `no-stem-darkening` is set to TRUE
+   *   switched off by default (that is, `no-stem-darkening` is set to TRUE
    *   by default).  Total consistency with the CFF driver is not achieved
    *   right now because the emboldening method differs and glyphs must be
    *   scaled down on the Y-axis to keep outline points inside their
@@ -651,11 +651,8 @@ FT_BEGIN_HEADER
    *     Windows~98; only grayscale and B/W rasterizing is supported.
    *
    *   TT_INTERPRETER_VERSION_38 ::
-   *     Version~38 corresponds to MS rasterizer v.1.9; it is roughly
-   *     equivalent to the hinting provided by DirectWrite ClearType (as can
-   *     be found, for example, in the Internet Explorer~9 running on
-   *     Windows~7).  It is used in FreeType to select the 'Infinality'
-   *     subpixel hinting code.  The code may be removed in a future version.
+   *     Version~38 is the same Version~40. The original 'Infinality' code is
+   *     no longer available.
    *
    *   TT_INTERPRETER_VERSION_40 ::
    *     Version~40 corresponds to MS rasterizer v.2.1; it is roughly
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h
index 2e8e6734cc048..6baa812560ead 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h
@@ -19,7 +19,7 @@
   /**************************************************************************
    *
    * Note: A 'raster' is simply a scan-line converter, used to render
-   *       FT_Outlines into FT_Bitmaps.
+   *       `FT_Outline`s into `FT_Bitmap`s.
    *
    */
 
@@ -256,6 +256,12 @@ FT_BEGIN_HEADER
    *   palette ::
    *     A typeless pointer to the bitmap palette; this field is intended for
    *     paletted pixel modes.  Not used currently.
+   *
+   * @note:
+   *   `width` and `rows` refer to the *physical* size of the bitmap, not the
+   *   *logical* one.  For example, if @FT_Pixel_Mode is set to
+   *   `FT_PIXEL_MODE_LCD`, the logical width is a just a third of the
+   *   physical one.
    */
   typedef struct  FT_Bitmap_
   {
@@ -856,7 +862,7 @@ FT_BEGIN_HEADER
    *   @FT_SpanFunc that takes the y~coordinate of the span as a parameter.
    *
    *   The anti-aliased rasterizer produces coverage values from 0 to 255,
-   *   this is, from completely transparent to completely opaque.
+   *   that is, from completely transparent to completely opaque.
    */
   typedef struct  FT_Span_
   {
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h
index 2246dc8365193..53b8b89642711 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h
@@ -62,7 +62,7 @@ FT_BEGIN_HEADER
    *   component.
    *
    *   ```
-   *   FT_Trace_Set_Level( "any:7 memory:0 );
+   *   FT_Trace_Set_Level( "any:7 memory:0" );
    *   ```
    *
    * @note:
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h
index e381ef3d30a17..d145128a9bcdb 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h
@@ -153,7 +153,7 @@ FT_BEGIN_HEADER
    * @note:
    *   The fields `minimum`, `def`, and `maximum` are 16.16 fractional values
    *   for TrueType GX and OpenType variation fonts.  For Adobe MM fonts, the
-   *   values are integers.
+   *   values are whole numbers (i.e., the fractional part is zero).
    */
   typedef struct  FT_Var_Axis_
   {
@@ -399,8 +399,8 @@ FT_BEGIN_HEADER
    *
    * @note:
    *   The design coordinates are 16.16 fractional values for TrueType GX and
-   *   OpenType variation fonts.  For Adobe MM fonts, the values are
-   *   integers.
+   *   OpenType variation fonts.  For Adobe MM fonts, the values are supposed
+   *   to be whole numbers (i.e., the fractional part is zero).
    *
    *   [Since 2.8.1] To reset all axes to the default values, call the
    *   function with `num_coords` set to zero and `coords` set to `NULL`.
@@ -446,8 +446,8 @@ FT_BEGIN_HEADER
    *
    * @note:
    *   The design coordinates are 16.16 fractional values for TrueType GX and
-   *   OpenType variation fonts.  For Adobe MM fonts, the values are
-   *   integers.
+   *   OpenType variation fonts.  For Adobe MM fonts, the values are whole
+   *   numbers (i.e., the fractional part is zero).
    *
    * @since:
    *   2.7.1
@@ -602,10 +602,12 @@ FT_BEGIN_HEADER
    *
    * @note:
    *   Adobe Multiple Master fonts limit the number of designs, and thus the
-   *   length of the weight vector to~16.
+   *   length of the weight vector to 16~elements.
    *
-   *   If `len` is zero and `weightvector` is `NULL`, the weight vector array
-   *   is reset to the default values.
+   *   If `len` is larger than zero, this function sets the
+   *   @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field (i.e.,
+   *   @FT_IS_VARIATION will return true).  If `len` is zero, this bit flag
+   *   is unset and the weight vector array is reset to the default values.
    *
    *   The Adobe documentation also states that the values in the
    *   WeightVector array must total 1.0 +/-~0.001.  In practice this does
@@ -753,6 +755,45 @@ FT_BEGIN_HEADER
   FT_Set_Named_Instance( FT_Face  face,
                          FT_UInt  instance_index );
 
+
+  /**************************************************************************
+   *
+   * @function:
+   *   FT_Get_Default_Named_Instance
+   *
+   * @description:
+   *   Retrieve the index of the default named instance, to be used with
+   *   @FT_Set_Named_Instance.
+   *
+   *   The default instance of a variation font is that instance for which
+   *   the nth axis coordinate is equal to `axis[n].def` (as specified in the
+   *   @FT_MM_Var structure), with~n covering all axes.
+   *
+   *   FreeType synthesizes a named instance for the default instance if the
+   *   font does not contain such an entry.
+   *
+   * @input:
+   *   face ::
+   *     A handle to the source face.
+   *
+   * @output:
+   *   instance_index ::
+   *     The index of the default named instance.
+   *
+   * @return:
+   *   FreeType error code.  0~means success.
+   *
+   * @note:
+   *   For Adobe MM fonts (which don't have named instances) this function
+   *   always returns zero for `instance_index`.
+   *
+   * @since:
+   *   2.13.1
+   */
+  FT_EXPORT( FT_Error )
+  FT_Get_Default_Named_Instance( FT_Face   face,
+                                 FT_UInt  *instance_index );
+
   /* */
 
 
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h
index 54434b25f6f47..f9329ca40c98a 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h
@@ -118,7 +118,7 @@ FT_BEGIN_HEADER
    *   attachement.
    *
    *   Similarly, the function returns success for an empty outline also
-   *   (doing nothing, this is, not calling any emitter); if necessary, you
+   *   (doing nothing, that is, not calling any emitter); if necessary, you
    *   should filter this out, too.
    */
   FT_EXPORT( FT_Error )
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h
index a8576dab00268..0b6fad32e8497 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h
@@ -158,7 +158,7 @@ FT_BEGIN_HEADER
     FT_Renderer_GetCBoxFunc    get_glyph_cbox;
     FT_Renderer_SetModeFunc    set_mode;
 
-    FT_Raster_Funcs*           raster_class;
+    const FT_Raster_Funcs*     raster_class;
 
   } FT_Renderer_Class;
 
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h
index 5d196976572df..af90967dda0de 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h
@@ -68,6 +68,18 @@ FT_BEGIN_HEADER
   FT_EXPORT( void )
   FT_GlyphSlot_Embolden( FT_GlyphSlot  slot );
 
+  /* Precisely adjust the glyph weight either horizontally or vertically.  */
+  /* The `xdelta` and `ydelta` values are fractions of the face Em size    */
+  /* (in fixed-point format).  Considering that a regular face would have  */
+  /* stem widths on the order of 0.1 Em, a delta of 0.05 (0x0CCC) should   */
+  /* be very noticeable.  To increase or decrease the weight, use positive */
+  /* or negative values, respectively.                                     */
+  FT_EXPORT( void )
+  FT_GlyphSlot_AdjustWeight( FT_GlyphSlot  slot,
+                             FT_Fixed      xdelta,
+                             FT_Fixed      ydelta );
+
+
   /* Slant an outline glyph to the right by about 12 degrees.              */
   FT_EXPORT( void )
   FT_GlyphSlot_Oblique( FT_GlyphSlot  slot );
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h
index a995b078de5e9..3a08f4912c982 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h
@@ -229,8 +229,7 @@ FT_BEGIN_HEADER
    *     A handle to the source stream.
    *
    *   offset ::
-   *     The offset from the start of the stream to seek to if this is a seek
-   *     operation (see note).
+   *     The offset from the start of the stream to seek to.
    *
    *   buffer ::
    *     The address of the read buffer.
@@ -239,16 +238,9 @@ FT_BEGIN_HEADER
    *     The number of bytes to read from the stream.
    *
    * @return:
-   *   The number of bytes effectively read by the stream.
-   *
-   * @note:
-   *   This function performs a seek *or* a read operation depending on the
-   *   argument values.  If `count` is zero, the operation is a seek to
-   *   `offset` bytes.  If `count` is >~0, the operation is a read of `count`
-   *   bytes from the current position in the stream, and the `offset` value
-   *   should be ignored.
-   *
-   *   For seek operations, a non-zero return value indicates an error.
+   *   If count >~0, return the number of bytes effectively read by the
+   *   stream (after seeking to `offset`).  If count ==~0, return the status
+   *   of the seek operation (non-zero indicates an error).
    *
    */
   typedef unsigned long
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h
index 7883317fed98b..6f67650979e9e 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h
@@ -41,8 +41,11 @@ FT_BEGIN_HEADER
 #  if ( defined( __STDC_VERSION__ ) && __STDC_VERSION__ > 201710L ) || \
       ( defined( __cplusplus ) && __cplusplus > 201402L )
 #    define FALL_THROUGH  [[__fallthrough__]]
-#  elif ( defined( __GNUC__ ) && __GNUC__ >= 7 )          || \
-        ( defined( __clang__ ) && __clang_major__ >= 10 )
+#  elif ( defined( __GNUC__ ) && __GNUC__ >= 7 )       || \
+        ( defined( __clang__ )                      &&    \
+          ( defined( __apple_build_version__ )            \
+              ? __apple_build_version__ >= 12000000       \
+              : __clang_major__ >= 10 ) )
 #    define FALL_THROUGH  __attribute__(( __fallthrough__ ))
 #  else
 #    define FALL_THROUGH  ( (void)0 )
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h
index d1baa392bd643..d9aea236024fb 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h
@@ -332,9 +332,9 @@ FT_BEGIN_HEADER
    * Based on geometric considerations we use the following inequality to
    * identify a degenerate matrix.
    *
-   *   50 * abs(xx*yy - xy*yx) < xx^2 + xy^2 + yx^2 + yy^2
+   *   32 * abs(xx*yy - xy*yx) < xx^2 + xy^2 + yx^2 + yy^2
    *
-   * Value 50 is heuristic.
+   * Value 32 is heuristic.
    */
   FT_BASE( FT_Bool )
   FT_Matrix_Check( const FT_Matrix*  matrix );
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h
index f78912ca0c72a..9001c07ad0b4a 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h
@@ -157,6 +157,7 @@ FT_BEGIN_HEADER
    *     A handle to a function used to select a new fixed size.  It is used
    *     only if @FT_FACE_FLAG_FIXED_SIZES is set.  Can be set to 0 if the
    *     scaling done in the base layer suffices.
+   *
    * @note:
    *   Most function pointers, with the exception of `load_glyph`, can be set
    *   to 0 to indicate a default behaviour.
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h
index b7c66c35deff8..c4b21d6144ea0 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h
@@ -28,13 +28,19 @@ FT_BEGIN_HEADER
 
   typedef struct  GX_ItemVarDataRec_
   {
-    FT_UInt            itemCount;       /* number of delta sets per item    */
-    FT_UInt            regionIdxCount;  /* number of region indices         */
-    FT_UInt*           regionIndices;   /* array of `regionCount' indices;  */
-                                        /* these index `varRegionList'      */
-    FT_ItemVarDelta*   deltaSet;        /* array of `itemCount' deltas      */
-                                        /* use `innerIndex' for this array  */
-
+    FT_UInt            itemCount;      /* Number of delta sets per item.   */
+    FT_UInt            regionIdxCount; /* Number of region indices.        */
+    FT_UInt*           regionIndices;  /* Array of `regionCount` indices;  */
+                                       /* these index `varRegionList`.     */
+    FT_Byte*           deltaSet;       /* Array of `itemCount` deltas;     */
+                                       /* use `innerIndex` for this array. */
+    FT_UShort          wordDeltaCount; /* Number of the first 32-bit ints  */
+                                       /* or 16-bit ints of `deltaSet`     */
+                                       /* depending on `longWords`.        */
+    FT_Bool            longWords;      /* If true, `deltaSet` is a 32-bit  */
+                                       /* array followed by a 16-bit       */
+                                       /* array, otherwise a 16-bit array  */
+                                       /* followed by an 8-bit array.      */
   } GX_ItemVarDataRec, *GX_ItemVarData;
 
 
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h
index e588ea4872a14..167617ebb3d0e 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h
@@ -77,6 +77,9 @@ FT_BEGIN_HEADER
   typedef void
   (*FT_Metrics_Adjust_Func)( FT_Face  face );
 
+  typedef FT_Error
+  (*FT_Size_Reset_Func)( FT_Size  size );
+
 
   FT_DEFINE_SERVICE( MetricsVariations )
   {
@@ -90,6 +93,7 @@ FT_BEGIN_HEADER
     FT_VOrg_Adjust_Func      vorg_adjust;
 
     FT_Metrics_Adjust_Func   metrics_adjust;
+    FT_Size_Reset_Func       size_reset;
   };
 
 
@@ -101,7 +105,8 @@ FT_BEGIN_HEADER
                                                 tsb_adjust_,       \
                                                 bsb_adjust_,       \
                                                 vorg_adjust_,      \
-                                                metrics_adjust_  ) \
+                                                metrics_adjust_,   \
+                                                size_reset_      ) \
   static const FT_Service_MetricsVariationsRec  class_ =           \
   {                                                                \
     hadvance_adjust_,                                              \
@@ -111,7 +116,8 @@ FT_BEGIN_HEADER
     tsb_adjust_,                                                   \
     bsb_adjust_,                                                   \
     vorg_adjust_,                                                  \
-    metrics_adjust_                                                \
+    metrics_adjust_,                                               \
+    size_reset_                                                    \
   };
 
   /* */
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h
index d94204232e1a3..7e76ab8324e43 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h
@@ -60,9 +60,9 @@ FT_BEGIN_HEADER
   /* use return value -1 to indicate that the new coordinates  */
   /* are equal to the current ones; no changes are thus needed */
   typedef FT_Error
-  (*FT_Set_MM_Blend_Func)( FT_Face   face,
-                           FT_UInt   num_coords,
-                           FT_Long*  coords );
+  (*FT_Set_MM_Blend_Func)( FT_Face    face,
+                           FT_UInt    num_coords,
+                           FT_Fixed*  coords );
 
   typedef FT_Error
   (*FT_Get_Var_Design_Func)( FT_Face    face,
@@ -70,13 +70,17 @@ FT_BEGIN_HEADER
                              FT_Fixed*  coords );
 
   typedef FT_Error
-  (*FT_Set_Instance_Func)( FT_Face  face,
-                           FT_UInt  instance_index );
+  (*FT_Set_Named_Instance_Func)( FT_Face  face,
+                                 FT_UInt  instance_index );
 
   typedef FT_Error
-  (*FT_Get_MM_Blend_Func)( FT_Face   face,
-                           FT_UInt   num_coords,
-                           FT_Long*  coords );
+  (*FT_Get_Default_Named_Instance_Func)( FT_Face   face,
+                                         FT_UInt  *instance_index );
+
+  typedef FT_Error
+  (*FT_Get_MM_Blend_Func)( FT_Face    face,
+                           FT_UInt    num_coords,
+                           FT_Fixed*  coords );
 
   typedef FT_Error
   (*FT_Get_Var_Blend_Func)( FT_Face      face,
@@ -86,7 +90,7 @@ FT_BEGIN_HEADER
                             FT_MM_Var*  *mm_var );
 
   typedef void
-  (*FT_Done_Blend_Func)( FT_Face );
+  (*FT_Done_Blend_Func)( FT_Face  face );
 
   typedef FT_Error
   (*FT_Set_MM_WeightVector_Func)( FT_Face    face,
@@ -98,6 +102,9 @@ FT_BEGIN_HEADER
                                   FT_UInt*   len,
                                   FT_Fixed*  weight_vector );
 
+  typedef void
+  (*FT_Construct_PS_Name_Func)( FT_Face  face );
+
   typedef FT_Error
   (*FT_Var_Load_Delta_Set_Idx_Map_Func)( FT_Face            face,
                                          FT_ULong           offset,
@@ -134,11 +141,13 @@ FT_BEGIN_HEADER
     FT_Get_MM_Var_Func                    get_mm_var;
     FT_Set_Var_Design_Func                set_var_design;
     FT_Get_Var_Design_Func                get_var_design;
-    FT_Set_Instance_Func                  set_instance;
+    FT_Set_Named_Instance_Func            set_named_instance;
+    FT_Get_Default_Named_Instance_Func    get_default_named_instance;
     FT_Set_MM_WeightVector_Func           set_mm_weightvector;
     FT_Get_MM_WeightVector_Func           get_mm_weightvector;
 
     /* for internal use; only needed for code sharing between modules */
+    FT_Construct_PS_Name_Func             construct_ps_name;
     FT_Var_Load_Delta_Set_Idx_Map_Func    load_delta_set_idx_map;
     FT_Var_Load_Item_Var_Store_Func       load_item_var_store;
     FT_Var_Get_Item_Delta_Func            get_item_delta;
@@ -149,43 +158,49 @@ FT_BEGIN_HEADER
   };
 
 
-#define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_,                  \
-                                           get_mm_,                 \
-                                           set_mm_design_,          \
-                                           set_mm_blend_,           \
-                                           get_mm_blend_,           \
-                                           get_mm_var_,             \
-                                           set_var_design_,         \
-                                           get_var_design_,         \
-                                           set_instance_,           \
-                                           set_weightvector_,       \
-                                           get_weightvector_,       \
-                                           load_delta_set_idx_map_, \
-                                           load_item_var_store_,    \
-                                           get_item_delta_,         \
-                                           done_item_var_store_,    \
-                                           done_delta_set_idx_map_, \
-                                           get_var_blend_,          \
-                                           done_blend_ )            \
-  static const FT_Service_MultiMastersRec  class_ =                 \
-  {                                                                 \
-    get_mm_,                                                        \
-    set_mm_design_,                                                 \
-    set_mm_blend_,                                                  \
-    get_mm_blend_,                                                  \
-    get_mm_var_,                                                    \
-    set_var_design_,                                                \
-    get_var_design_,                                                \
-    set_instance_,                                                  \
-    set_weightvector_,                                              \
-    get_weightvector_,                                              \
-    load_delta_set_idx_map_,                                        \
-    load_item_var_store_,                                           \
-    get_item_delta_,                                                \
-    done_item_var_store_,                                           \
-    done_delta_set_idx_map_,                                        \
-    get_var_blend_,                                                 \
-    done_blend_                                                     \
+#define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_,                      \
+                                           get_mm_,                     \
+                                           set_mm_design_,              \
+                                           set_mm_blend_,               \
+                                           get_mm_blend_,               \
+                                           get_mm_var_,                 \
+                                           set_var_design_,             \
+                                           get_var_design_,             \
+                                           set_named_instance_,         \
+                                           get_default_named_instance_, \
+                                           set_mm_weightvector_,        \
+                                           get_mm_weightvector_,        \
+                                                                        \
+                                           construct_ps_name_,          \
+                                           load_delta_set_idx_map_,     \
+                                           load_item_var_store_,        \
+                                           get_item_delta_,             \
+                                           done_item_var_store_,        \
+                                           done_delta_set_idx_map_,     \
+                                           get_var_blend_,              \
+                                           done_blend_ )                \
+  static const FT_Service_MultiMastersRec  class_ =                     \
+  {                                                                     \
+    get_mm_,                                                            \
+    set_mm_design_,                                                     \
+    set_mm_blend_,                                                      \
+    get_mm_blend_,                                                      \
+    get_mm_var_,                                                        \
+    set_var_design_,                                                    \
+    get_var_design_,                                                    \
+    set_named_instance_,                                                \
+    get_default_named_instance_,                                        \
+    set_mm_weightvector_,                                               \
+    get_mm_weightvector_,                                               \
+                                                                        \
+    construct_ps_name_,                                                 \
+    load_delta_set_idx_map_,                                            \
+    load_item_var_store_,                                               \
+    get_item_delta_,                                                    \
+    done_item_var_store_,                                               \
+    done_delta_set_idx_map_,                                            \
+    get_var_blend_,                                                     \
+    done_blend_                                                         \
   };
 
   /* */
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h
index fd99d857e47d3..6e599f3aabe40 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h
@@ -97,7 +97,7 @@ FT_BEGIN_HEADER
   (*PS_Unicodes_CharIndexFunc)( PS_Unicodes  unicodes,
                                 FT_UInt32    unicode );
 
-  typedef FT_UInt32
+  typedef FT_UInt
   (*PS_Unicodes_CharNextFunc)( PS_Unicodes  unicodes,
                                FT_UInt32   *unicode );
 
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h
index 5a105c5879534..b9c94398fd155 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h
@@ -201,30 +201,30 @@ FT_BEGIN_HEADER
 
   typedef struct  T1_FaceRec_
   {
-    FT_FaceRec      root;
-    T1_FontRec      type1;
-    const void*     psnames;
-    const void*     psaux;
-    const void*     afm_data;
-    FT_CharMapRec   charmaprecs[2];
-    FT_CharMap      charmaps[2];
+    FT_FaceRec     root;
+    T1_FontRec     type1;
+    const void*    psnames;
+    const void*    psaux;
+    const void*    afm_data;
+    FT_CharMapRec  charmaprecs[2];
+    FT_CharMap     charmaps[2];
 
     /* support for Multiple Masters fonts */
-    PS_Blend        blend;
+    PS_Blend       blend;
 
     /* undocumented, optional: indices of subroutines that express      */
     /* the NormalizeDesignVector and the ConvertDesignVector procedure, */
     /* respectively, as Type 2 charstrings; -1 if keywords not present  */
-    FT_Int           ndv_idx;
-    FT_Int           cdv_idx;
+    FT_Int         ndv_idx;
+    FT_Int         cdv_idx;
 
     /* undocumented, optional: has the same meaning as len_buildchar */
     /* for Type 2 fonts; manipulated by othersubrs 19, 24, and 25    */
-    FT_UInt          len_buildchar;
-    FT_Long*         buildchar;
+    FT_UInt        len_buildchar;
+    FT_Long*       buildchar;
 
     /* since version 2.1 - interface to PostScript hinter */
-    const void*     pshinter;
+    const void*    pshinter;
 
   } T1_FaceRec;
 
diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h
index 3b521924ca5b5..b9788c7831ec5 100644
--- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h
+++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h
@@ -779,13 +779,15 @@ FT_BEGIN_HEADER
   /**************************************************************************
    *
    * @struct:
-   *   TT_Post_20Rec
+   *   TT_Post_NamesRec
    *
    * @description:
-   *   Postscript names sub-table, format 2.0.  Stores the PS name of each
-   *   glyph in the font face.
+   *   Postscript names table, either format 2.0 or 2.5.
    *
    * @fields:
+   *   loaded ::
+   *     A flag to indicate whether the PS names are loaded.
+   *
    *   num_glyphs ::
    *     The number of named glyphs in the table.
    *
@@ -798,68 +800,13 @@ FT_BEGIN_HEADER
    *   glyph_names ::
    *     The PS names not in Mac Encoding.
    */
-  typedef struct  TT_Post_20Rec_
+  typedef struct  TT_Post_NamesRec_
   {
+    FT_Bool     loaded;
     FT_UShort   num_glyphs;
     FT_UShort   num_names;
     FT_UShort*  glyph_indices;
-    FT_Char**   glyph_names;
-
-  } TT_Post_20Rec, *TT_Post_20;
-
-
-  /**************************************************************************
-   *
-   * @struct:
-   *   TT_Post_25Rec
-   *
-   * @description:
-   *   Postscript names sub-table, format 2.5.  Stores the PS name of each
-   *   glyph in the font face.
-   *
-   * @fields:
-   *   num_glyphs ::
-   *     The number of glyphs in the table.
-   *
-   *   offsets ::
-   *     An array of signed offsets in a normal Mac Postscript name encoding.
-   */
-  typedef struct  TT_Post_25_
-  {
-    FT_UShort  num_glyphs;
-    FT_Char*   offsets;
-
-  } TT_Post_25Rec, *TT_Post_25;
-
-
-  /**************************************************************************
-   *
-   * @struct:
-   *   TT_Post_NamesRec
-   *
-   * @description:
-   *   Postscript names table, either format 2.0 or 2.5.
-   *
-   * @fields:
-   *   loaded ::
-   *     A flag to indicate whether the PS names are loaded.
-   *
-   *   format_20 ::
-   *     The sub-table used for format 2.0.
-   *
-   *   format_25 ::
-   *     The sub-table used for format 2.5.
-   */
-  typedef struct  TT_Post_NamesRec_
-  {
-    FT_Bool  loaded;
-
-    union
-    {
-      TT_Post_20Rec  format_20;
-      TT_Post_25Rec  format_25;
-
-    } names;
+    FT_Byte**   glyph_names;
 
   } TT_Post_NamesRec, *TT_Post_Names;
 
@@ -1253,12 +1200,16 @@ FT_BEGIN_HEADER
    *   mm ::
    *     A pointer to the Multiple Masters service.
    *
-   *   var ::
-   *     A pointer to the Metrics Variations service.
+   *   tt_var ::
+   *     A pointer to the Metrics Variations service for the "truetype"
+   *     driver.
    *
-   *   hdmx ::
-   *     The face's horizontal device metrics ('hdmx' table).  This table is
-   *     optional in TrueType/OpenType fonts.
+   *   face_var ::
+   *     A pointer to the Metrics Variations service for this `TT_Face`'s
+   *     driver.
+   *
+   *   psaux ::
+   *     A pointer to the PostScript Auxiliary service.
    *
    *   gasp ::
    *     The grid-fitting and scaling properties table ('gasp').  This table
@@ -1364,6 +1315,12 @@ FT_BEGIN_HEADER
    *   var_postscript_prefix_len ::
    *     The length of the `var_postscript_prefix` string.
    *
+   *   var_default_named_instance ::
+   *     The index of the default named instance.
+   *
+   *   non_var_style_name ::
+   *     The non-variation style name, used as a backup.
+   *
    *   horz_metrics_size ::
    *     The size of the 'hmtx' table.
    *
@@ -1410,14 +1367,6 @@ FT_BEGIN_HEADER
    *     A mapping between the strike indices exposed by the API and the
    *     indices used in the font's sbit table.
    *
-   *   cpal ::
-   *     A pointer to data related to the 'CPAL' table.  `NULL` if the table
-   *     is not available.
-   *
-   *   colr ::
-   *     A pointer to data related to the 'COLR' table.  `NULL` if the table
-   *     is not available.
-   *
    *   kern_table ::
    *     A pointer to the 'kern' table.
    *
@@ -1445,19 +1394,23 @@ FT_BEGIN_HEADER
    *   vert_metrics_offset ::
    *     The file offset of the 'vmtx' table.
    *
-   *   sph_found_func_flags ::
-   *     Flags identifying special bytecode functions (used by the v38
-   *     implementation of the bytecode interpreter).
-   *
-   *   sph_compatibility_mode ::
-   *     This flag is set if we are in ClearType backward compatibility mode
-   *     (used by the v38 implementation of the bytecode interpreter).
-   *
    *   ebdt_start ::
    *     The file offset of the sbit data table (CBDT, bdat, etc.).
    *
    *   ebdt_size ::
    *     The size of the sbit data table.
+   *
+   *   cpal ::
+   *     A pointer to data related to the 'CPAL' table.  `NULL` if the table
+   *     is not available.
+   *
+   *   colr ::
+   *     A pointer to data related to the 'COLR' table.  `NULL` if the table
+   *     is not available.
+   *
+   *   svg ::
+   *     A pointer to data related to the 'SVG' table.  `NULL` if the table
+   *     is not available.
    */
   typedef struct  TT_FaceRec_
   {
@@ -1508,8 +1461,14 @@ FT_BEGIN_HEADER
     void*                 mm;
 
     /* a typeless pointer to the FT_Service_MetricsVariationsRec table */
-    /* used to handle the HVAR, VVAR, and MVAR OpenType tables         */
-    void*                 var;
+    /* used to handle the HVAR, VVAR, and MVAR OpenType tables by the  */
+    /* "truetype" driver                                               */
+    void*                 tt_var;
+
+    /* a typeless pointer to the FT_Service_MetricsVariationsRec table */
+    /* used to handle the HVAR, VVAR, and MVAR OpenType tables by this */
+    /* TT_Face's driver                                                */
+    void*                 face_var;             /* since 2.13.1 */
 #endif
 
     /* a typeless pointer to the PostScript Aux service */
@@ -1591,6 +1550,9 @@ FT_BEGIN_HEADER
     const char*           var_postscript_prefix;     /* since 2.7.2 */
     FT_UInt               var_postscript_prefix_len; /* since 2.7.2 */
 
+    FT_UInt               var_default_named_instance;  /* since 2.13.1 */
+
+    const char*           non_var_style_name;  /* since 2.13.1 */
 #endif
 
     /* since version 2.2 */
@@ -1627,13 +1589,6 @@ FT_BEGIN_HEADER
     FT_ULong              horz_metrics_offset;
     FT_ULong              vert_metrics_offset;
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    /* since 2.4.12 */
-    FT_ULong              sph_found_func_flags; /* special functions found */
-                                                /* for this face           */
-    FT_Bool               sph_compatibility_mode;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
     /* since 2.7 */
     FT_ULong              ebdt_start;  /* either `CBDT', `EBDT', or `bdat' */
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat
index b7efe8be6ce71..8299baa2591d3 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat
@@ -89,7 +89,7 @@ AF_BLUE_STRING_ENUM AF_BLUE_STRINGS_ARRAY AF_BLUE_STRING_MAX_LEN:
     "ت ث ط ظ ك"
   // We don't necessarily have access to medial forms via Unicode in case
   // Arabic presentational forms are missing.  The only character that is
-  // guaranteed to have the same vertical position with joining (this is,
+  // guaranteed to have the same vertical position with joining (that is,
   // non-isolated) forms is U+0640, ARABIC TATWEEL, which must join both
   // round and flat curves.
   AF_BLUE_STRING_ARABIC_JOIN
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c
index 5daefff359cb7..f414289adcd25 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c
@@ -417,16 +417,14 @@
 
         {
           FT_Int  nn;
-          FT_Int  first = 0;
-          FT_Int  last  = -1;
+          FT_Int  pp, first, last;
 
 
-          for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
+          last = -1;
+          for ( nn = 0; nn < outline.n_contours; nn++ )
           {
-            FT_Int  pp;
-
-
-            last = outline.contours[nn];
+            first = last + 1;
+            last  = outline.contours[nn];
 
             /* Avoid single-point contours since they are never rasterized. */
             /* In some fonts, they correspond to mark attachment points     */
@@ -569,8 +567,8 @@
   af_cjk_metrics_check_digits( AF_CJKMetrics  metrics,
                                FT_Face        face )
   {
-    FT_Bool   started = 0, same_width = 1;
-    FT_Fixed  advance = 0, old_advance = 0;
+    FT_Bool  started = 0, same_width = 1;
+    FT_Long  advance = 0, old_advance = 0;
 
     /* If HarfBuzz is not available, we need a pointer to a single */
     /* unsigned long value.                                        */
@@ -635,10 +633,11 @@
   /* Initialize global metrics. */
 
   FT_LOCAL_DEF( FT_Error )
-  af_cjk_metrics_init( AF_CJKMetrics  metrics,
-                       FT_Face        face )
+  af_cjk_metrics_init( AF_StyleMetrics  metrics_,  /* AF_CJKMetrics */
+                       FT_Face          face )
   {
-    FT_CharMap  oldmap = face->charmap;
+    AF_CJKMetrics  metrics = (AF_CJKMetrics)metrics_;
+    FT_CharMap     oldmap  = face->charmap;
 
 
     metrics->units_per_em = face->units_per_EM;
@@ -756,9 +755,12 @@
   /* Scale global values in both directions. */
 
   FT_LOCAL_DEF( void )
-  af_cjk_metrics_scale( AF_CJKMetrics  metrics,
-                        AF_Scaler      scaler )
+  af_cjk_metrics_scale( AF_StyleMetrics  metrics_,   /* AF_CJKMetrics */
+                        AF_Scaler        scaler )
   {
+    AF_CJKMetrics  metrics = (AF_CJKMetrics)metrics_;
+
+
     /* we copy the whole structure since the x and y scaling values */
     /* are not modified, contrary to e.g. the `latin' auto-hinter   */
     metrics->root.scaler = *scaler;
@@ -771,11 +773,14 @@
   /* Extract standard_width from writing system/script specific */
   /* metrics class.                                             */
 
-  FT_LOCAL_DEF( void )
-  af_cjk_get_standard_widths( AF_CJKMetrics  metrics,
-                              FT_Pos*        stdHW,
-                              FT_Pos*        stdVW )
+  FT_CALLBACK_DEF( void )
+  af_cjk_get_standard_widths( AF_StyleMetrics  metrics_,  /* AF_CJKMetrics */
+                              FT_Pos*          stdHW,
+                              FT_Pos*          stdVW )
   {
+    AF_CJKMetrics  metrics = (AF_CJKMetrics)metrics_;
+
+
     if ( stdHW )
       *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
 
@@ -1376,9 +1381,10 @@
   /* Initalize hinting engine. */
 
   FT_LOCAL_DEF( FT_Error )
-  af_cjk_hints_init( AF_GlyphHints  hints,
-                     AF_CJKMetrics  metrics )
+  af_cjk_hints_init( AF_GlyphHints    hints,
+                     AF_StyleMetrics  metrics_ )   /* AF_CJKMetrics */
   {
+    AF_CJKMetrics   metrics = (AF_CJKMetrics)metrics_;
     FT_Render_Mode  mode;
     FT_UInt32       scaler_flags, other_flags;
 
@@ -1628,7 +1634,7 @@
 
     stem_edge->pos = base_edge->pos + fitted_width;
 
-    FT_TRACE5(( "  CJKLINK: edge %ld @%d (opos=%.2f) linked to %.2f,"
+    FT_TRACE5(( "  CJKLINK: edge %td @%d (opos=%.2f) linked to %.2f,"
                 " dist was %.2f, now %.2f\n",
                 stem_edge - hints->axis[dim].edges, stem_edge->fpos,
                 (double)stem_edge->opos / 64,
@@ -1852,7 +1858,7 @@
           continue;
 
 #ifdef FT_DEBUG_LEVEL_TRACE
-        FT_TRACE5(( "  CJKBLUE: edge %ld @%d (opos=%.2f) snapped to %.2f,"
+        FT_TRACE5(( "  CJKBLUE: edge %td @%d (opos=%.2f) snapped to %.2f,"
                     " was %.2f\n",
                     edge1 - edges, edge1->fpos, (double)edge1->opos / 64,
                     (double)blue->fit / 64, (double)edge1->pos / 64 ));
@@ -1916,7 +1922,7 @@
       /* this should not happen, but it's better to be safe */
       if ( edge2->blue_edge )
       {
-        FT_TRACE5(( "ASSERTION FAILED for edge %ld\n", edge2-edges ));
+        FT_TRACE5(( "ASSERTION FAILED for edge %td\n", edge2 - edges ));
 
         af_cjk_align_linked_edge( hints, dim, edge2, edge );
         edge->flags |= AF_EDGE_DONE;
@@ -2268,11 +2274,13 @@
   /* Apply the complete hinting algorithm to a CJK glyph. */
 
   FT_LOCAL_DEF( FT_Error )
-  af_cjk_hints_apply( FT_UInt        glyph_index,
-                      AF_GlyphHints  hints,
-                      FT_Outline*    outline,
-                      AF_CJKMetrics  metrics )
+  af_cjk_hints_apply( FT_UInt          glyph_index,
+                      AF_GlyphHints    hints,
+                      FT_Outline*      outline,
+                      AF_StyleMetrics  metrics_ )   /* AF_CJKMetrics */
   {
+    AF_CJKMetrics  metrics = (AF_CJKMetrics)metrics_;
+
     FT_Error  error;
     int       dim;
 
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h
index bd7b81b3e24b4..f380ef6e03211 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h
@@ -103,22 +103,22 @@ FT_BEGIN_HEADER
 
 #ifdef AF_CONFIG_OPTION_CJK
   FT_LOCAL( FT_Error )
-  af_cjk_metrics_init( AF_CJKMetrics  metrics,
-                       FT_Face        face );
+  af_cjk_metrics_init( AF_StyleMetrics  metrics,
+                       FT_Face          face );
 
   FT_LOCAL( void )
-  af_cjk_metrics_scale( AF_CJKMetrics  metrics,
-                        AF_Scaler      scaler );
+  af_cjk_metrics_scale( AF_StyleMetrics  metrics,
+                        AF_Scaler        scaler );
 
   FT_LOCAL( FT_Error )
-  af_cjk_hints_init( AF_GlyphHints  hints,
-                     AF_CJKMetrics  metrics );
+  af_cjk_hints_init( AF_GlyphHints    hints,
+                     AF_StyleMetrics  metrics );
 
   FT_LOCAL( FT_Error )
-  af_cjk_hints_apply( FT_UInt        glyph_index,
-                      AF_GlyphHints  hints,
-                      FT_Outline*    outline,
-                      AF_CJKMetrics  metrics );
+  af_cjk_hints_apply( FT_UInt          glyph_index,
+                      AF_GlyphHints    hints,
+                      FT_Outline*      outline,
+                      AF_StyleMetrics  metrics );
 
   /* shared; called from afindic.c */
   FT_LOCAL( void )
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c
index ede27eb16609f..b1957570f03bf 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c
@@ -376,8 +376,11 @@
 
 
   FT_LOCAL_DEF( void )
-  af_face_globals_free( AF_FaceGlobals  globals )
+  af_face_globals_free( void*  globals_ )
   {
+    AF_FaceGlobals  globals = (AF_FaceGlobals)globals_;
+
+
     if ( globals )
     {
       FT_Memory  memory = globals->face->memory;
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h
index 83a7c2ff15bc0..66170e419ddc9 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h
@@ -156,7 +156,7 @@ FT_BEGIN_HEADER
                                AF_StyleMetrics  *ametrics );
 
   FT_LOCAL( void )
-  af_face_globals_free( AF_FaceGlobals  globals );
+  af_face_globals_free( void*  globals );
 
   FT_LOCAL( FT_Bool )
   af_face_globals_is_digit( AF_FaceGlobals  globals,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c b/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c
index 6515af9f04ead..e4a378fbf74ca 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c
@@ -320,8 +320,9 @@
 
 
   static char*
-  af_print_idx( char* p,
-                int   idx )
+  af_print_idx( char*   p,
+                size_t  n,
+                int     idx )
   {
     if ( idx == -1 )
     {
@@ -330,7 +331,7 @@
       p[2] = '\0';
     }
     else
-      ft_sprintf( p, "%d", idx );
+      ft_snprintf( p, n, "%d", idx );
 
     return p;
   }
@@ -457,12 +458,12 @@
                 " %5d %5d %7.2f %7.2f %7.2f %7.2f"
                 " %5s %5s %5s %5s\n",
                 point_idx,
-                af_print_idx( buf1,
+                af_print_idx( buf1, 16,
                               af_get_edge_index( hints, segment_idx_1, 1 ) ),
-                af_print_idx( buf2, segment_idx_1 ),
-                af_print_idx( buf3,
+                af_print_idx( buf2, 16, segment_idx_1 ),
+                af_print_idx( buf3, 16,
                               af_get_edge_index( hints, segment_idx_0, 0 ) ),
-                af_print_idx( buf4, segment_idx_0 ),
+                af_print_idx( buf4, 16, segment_idx_0 ),
                 ( point->flags & AF_FLAG_NEAR )
                   ? " near "
                   : ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
@@ -476,18 +477,22 @@
                 (double)point->x / 64,
                 (double)point->y / 64,
 
-                af_print_idx( buf5, af_get_strong_edge_index( hints,
-                                                              point->before,
-                                                              1 ) ),
-                af_print_idx( buf6, af_get_strong_edge_index( hints,
-                                                              point->after,
-                                                              1 ) ),
-                af_print_idx( buf7, af_get_strong_edge_index( hints,
-                                                              point->before,
-                                                              0 ) ),
-                af_print_idx( buf8, af_get_strong_edge_index( hints,
-                                                              point->after,
-                                                              0 ) ) ));
+                af_print_idx( buf5, 16,
+                              af_get_strong_edge_index( hints,
+                                                        point->before,
+                                                        1 ) ),
+                af_print_idx( buf6, 16,
+                              af_get_strong_edge_index( hints,
+                                                        point->after,
+                                                        1 ) ),
+                af_print_idx( buf7, 16,
+                              af_get_strong_edge_index( hints,
+                                                        point->before,
+                                                        0 ) ),
+                af_print_idx( buf8, 16,
+                              af_get_strong_edge_index( hints,
+                                                        point->after,
+                                                        0 ) ) ));
     }
     AF_DUMP(( "\n" ));
   }
@@ -574,9 +579,12 @@
                   AF_INDEX_NUM( seg->first, points ),
                   AF_INDEX_NUM( seg->last, points ),
 
-                  af_print_idx( buf1, AF_INDEX_NUM( seg->link, segments ) ),
-                  af_print_idx( buf2, AF_INDEX_NUM( seg->serif, segments ) ),
-                  af_print_idx( buf3, AF_INDEX_NUM( seg->edge, edges ) ),
+                  af_print_idx( buf1, 16,
+                                AF_INDEX_NUM( seg->link, segments ) ),
+                  af_print_idx( buf2, 16,
+                                AF_INDEX_NUM( seg->serif, segments ) ),
+                  af_print_idx( buf3, 16,
+                                AF_INDEX_NUM( seg->edge, edges ) ),
 
                   seg->height,
                   seg->height - ( seg->max_coord - seg->min_coord ),
@@ -716,8 +724,10 @@
                   AF_INDEX_NUM( edge, edges ),
                   (double)(int)edge->opos / 64,
                   af_dir_str( (AF_Direction)edge->dir ),
-                  af_print_idx( buf1, AF_INDEX_NUM( edge->link, edges ) ),
-                  af_print_idx( buf2, AF_INDEX_NUM( edge->serif, edges ) ),
+                  af_print_idx( buf1, 16,
+                                AF_INDEX_NUM( edge->link, edges ) ),
+                  af_print_idx( buf2, 16,
+                                AF_INDEX_NUM( edge->serif, edges ) ),
 
                   edge->blue_edge ? 'y' : 'n',
                   (double)edge->opos / 64,
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c b/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c
index 289a09d71d8a5..7fb12c63d5a35 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c
@@ -28,9 +28,12 @@
 
 
   static FT_Error
-  af_indic_metrics_init( AF_CJKMetrics  metrics,
-                         FT_Face        face )
+  af_indic_metrics_init( AF_StyleMetrics  metrics_, /* AF_CJKMetrics */
+                         FT_Face          face )
   {
+    AF_CJKMetrics  metrics = (AF_CJKMetrics)metrics_;
+
+
     /* skip blue zone init in CJK routines */
     FT_CharMap  oldmap = face->charmap;
 
@@ -55,8 +58,8 @@
 
 
   static void
-  af_indic_metrics_scale( AF_CJKMetrics  metrics,
-                          AF_Scaler      scaler )
+  af_indic_metrics_scale( AF_StyleMetrics  metrics,
+                          AF_Scaler        scaler )
   {
     /* use CJK routines */
     af_cjk_metrics_scale( metrics, scaler );
@@ -64,8 +67,8 @@
 
 
   static FT_Error
-  af_indic_hints_init( AF_GlyphHints  hints,
-                       AF_CJKMetrics  metrics )
+  af_indic_hints_init( AF_GlyphHints    hints,
+                       AF_StyleMetrics  metrics )
   {
     /* use CJK routines */
     return af_cjk_hints_init( hints, metrics );
@@ -73,10 +76,10 @@
 
 
   static FT_Error
-  af_indic_hints_apply( FT_UInt        glyph_index,
-                        AF_GlyphHints  hints,
-                        FT_Outline*    outline,
-                        AF_CJKMetrics  metrics )
+  af_indic_hints_apply( FT_UInt          glyph_index,
+                        AF_GlyphHints    hints,
+                        FT_Outline*      outline,
+                        AF_StyleMetrics  metrics )
   {
     /* use CJK routines */
     return af_cjk_hints_apply( glyph_index, hints, outline, metrics );
@@ -87,10 +90,13 @@
   /* metrics class.                                             */
 
   static void
-  af_indic_get_standard_widths( AF_CJKMetrics  metrics,
-                                FT_Pos*        stdHW,
-                                FT_Pos*        stdVW )
+  af_indic_get_standard_widths( AF_StyleMetrics  metrics_, /* AF_CJKMetrics */
+                                FT_Pos*          stdHW,
+                                FT_Pos*          stdVW )
   {
+    AF_CJKMetrics  metrics = (AF_CJKMetrics)metrics_;
+
+
     if ( stdHW )
       *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
 
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c
index 4b3c59b3c3117..b86367aa94dc6 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c
@@ -496,23 +496,20 @@
           /* now compute min or max point indices and coordinates */
           points             = outline.points;
           best_point         = -1;
+          best_contour_first = -1;
+          best_contour_last  = -1;
           best_y             = 0;  /* make compiler happy */
-          best_contour_first = 0;  /* ditto */
-          best_contour_last  = 0;  /* ditto */
 
           {
             FT_Int  nn;
-            FT_Int  first = 0;
-            FT_Int  last  = -1;
+            FT_Int  pp, first, last;
 
 
-            for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
+            last = -1;
+            for ( nn = 0; nn < outline.n_contours; nn++ )
             {
-              FT_Int  old_best_point = best_point;
-              FT_Int  pp;
-
-
-              last = outline.contours[nn];
+              first = last + 1;
+              last  = outline.contours[nn];
 
               /* Avoid single-point contours since they are never      */
               /* rasterized.  In some fonts, they correspond to mark   */
@@ -551,7 +548,7 @@
                 }
               }
 
-              if ( best_point != old_best_point )
+              if ( best_point > best_contour_last )
               {
                 best_contour_first = first;
                 best_contour_last  = last;
@@ -1025,7 +1022,7 @@
         {
           *a = *b;
           FT_TRACE5(( "blue zone overlap:"
-                      " adjusting %s %ld to %ld\n",
+                      " adjusting %s %td to %ld\n",
                       a_is_top ? "overshoot" : "reference",
                       blue_sorted[i] - axis->blues,
                       *a ));
@@ -1068,8 +1065,8 @@
   af_latin_metrics_check_digits( AF_LatinMetrics  metrics,
                                  FT_Face          face )
   {
-    FT_Bool   started = 0, same_width = 1;
-    FT_Fixed  advance = 0, old_advance = 0;
+    FT_Bool  started = 0, same_width = 1;
+    FT_Long  advance = 0, old_advance = 0;
 
     /* If HarfBuzz is not available, we need a pointer to a single */
     /* unsigned long value.                                        */
@@ -1134,9 +1131,11 @@
   /* Initialize global metrics. */
 
   FT_LOCAL_DEF( FT_Error )
-  af_latin_metrics_init( AF_LatinMetrics  metrics,
+  af_latin_metrics_init( AF_StyleMetrics  metrics_,   /* AF_LatinMetrics */
                          FT_Face          face )
   {
+    AF_LatinMetrics  metrics = (AF_LatinMetrics)metrics_;
+
     FT_Error  error = FT_Err_Ok;
 
     FT_CharMap  oldmap = face->charmap;
@@ -1489,9 +1488,12 @@
   /* Scale global values in both directions. */
 
   FT_LOCAL_DEF( void )
-  af_latin_metrics_scale( AF_LatinMetrics  metrics,
+  af_latin_metrics_scale( AF_StyleMetrics  metrics_,   /* AF_LatinMetrics */
                           AF_Scaler        scaler )
   {
+    AF_LatinMetrics  metrics = (AF_LatinMetrics)metrics_;
+
+
     metrics->root.scaler.render_mode = scaler->render_mode;
     metrics->root.scaler.face        = scaler->face;
     metrics->root.scaler.flags       = scaler->flags;
@@ -1504,11 +1506,14 @@
   /* Extract standard_width from writing system/script specific */
   /* metrics class.                                             */
 
-  FT_LOCAL_DEF( void )
-  af_latin_get_standard_widths( AF_LatinMetrics  metrics,
+  FT_CALLBACK_DEF( void )
+  af_latin_get_standard_widths( AF_StyleMetrics  metrics_, /* AF_LatinMetrics */
                                 FT_Pos*          stdHW,
                                 FT_Pos*          stdVW )
   {
+    AF_LatinMetrics  metrics = (AF_LatinMetrics)metrics_;
+
+
     if ( stdHW )
       *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
 
@@ -2041,7 +2046,7 @@
             max = seg2->max_coord;
 
           /* compute maximum coordinate difference of the two segments */
-          /* (this is, how much they overlap)                          */
+          /* (that is, how much they overlap)                          */
           len = max - min;
           if ( len >= len_threshold )
           {
@@ -2610,8 +2615,10 @@
 
   static FT_Error
   af_latin_hints_init( AF_GlyphHints    hints,
-                       AF_LatinMetrics  metrics )
+                       AF_StyleMetrics  metrics_ )   /* AF_LatinMetrics */
   {
+    AF_LatinMetrics  metrics = (AF_LatinMetrics)metrics_;
+
     FT_Render_Mode  mode;
     FT_UInt32       scaler_flags, other_flags;
     FT_Face         face = metrics->root.scaler.face;
@@ -2953,7 +2960,7 @@
 
     stem_edge->pos = base_edge->pos + fitted_width;
 
-    FT_TRACE5(( "  LINK: edge %ld (opos=%.2f) linked to %.2f,"
+    FT_TRACE5(( "  LINK: edge %td (opos=%.2f) linked to %.2f,"
                 " dist was %.2f, now %.2f\n",
                 stem_edge - hints->axis[dim].edges,
                 (double)stem_edge->opos / 64, (double)stem_edge->pos / 64,
@@ -3078,13 +3085,13 @@
 
 #ifdef FT_DEBUG_LEVEL_TRACE
         if ( !anchor )
-          FT_TRACE5(( "  BLUE_ANCHOR: edge %ld (opos=%.2f) snapped to %.2f,"
-                      " was %.2f (anchor=edge %ld)\n",
+          FT_TRACE5(( "  BLUE_ANCHOR: edge %td (opos=%.2f) snapped to %.2f,"
+                      " was %.2f (anchor=edge %td)\n",
                       edge1 - edges,
                       (double)edge1->opos / 64, (double)blue->fit / 64,
                       (double)edge1->pos / 64, edge - edges ));
         else
-          FT_TRACE5(( "  BLUE: edge %ld (opos=%.2f) snapped to %.2f,"
+          FT_TRACE5(( "  BLUE: edge %td (opos=%.2f) snapped to %.2f,"
                       " was %.2f\n",
                       edge1 - edges,
                       (double)edge1->opos / 64, (double)blue->fit / 64,
@@ -3134,7 +3141,7 @@
       /* this should not happen, but it's better to be safe */
       if ( edge2->blue_edge )
       {
-        FT_TRACE5(( "  ASSERTION FAILED for edge %ld\n", edge2 - edges ));
+        FT_TRACE5(( "  ASSERTION FAILED for edge %td\n", edge2 - edges ));
 
         af_latin_align_linked_edge( hints, dim, edge2, edge );
         edge->flags |= AF_EDGE_DONE;
@@ -3202,7 +3209,7 @@
         anchor       = edge;
         edge->flags |= AF_EDGE_DONE;
 
-        FT_TRACE5(( "  ANCHOR: edge %ld (opos=%.2f) and %ld (opos=%.2f)"
+        FT_TRACE5(( "  ANCHOR: edge %td (opos=%.2f) and %td (opos=%.2f)"
                     " snapped to %.2f and %.2f\n",
                     edge - edges, (double)edge->opos / 64,
                     edge2 - edges, (double)edge2->opos / 64,
@@ -3231,7 +3238,7 @@
 
         if ( edge2->flags & AF_EDGE_DONE )
         {
-          FT_TRACE5(( "  ADJUST: edge %ld (pos=%.2f) moved to %.2f\n",
+          FT_TRACE5(( "  ADJUST: edge %td (pos=%.2f) moved to %.2f\n",
                       edge - edges, (double)edge->pos / 64,
                       (double)( edge2->pos - cur_len ) / 64 ));
 
@@ -3272,7 +3279,7 @@
           edge->pos  = cur_pos1 - cur_len / 2;
           edge2->pos = cur_pos1 + cur_len / 2;
 
-          FT_TRACE5(( "  STEM: edge %ld (opos=%.2f) linked to %ld (opos=%.2f)"
+          FT_TRACE5(( "  STEM: edge %td (opos=%.2f) linked to %td (opos=%.2f)"
                       " snapped to %.2f and %.2f\n",
                       edge - edges, (double)edge->opos / 64,
                       edge2 - edges, (double)edge2->opos / 64,
@@ -3303,7 +3310,7 @@
           edge->pos  = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
           edge2->pos = edge->pos + cur_len;
 
-          FT_TRACE5(( "  STEM: edge %ld (opos=%.2f) linked to %ld (opos=%.2f)"
+          FT_TRACE5(( "  STEM: edge %td (opos=%.2f) linked to %td (opos=%.2f)"
                       " snapped to %.2f and %.2f\n",
                       edge - edges, (double)edge->opos / 64,
                       edge2 - edges, (double)edge2->opos / 64,
@@ -3326,7 +3333,7 @@
           if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
           {
 #ifdef FT_DEBUG_LEVEL_TRACE
-            FT_TRACE5(( "  BOUND: edge %ld (pos=%.2f) moved to %.2f\n",
+            FT_TRACE5(( "  BOUND: edge %td (pos=%.2f) moved to %.2f\n",
                         edge - edges,
                         (double)edge->pos / 64,
                         (double)edge[-1].pos / 64 ));
@@ -3428,7 +3435,7 @@
         if ( delta < 64 + 16 )
         {
           af_latin_align_serif_edge( hints, edge->serif, edge );
-          FT_TRACE5(( "  SERIF: edge %ld (opos=%.2f) serif to %ld (opos=%.2f)"
+          FT_TRACE5(( "  SERIF: edge %td (opos=%.2f) serif to %td (opos=%.2f)"
                       " aligned to %.2f\n",
                       edge - edges, (double)edge->opos / 64,
                       edge->serif - edges, (double)edge->serif->opos / 64,
@@ -3438,9 +3445,9 @@
         {
           edge->pos = FT_PIX_ROUND( edge->opos );
           anchor    = edge;
-          FT_TRACE5(( "  SERIF_ANCHOR: edge %ld (opos=%.2f)"
+          FT_TRACE5(( "  SERIF_ANCHOR: edge %td (opos=%.2f)"
                       " snapped to %.2f\n",
-                      edge-edges,
+                      edge - edges,
                       (double)edge->opos / 64, (double)edge->pos / 64 ));
         }
         else
@@ -3467,8 +3474,8 @@
                                      after->pos - before->pos,
                                      after->opos - before->opos );
 
-            FT_TRACE5(( "  SERIF_LINK1: edge %ld (opos=%.2f) snapped to %.2f"
-                        " from %ld (opos=%.2f)\n",
+            FT_TRACE5(( "  SERIF_LINK1: edge %td (opos=%.2f) snapped to %.2f"
+                        " from %td (opos=%.2f)\n",
                         edge - edges, (double)edge->opos / 64,
                         (double)edge->pos / 64,
                         before - edges, (double)before->opos / 64 ));
@@ -3477,7 +3484,7 @@
           {
             edge->pos = anchor->pos +
                         ( ( edge->opos - anchor->opos + 16 ) & ~31 );
-            FT_TRACE5(( "  SERIF_LINK2: edge %ld (opos=%.2f)"
+            FT_TRACE5(( "  SERIF_LINK2: edge %td (opos=%.2f)"
                         " snapped to %.2f\n",
                         edge - edges,
                         (double)edge->opos / 64, (double)edge->pos / 64 ));
@@ -3498,7 +3505,7 @@
           if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
           {
 #ifdef FT_DEBUG_LEVEL_TRACE
-            FT_TRACE5(( "  BOUND: edge %ld (pos=%.2f) moved to %.2f\n",
+            FT_TRACE5(( "  BOUND: edge %td (pos=%.2f) moved to %.2f\n",
                         edge - edges,
                         (double)edge->pos / 64,
                         (double)edge[-1].pos / 64 ));
@@ -3519,7 +3526,7 @@
           if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
           {
 #ifdef FT_DEBUG_LEVEL_TRACE
-            FT_TRACE5(( "  BOUND: edge %ld (pos=%.2f) moved to %.2f\n",
+            FT_TRACE5(( "  BOUND: edge %td (pos=%.2f) moved to %.2f\n",
                         edge - edges,
                         (double)edge->pos / 64,
                         (double)edge[1].pos / 64 ));
@@ -3547,8 +3554,10 @@
   af_latin_hints_apply( FT_UInt          glyph_index,
                         AF_GlyphHints    hints,
                         FT_Outline*      outline,
-                        AF_LatinMetrics  metrics )
+                        AF_StyleMetrics  metrics_ )    /* AF_LatinMetrics */
   {
+    AF_LatinMetrics  metrics = (AF_LatinMetrics)metrics_;
+
     FT_Error  error;
     int       dim;
 
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h
index 3c6a7ee4f62ac..31aa91d3bdb05 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h
@@ -116,11 +116,11 @@ FT_BEGIN_HEADER
 
 
   FT_LOCAL( FT_Error )
-  af_latin_metrics_init( AF_LatinMetrics  metrics,
+  af_latin_metrics_init( AF_StyleMetrics  metrics,
                          FT_Face          face );
 
   FT_LOCAL( void )
-  af_latin_metrics_scale( AF_LatinMetrics  metrics,
+  af_latin_metrics_scale( AF_StyleMetrics  metrics,
                           AF_Scaler        scaler );
 
   FT_LOCAL( void )
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c b/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c
index c8082796fe881..7c47d562af66f 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c
@@ -55,10 +55,8 @@
       error = af_face_globals_new( face, &loader->globals, module );
       if ( !error )
       {
-        face->autohint.data =
-          (FT_Pointer)loader->globals;
-        face->autohint.finalizer =
-          (FT_Generic_Finalizer)af_face_globals_free;
+        face->autohint.data      = (FT_Pointer)loader->globals;
+        face->autohint.finalizer = af_face_globals_free;
       }
     }
 
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c b/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c
index 92e5156ab2dc7..20a6b96bc4ff4 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c
@@ -89,10 +89,8 @@
       error = af_face_globals_new( face, &globals, module );
       if ( !error )
       {
-        face->autohint.data =
-          (FT_Pointer)globals;
-        face->autohint.finalizer =
-          (FT_Generic_Finalizer)af_face_globals_free;
+        face->autohint.data      = (FT_Pointer)globals;
+        face->autohint.finalizer = af_face_globals_free;
       }
     }
 
@@ -374,8 +372,9 @@
   FT_DEFINE_SERVICE_PROPERTIESREC(
     af_service_properties,
 
-    (FT_Properties_SetFunc)af_property_set,        /* set_property */
-    (FT_Properties_GetFunc)af_property_get )       /* get_property */
+    af_property_set,  /* FT_Properties_SetFunc set_property */
+    af_property_get   /* FT_Properties_GetFunc get_property */
+  )
 
 
   FT_DEFINE_SERVICEDESCREC1(
@@ -430,12 +429,14 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  af_autofitter_load_glyph( AF_Module     module,
-                            FT_GlyphSlot  slot,
-                            FT_Size       size,
-                            FT_UInt       glyph_index,
-                            FT_Int32      load_flags )
+  af_autofitter_load_glyph( FT_AutoHinter  module_,
+                            FT_GlyphSlot   slot,
+                            FT_Size        size,
+                            FT_UInt        glyph_index,
+                            FT_Int32       load_flags )
   {
+    AF_Module  module = (AF_Module)module_;
+
     FT_Error   error  = FT_Err_Ok;
     FT_Memory  memory = module->root.library->memory;
 
@@ -499,10 +500,10 @@
   FT_DEFINE_AUTOHINTER_INTERFACE(
     af_autofitter_interface,
 
-    NULL,                                                    /* reset_face */
-    NULL,                                              /* get_global_hints */
-    NULL,                                             /* done_global_hints */
-    (FT_AutoHinter_GlyphLoadFunc)af_autofitter_load_glyph    /* load_glyph */
+    NULL,                     /* FT_AutoHinter_GlobalResetFunc reset_face        */
+    NULL,                     /* FT_AutoHinter_GlobalGetFunc   get_global_hints  */
+    NULL,                     /* FT_AutoHinter_GlobalDoneFunc  done_global_hints */
+    af_autofitter_load_glyph  /* FT_AutoHinter_GlyphLoadFunc   load_glyph        */
   )
 
   FT_DEFINE_MODULE(
@@ -517,9 +518,9 @@
 
     (const void*)&af_autofitter_interface,
 
-    (FT_Module_Constructor)af_autofitter_init,  /* module_init   */
-    (FT_Module_Destructor) af_autofitter_done,  /* module_done   */
-    (FT_Module_Requester)  af_get_interface     /* get_interface */
+    af_autofitter_init,  /* FT_Module_Constructor module_init   */
+    af_autofitter_done,  /* FT_Module_Destructor  module_done   */
+    af_get_interface     /* FT_Module_Requester   get_interface */
   )
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c
index 1b8b870e89dda..abc6f1d292d42 100644
--- a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c
+++ b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c
@@ -258,7 +258,7 @@
     /*
      * We now check whether we can construct blue zones, using glyphs
      * covered by the feature only.  In case there is not a single zone
-     * (this is, not a single character is covered), we skip this coverage.
+     * (that is, not a single character is covered), we skip this coverage.
      *
      */
     if ( style_class->coverage != AF_COVERAGE_DEFAULT )
@@ -313,9 +313,9 @@
      * hinted and usually rendered glyph.
      *
      * Consider the superscript feature of font `pala.ttf': Some of the
-     * glyphs are `real', this is, they have a zero vertical offset, but
+     * glyphs are `real', that is, they have a zero vertical offset, but
      * most of them are small caps glyphs shifted up to the superscript
-     * position (this is, the `sups' feature is present in both the GSUB and
+     * position (that is, the `sups' feature is present in both the GSUB and
      * GPOS tables).  The code for blue zones computation actually uses a
      * feature's y offset so that the `real' glyphs get correct hints.  But
      * later on it is impossible to decide whether a glyph index belongs to,
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c b/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c
index 7dd71882ea5da..385fea4040103 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c
@@ -82,10 +82,13 @@
    * @Return:
    *   Always 0.  Needed for the interface only.
    */
-  static int
-  BBox_Move_To( FT_Vector*  to,
-                TBBox_Rec*  user )
+  FT_CALLBACK_DEF( int )
+  BBox_Move_To( const FT_Vector*  to,
+                void*             user_ )
   {
+    TBBox_Rec*  user = (TBBox_Rec*)user_;
+
+
     FT_UPDATE_BBOX( to, user->bbox );
 
     user->last = *to;
@@ -116,10 +119,13 @@
    * @Return:
    *   Always 0.  Needed for the interface only.
    */
-  static int
-  BBox_Line_To( FT_Vector*  to,
-                TBBox_Rec*  user )
+  FT_CALLBACK_DEF( int )
+  BBox_Line_To( const FT_Vector*  to,
+                void*             user_ )
   {
+    TBBox_Rec*  user = (TBBox_Rec*)user_;
+
+
     user->last = *to;
 
     return 0;
@@ -205,11 +211,14 @@
    *   In the case of a non-monotonous arc, we compute directly the
    *   extremum coordinates, as it is sufficiently fast.
    */
-  static int
-  BBox_Conic_To( FT_Vector*  control,
-                 FT_Vector*  to,
-                 TBBox_Rec*  user )
+  FT_CALLBACK_DEF( int )
+  BBox_Conic_To( const FT_Vector*  control,
+                 const FT_Vector*  to,
+                 void*             user_ )
   {
+    TBBox_Rec*  user = (TBBox_Rec*)user_;
+
+
     /* in case `to' is implicit and not included in bbox yet */
     FT_UPDATE_BBOX( to, user->bbox );
 
@@ -410,12 +419,15 @@
    *   In the case of a non-monotonous arc, we don't compute directly
    *   extremum coordinates, we subdivide instead.
    */
-  static int
-  BBox_Cubic_To( FT_Vector*  control1,
-                 FT_Vector*  control2,
-                 FT_Vector*  to,
-                 TBBox_Rec*  user )
+  FT_CALLBACK_DEF( int )
+  BBox_Cubic_To( const FT_Vector*  control1,
+                 const FT_Vector*  control2,
+                 const FT_Vector*  to,
+                 void*             user_ )
   {
+    TBBox_Rec*  user = (TBBox_Rec*)user_;
+
+
     /* We don't need to check `to' since it is always an on-point,    */
     /* thus within the bbox.  Only segments with an off-point outside */
     /* the bbox can possibly reach new extreme values.                */
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c b/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c
index 13e74f3353bf3..c5bc7e3b14eed 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c
@@ -749,65 +749,43 @@
   FT_BASE_DEF( FT_Bool )
   FT_Matrix_Check( const FT_Matrix*  matrix )
   {
-    FT_Matrix  m;
-    FT_Fixed   val[4];
-    FT_Fixed   nonzero_minval, maxval;
-    FT_Fixed   temp1, temp2;
-    FT_UInt    i;
+    FT_Fixed  xx, xy, yx, yy;
+    FT_Fixed  val;
+    FT_Int    shift;
+    FT_ULong  temp1, temp2;
 
 
     if ( !matrix )
       return 0;
 
-    val[0] = FT_ABS( matrix->xx );
-    val[1] = FT_ABS( matrix->xy );
-    val[2] = FT_ABS( matrix->yx );
-    val[3] = FT_ABS( matrix->yy );
+    xx  = matrix->xx;
+    xy  = matrix->xy;
+    yx  = matrix->yx;
+    yy  = matrix->yy;
+    val = FT_ABS( xx ) | FT_ABS( xy ) | FT_ABS( yx ) | FT_ABS( yy );
 
-    /*
-     * To avoid overflow, we ensure that each value is not larger than
-     *
-     *   int(sqrt(2^31 / 4)) = 23170  ;
-     *
-     * we also check that no value becomes zero if we have to scale.
-     */
-
-    maxval         = 0;
-    nonzero_minval = FT_LONG_MAX;
-
-    for ( i = 0; i < 4; i++ )
-    {
-      if ( val[i] > maxval )
-        maxval = val[i];
-      if ( val[i] && val[i] < nonzero_minval )
-        nonzero_minval = val[i];
-    }
-
-    /* we only handle 32bit values */
-    if ( maxval > 0x7FFFFFFFL )
+    /* we only handle non-zero 32-bit values */
+    if ( !val || val > 0x7FFFFFFFL )
       return 0;
 
-    if ( maxval > 23170 )
-    {
-      FT_Fixed  scale = FT_DivFix( maxval, 23170 );
-
+    /* Scale matrix to avoid the temp1 overflow, which is */
+    /* more stringent than avoiding the temp2 overflow.   */
 
-      if ( !FT_DivFix( nonzero_minval, scale ) )
-        return 0;    /* value range too large */
+    shift = FT_MSB( val ) - 12;
 
-      m.xx = FT_DivFix( matrix->xx, scale );
-      m.xy = FT_DivFix( matrix->xy, scale );
-      m.yx = FT_DivFix( matrix->yx, scale );
-      m.yy = FT_DivFix( matrix->yy, scale );
+    if ( shift > 0 )
+    {
+      xx >>= shift;
+      xy >>= shift;
+      yx >>= shift;
+      yy >>= shift;
     }
-    else
-      m = *matrix;
 
-    temp1 = FT_ABS( m.xx * m.yy - m.xy * m.yx );
-    temp2 = m.xx * m.xx + m.xy * m.xy + m.yx * m.yx + m.yy * m.yy;
+    temp1 = 32U * (FT_ULong)FT_ABS( xx * yy - xy * yx );
+    temp2 = (FT_ULong)( xx * xx ) + (FT_ULong)( xy * xy ) +
+            (FT_ULong)( yx * yx ) + (FT_ULong)( yy * yy );
 
-    if ( temp1 == 0         ||
-         temp2 / temp1 > 50 )
+    if ( temp1 <= temp2 )
       return 0;
 
     return 1;
@@ -1061,7 +1039,7 @@
     /*                                                           */
     /* This approach has the advantage that the angle between    */
     /* `in' and `out' is not checked.  In case one of the two    */
-    /* vectors is `dominant', this is, much larger than the      */
+    /* vectors is `dominant', that is, much larger than the      */
     /* other vector, we thus always have a flat corner.          */
     /*                                                           */
     /*                hypotenuse                                 */
@@ -1092,9 +1070,6 @@
   {
     FT_UInt   i;
     FT_Int64  temp;
-#ifndef FT_INT64
-    FT_Int64  halfUnit;
-#endif
 
 
 #ifdef FT_INT64
@@ -1103,7 +1078,7 @@
     for ( i = 0; i < count; ++i )
       temp += (FT_Int64)s[i] * f[i];
 
-    return ( temp + 0x8000 ) >> 16;
+    return (FT_Int32)( ( temp + 0x8000 ) >> 16 );
 #else
     temp.hi = 0;
     temp.lo = 0;
@@ -1139,13 +1114,10 @@
       FT_Add64( &temp, &multResult, &temp );
     }
 
-    /* Round value. */
-    halfUnit.hi = 0;
-    halfUnit.lo = 0x8000;
-    FT_Add64( &temp, &halfUnit, &temp );
+    /* Shift and round value. */
+    return (FT_Int32)( ( ( temp.hi << 16 ) | ( temp.lo >> 16 ) )
+                                     + ( 1 & ( temp.lo >> 15 ) ) );
 
-    return (FT_Int32)( ( (FT_Int32)( temp.hi & 0xFFFF ) << 16 ) |
-                                   ( temp.lo >> 16 )            );
 
 #endif /* !FT_INT64 */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c b/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c
index 6730c4c8d3802..8fab50dd017e6 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c
@@ -963,7 +963,7 @@
 #else  /* !FT_DEBUG_MEMORY */
 
   /* ANSI C doesn't like empty source files */
-  typedef int  _debug_mem_dummy;
+  typedef int  debug_mem_dummy_;
 
 #endif /* !FT_DEBUG_MEMORY */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftmac.c b/src/java.desktop/share/native/libfreetype/src/base/ftmac.c
index de34e834f255e..492d0553845dc 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftmac.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftmac.c
@@ -1082,7 +1082,7 @@
 #else /* !FT_MACINTOSH */
 
   /* ANSI C doesn't like empty source files */
-  typedef int  _ft_mac_dummy;
+  typedef int  ft_mac_dummy_;
 
 #endif /* !FT_MACINTOSH */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftmm.c b/src/java.desktop/share/native/libfreetype/src/base/ftmm.c
index a2b4bd03d78cf..9e2dd7ee79ddc 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftmm.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftmm.c
@@ -185,6 +185,14 @@
       error = FT_ERR( Invalid_Argument );
       if ( service->set_mm_design )
         error = service->set_mm_design( face, num_coords, coords );
+
+      if ( !error )
+      {
+        if ( num_coords )
+          face->face_flags |= FT_FACE_FLAG_VARIATION;
+        else
+          face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+      }
     }
 
     /* enforce recomputation of auto-hinting data */
@@ -220,6 +228,14 @@
       error = FT_ERR( Invalid_Argument );
       if ( service->set_mm_weightvector )
         error = service->set_mm_weightvector( face, len, weightvector );
+
+      if ( !error )
+      {
+        if ( len )
+          face->face_flags |= FT_FACE_FLAG_VARIATION;
+        else
+          face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+      }
     }
 
     /* enforce recomputation of auto-hinting data */
@@ -283,6 +299,30 @@
       if ( service_mm->set_var_design )
         error = service_mm->set_var_design( face, num_coords, coords );
 
+      if ( !error || error == -1 )
+      {
+        FT_Bool  is_variation_old = FT_IS_VARIATION( face );
+
+
+        if ( num_coords )
+          face->face_flags |= FT_FACE_FLAG_VARIATION;
+        else
+          face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+
+        if ( service_mm->construct_ps_name )
+        {
+          if ( error == -1 )
+          {
+            /* The PS name of a named instance and a non-named instance */
+            /* usually differs, even if the axis values are identical.  */
+            if ( is_variation_old != FT_IS_VARIATION( face ) )
+              service_mm->construct_ps_name( face );
+          }
+          else
+            service_mm->construct_ps_name( face );
+        }
+      }
+
       /* internal error code -1 means `no change'; we can exit immediately */
       if ( error == -1 )
         return FT_Err_Ok;
@@ -359,6 +399,30 @@
       if ( service_mm->set_mm_blend )
         error = service_mm->set_mm_blend( face, num_coords, coords );
 
+      if ( !error || error == -1 )
+      {
+        FT_Bool  is_variation_old = FT_IS_VARIATION( face );
+
+
+        if ( num_coords )
+          face->face_flags |= FT_FACE_FLAG_VARIATION;
+        else
+          face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+
+        if ( service_mm->construct_ps_name )
+        {
+          if ( error == -1 )
+          {
+            /* The PS name of a named instance and a non-named instance */
+            /* usually differs, even if the axis values are identical.  */
+            if ( is_variation_old != FT_IS_VARIATION( face ) )
+              service_mm->construct_ps_name( face );
+          }
+          else
+            service_mm->construct_ps_name( face );
+        }
+      }
+
       /* internal error code -1 means `no change'; we can exit immediately */
       if ( error == -1 )
         return FT_Err_Ok;
@@ -410,6 +474,30 @@
       if ( service_mm->set_mm_blend )
         error = service_mm->set_mm_blend( face, num_coords, coords );
 
+      if ( !error || error == -1 )
+      {
+        FT_Bool  is_variation_old = FT_IS_VARIATION( face );
+
+
+        if ( num_coords )
+          face->face_flags |= FT_FACE_FLAG_VARIATION;
+        else
+          face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+
+        if ( service_mm->construct_ps_name )
+        {
+          if ( error == -1 )
+          {
+            /* The PS name of a named instance and a non-named instance */
+            /* usually differs, even if the axis values are identical.  */
+            if ( is_variation_old != FT_IS_VARIATION( face ) )
+              service_mm->construct_ps_name( face );
+          }
+          else
+            service_mm->construct_ps_name( face );
+        }
+      }
+
       /* internal error code -1 means `no change'; we can exit immediately */
       if ( error == -1 )
         return FT_Err_Ok;
@@ -535,8 +623,35 @@
     if ( !error )
     {
       error = FT_ERR( Invalid_Argument );
-      if ( service_mm->set_instance )
-        error = service_mm->set_instance( face, instance_index );
+      if ( service_mm->set_named_instance )
+        error = service_mm->set_named_instance( face, instance_index );
+
+      if ( !error || error == -1 )
+      {
+        FT_Bool  is_variation_old = FT_IS_VARIATION( face );
+
+
+        face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+        face->face_index  = ( instance_index << 16 )        |
+                            ( face->face_index & 0xFFFFL );
+
+        if ( service_mm->construct_ps_name )
+        {
+          if ( error == -1 )
+          {
+            /* The PS name of a named instance and a non-named instance */
+            /* usually differs, even if the axis values are identical.  */
+            if ( is_variation_old != FT_IS_VARIATION( face ) )
+              service_mm->construct_ps_name( face );
+          }
+          else
+            service_mm->construct_ps_name( face );
+        }
+      }
+
+      /* internal error code -1 means `no change'; we can exit immediately */
+      if ( error == -1 )
+        return FT_Err_Ok;
     }
 
     if ( !error )
@@ -554,11 +669,32 @@
       face->autohint.data = NULL;
     }
 
+    return error;
+  }
+
+
+  /* documentation is in ftmm.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_Default_Named_Instance( FT_Face   face,
+                                 FT_UInt  *instance_index )
+  {
+    FT_Error  error;
+
+    FT_Service_MultiMasters  service_mm = NULL;
+
+
+    /* check of `face' delayed to `ft_face_get_mm_service' */
+
+    error = ft_face_get_mm_service( face, &service_mm );
     if ( !error )
     {
-      face->face_index  = ( instance_index << 16 )        |
-                          ( face->face_index & 0xFFFFL );
-      face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+      /* no error if `get_default_named_instance` is not available */
+      if ( service_mm->get_default_named_instance )
+        error = service_mm->get_default_named_instance( face,
+                                                        instance_index );
+      else
+        error = FT_Err_Ok;
     }
 
     return error;
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c b/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c
index ad6ef0ae168e6..89a25bc732d6f 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c
@@ -1019,7 +1019,8 @@
       /*      elegant.                                            */
 
       /* try to load SVG documents if available */
-      if ( FT_HAS_SVG( face ) )
+      if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 &&
+           FT_HAS_SVG( face )                   )
       {
         error = driver->clazz->load_glyph( slot, face->size,
                                            glyph_index,
@@ -1245,9 +1246,13 @@
   /* destructor for sizes list */
   static void
   destroy_size( FT_Memory  memory,
-                FT_Size    size,
-                FT_Driver  driver )
+                void*      size_,
+                void*      driver_ )
   {
+    FT_Size    size   = (FT_Size)size_;
+    FT_Driver  driver = (FT_Driver)driver_;
+
+
     /* finalize client-specific data */
     if ( size->generic.finalizer )
       size->generic.finalizer( size );
@@ -1293,10 +1298,12 @@
   /* destructor for faces list */
   static void
   destroy_face( FT_Memory  memory,
-                FT_Face    face,
-                FT_Driver  driver )
+                void*      face_,
+                void*      driver_ )
   {
-    FT_Driver_Class  clazz = driver->clazz;
+    FT_Face          face   = (FT_Face)face_;
+    FT_Driver        driver = (FT_Driver)driver_;
+    FT_Driver_Class  clazz  = driver->clazz;
 
 
     /* discard auto-hinting data */
@@ -1310,7 +1317,7 @@
 
     /* discard all sizes for this face */
     FT_List_Finalize( &face->sizes_list,
-                      (FT_List_Destructor)destroy_size,
+                      destroy_size,
                       memory,
                       driver );
     face->size = NULL;
@@ -1346,7 +1353,7 @@
   Destroy_Driver( FT_Driver  driver )
   {
     FT_List_Finalize( &driver->faces_list,
-                      (FT_List_Destructor)destroy_face,
+                      destroy_face,
                       driver->root.memory,
                       driver );
   }
@@ -1740,7 +1747,8 @@
     FT_Memory     memory = library->memory;
 
 
-    args.flags = 0;
+    args.driver = NULL;
+    args.flags  = 0;
 
     if ( driver_name )
     {
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c b/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c
index 30ff21ff39e6f..134f39d2b1fa0 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c
@@ -58,7 +58,9 @@
     FT_Error    error;
 
     FT_Int   n;         /* index of contour in outline     */
-    FT_UInt  first;     /* index of first point in contour */
+    FT_Int   first;     /* index of first point in contour */
+    FT_Int   last;      /* index of last point in contour  */
+
     FT_Int   tag;       /* current point's state           */
 
     FT_Int   shift;
@@ -73,18 +75,17 @@
 
     shift = func_interface->shift;
     delta = func_interface->delta;
-    first = 0;
 
+    last = -1;
     for ( n = 0; n < outline->n_contours; n++ )
     {
-      FT_Int  last;  /* index of last point in contour */
-
-
-      FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
+      FT_TRACE5(( "FT_Outline_Decompose: Contour %d\n", n ));
 
-      last = outline->contours[n];
-      if ( last < 0 )
+      first = last + 1;
+      last  = outline->contours[n];
+      if ( last < first )
         goto Invalid_Outline;
+
       limit = outline->points + last;
 
       v_start   = outline->points[first];
@@ -282,8 +283,6 @@
     Close:
       if ( error )
         goto Exit;
-
-      first = (FT_UInt)last + 1;
     }
 
     FT_TRACE5(( "FT_Outline_Decompose: Done\n" ));
@@ -368,7 +367,7 @@
       if ( n_points <= 0 || n_contours <= 0 )
         goto Bad;
 
-      end0 = end = -1;
+      end0 = -1;
       for ( n = 0; n < n_contours; n++ )
       {
         end = outline->contours[n];
@@ -380,7 +379,7 @@
         end0 = end;
       }
 
-      if ( end != n_points - 1 )
+      if ( end0 != n_points - 1 )
         goto Bad;
 
       /* XXX: check the tags array */
@@ -388,7 +387,7 @@
     }
 
   Bad:
-    return FT_THROW( Invalid_Argument );
+    return FT_THROW( Invalid_Outline );
   }
 
 
@@ -550,10 +549,12 @@
     if ( !outline )
       return;
 
-    first = 0;
-
+    last = -1;
     for ( n = 0; n < outline->n_contours; n++ )
     {
+      /* keep the first contour point as is and swap points around it */
+      /* to guarantee that the cubic arches stay valid after reverse  */
+      first = last + 2;
       last  = outline->contours[n];
 
       /* reverse point table */
@@ -591,8 +592,6 @@
           q--;
         }
       }
-
-      first = last + 1;
     }
 
     outline->flags ^= FT_OUTLINE_REVERSE_FILL;
@@ -941,7 +940,7 @@
 
     points = outline->points;
 
-    first = 0;
+    last = -1;
     for ( c = 0; c < outline->n_contours; c++ )
     {
       FT_Vector  in, out, anchor, shift;
@@ -949,8 +948,9 @@
       FT_Int     i, j, k;
 
 
-      l_in = 0;
-      last = outline->contours[c];
+      first = last + 1;
+      last  = outline->contours[c];
+      l_in  = 0;
 
       /* pacify compiler */
       in.x = in.y = anchor.x = anchor.y = 0;
@@ -1037,8 +1037,6 @@
         in   = out;
         l_in = l_out;
       }
-
-      first = last + 1;
     }
 
     return FT_Err_Ok;
@@ -1054,7 +1052,7 @@
     FT_Int      xshift, yshift;
     FT_Vector*  points;
     FT_Vector   v_prev, v_cur;
-    FT_Int      c, n, first;
+    FT_Int      c, n, first, last;
     FT_Pos      area = 0;
 
 
@@ -1086,11 +1084,11 @@
 
     points = outline->points;
 
-    first = 0;
+    last = -1;
     for ( c = 0; c < outline->n_contours; c++ )
     {
-      FT_Int  last = outline->contours[c];
-
+      first = last + 1;
+      last  = outline->contours[c];
 
       v_prev.x = points[last].x >> xshift;
       v_prev.y = points[last].y >> yshift;
@@ -1106,8 +1104,6 @@
 
         v_prev = v_cur;
       }
-
-      first = last + 1;
     }
 
     if ( area > 0 )
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftstream.c b/src/java.desktop/share/native/libfreetype/src/base/ftstream.c
index 05c5637578be1..64826acebe52a 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftstream.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftstream.c
@@ -141,7 +141,9 @@
       if ( read_bytes > count )
         read_bytes = count;
 
-      FT_MEM_COPY( buffer, stream->base + pos, read_bytes );
+      /* Allow "reading" zero bytes without UB even if buffer is NULL */
+      if ( count )
+        FT_MEM_COPY( buffer, stream->base + pos, read_bytes );
     }
 
     stream->pos = pos + read_bytes;
@@ -178,7 +180,9 @@
       if ( read_bytes > count )
         read_bytes = count;
 
-      FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes );
+      /* Allow "reading" zero bytes without UB even if buffer is NULL */
+      if ( count )
+        FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes );
     }
 
     stream->pos += read_bytes;
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c b/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c
index db358e772ed1a..92f1e43080fdc 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c
@@ -2055,7 +2055,9 @@
     FT_Error    error;
 
     FT_Int      n;         /* index of contour in outline     */
-    FT_UInt     first;     /* index of first point in contour */
+    FT_Int      first;     /* index of first point in contour */
+    FT_Int      last;      /* index of last point in contour  */
+
     FT_Int      tag;       /* current point's state           */
 
 
@@ -2067,22 +2069,17 @@
 
     FT_Stroker_Rewind( stroker );
 
-    first = 0;
-
+    last = -1;
     for ( n = 0; n < outline->n_contours; n++ )
     {
-      FT_UInt  last;  /* index of last point in contour */
-
-
-      last  = (FT_UInt)outline->contours[n];
-      limit = outline->points + last;
+      first = last + 1;
+      last  = outline->contours[n];
 
       /* skip empty points; we don't stroke these */
       if ( last <= first )
-      {
-        first = last + 1;
         continue;
-      }
+
+      limit = outline->points + last;
 
       v_start = outline->points[first];
       v_last  = outline->points[last];
@@ -2231,8 +2228,6 @@
         if ( error )
           goto Exit;
       }
-
-      first = last + 1;
     }
 
     return FT_Err_Ok;
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c b/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c
index 6ec25e13e47f2..f32edd3388b0b 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c
@@ -97,9 +97,18 @@
 
   FT_EXPORT_DEF( void )
   FT_GlyphSlot_Embolden( FT_GlyphSlot  slot )
+  {
+    FT_GlyphSlot_AdjustWeight( slot, 0x0AAA, 0x0AAA );
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FT_GlyphSlot_AdjustWeight( FT_GlyphSlot  slot,
+                             FT_Fixed      xdelta,
+                             FT_Fixed      ydelta )
   {
     FT_Library  library;
-    FT_Face     face;
+    FT_Size     size;
     FT_Error    error;
     FT_Pos      xstr, ystr;
 
@@ -108,16 +117,15 @@
       return;
 
     library = slot->library;
-    face    = slot->face;
+    size    = slot->face->size;
 
     if ( slot->format != FT_GLYPH_FORMAT_OUTLINE &&
          slot->format != FT_GLYPH_FORMAT_BITMAP  )
       return;
 
-    /* some reasonable strength */
-    xstr = FT_MulFix( face->units_per_EM,
-                      face->size->metrics.y_scale ) / 24;
-    ystr = xstr;
+    /* express deltas in pixels in 26.6 format */
+    xstr = (FT_Pos)size->metrics.x_ppem * xdelta / 1024;
+    ystr = (FT_Pos)size->metrics.y_ppem * ydelta / 1024;
 
     if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
       FT_Outline_EmboldenXY( &slot->outline, xstr, ystr );
diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c b/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c
index fcd289d19f4bb..61c99e3635714 100644
--- a/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c
+++ b/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c
@@ -206,7 +206,7 @@
    *     The number of bytes to read from the stream.
    *
    * @Return:
-   *   The number of bytes actually read.  If `count' is zero (this is,
+   *   The number of bytes actually read.  If `count' is zero (that is,
    *   the function is used for seeking), a non-zero return value
    *   indicates an error.
    */
@@ -219,7 +219,7 @@
     FT_FILE*  file;
 
 
-    if ( !count && offset > stream->size )
+    if ( offset > stream->size && !count )
       return 1;
 
     file = STREAM_FILE( stream );
@@ -227,6 +227,11 @@
     if ( stream->pos != offset )
       ft_fseek( file, (long)offset, SEEK_SET );
 
+    /* Avoid calling `fread` with `buffer=NULL` and `count=0`, */
+    /* which is undefined behaviour.                           */
+    if ( !count )
+      return 0;
+
     return (unsigned long)ft_fread( buffer, 1, count, file );
   }
 
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c b/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c
index 6ed3143222766..10d287bc81fbb 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c
@@ -32,9 +32,10 @@
   /*************************************************************************/
 
   FT_CALLBACK_DEF( FT_Error )
-  cff_cmap_encoding_init( CFF_CMapStd  cmap,
-                          FT_Pointer   pointer )
+  cff_cmap_encoding_init( FT_CMap     cmap,
+                          FT_Pointer  pointer )
   {
+    CFF_CMapStd   cffcmap  = (CFF_CMapStd)cmap;
     TT_Face       face     = (TT_Face)FT_CMAP_FACE( cmap );
     CFF_Font      cff      = (CFF_Font)face->extra.data;
     CFF_Encoding  encoding = &cff->encoding;
@@ -42,63 +43,56 @@
     FT_UNUSED( pointer );
 
 
-    cmap->gids  = encoding->codes;
+    cffcmap->gids = encoding->codes;
 
     return 0;
   }
 
 
   FT_CALLBACK_DEF( void )
-  cff_cmap_encoding_done( CFF_CMapStd  cmap )
+  cff_cmap_encoding_done( FT_CMap  cmap )
   {
-    cmap->gids  = NULL;
+    CFF_CMapStd  cffcmap = (CFF_CMapStd)cmap;
+
+
+    cffcmap->gids = NULL;
   }
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  cff_cmap_encoding_char_index( CFF_CMapStd  cmap,
-                                FT_UInt32    char_code )
+  cff_cmap_encoding_char_index( FT_CMap    cmap,
+                                FT_UInt32  char_code )
   {
-    FT_UInt  result = 0;
+    CFF_CMapStd  cffcmap = (CFF_CMapStd)cmap;
+    FT_UInt      result  = 0;
 
 
     if ( char_code < 256 )
-      result = cmap->gids[char_code];
+      result = cffcmap->gids[char_code];
 
     return result;
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  cff_cmap_encoding_char_next( CFF_CMapStd   cmap,
-                               FT_UInt32    *pchar_code )
+  FT_CALLBACK_DEF( FT_UInt )
+  cff_cmap_encoding_char_next( FT_CMap     cmap,
+                               FT_UInt32  *pchar_code )
   {
-    FT_UInt    result    = 0;
-    FT_UInt32  char_code = *pchar_code;
+    CFF_CMapStd  cffcmap   = (CFF_CMapStd)cmap;
+    FT_UInt      result    = 0;
+    FT_UInt32    char_code = *pchar_code;
 
 
-    *pchar_code = 0;
-
-    if ( char_code < 255 )
+    while ( char_code < 255 )
     {
-      FT_UInt  code = (FT_UInt)( char_code + 1 );
-
-
-      for (;;)
+      result = cffcmap->gids[++char_code];
+      if ( result )
       {
-        if ( code >= 256 )
-          break;
-
-        result = cmap->gids[code];
-        if ( result != 0 )
-        {
-          *pchar_code = code;
-          break;
-        }
-
-        code++;
+        *pchar_code = char_code;
+        break;
       }
     }
+
     return result;
   }
 
@@ -130,9 +124,10 @@
   /*************************************************************************/
 
   FT_CALLBACK_DEF( const char* )
-  cff_sid_to_glyph_name( TT_Face  face,
+  cff_sid_to_glyph_name( void*    face_,  /* TT_Face */
                          FT_UInt  idx )
   {
+    TT_Face      face    = (TT_Face)face_;
     CFF_Font     cff     = (CFF_Font)face->extra.data;
     CFF_Charset  charset = &cff->charset;
     FT_UInt      sid     = charset->sids[idx];
@@ -143,14 +138,15 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  cff_cmap_unicode_init( PS_Unicodes  unicodes,
+  cff_cmap_unicode_init( FT_CMap      cmap,     /* PS_Unicodes */
                          FT_Pointer   pointer )
   {
-    TT_Face             face    = (TT_Face)FT_CMAP_FACE( unicodes );
-    FT_Memory           memory  = FT_FACE_MEMORY( face );
-    CFF_Font            cff     = (CFF_Font)face->extra.data;
-    CFF_Charset         charset = &cff->charset;
-    FT_Service_PsCMaps  psnames = (FT_Service_PsCMaps)cff->psnames;
+    PS_Unicodes         unicodes = (PS_Unicodes)cmap;
+    TT_Face             face     = (TT_Face)FT_CMAP_FACE( cmap );
+    FT_Memory           memory   = FT_FACE_MEMORY( face );
+    CFF_Font            cff      = (CFF_Font)face->extra.data;
+    CFF_Charset         charset  = &cff->charset;
+    FT_Service_PsCMaps  psnames  = (FT_Service_PsCMaps)cff->psnames;
 
     FT_UNUSED( pointer );
 
@@ -166,17 +162,18 @@
     return psnames->unicodes_init( memory,
                                    unicodes,
                                    cff->num_glyphs,
-                                   (PS_GetGlyphNameFunc)&cff_sid_to_glyph_name,
+                                   &cff_sid_to_glyph_name,
                                    (PS_FreeGlyphNameFunc)NULL,
                                    (FT_Pointer)face );
   }
 
 
   FT_CALLBACK_DEF( void )
-  cff_cmap_unicode_done( PS_Unicodes  unicodes )
+  cff_cmap_unicode_done( FT_CMap  cmap )    /* PS_Unicodes */
   {
-    FT_Face    face   = FT_CMAP_FACE( unicodes );
-    FT_Memory  memory = FT_FACE_MEMORY( face );
+    PS_Unicodes  unicodes = (PS_Unicodes)cmap;
+    FT_Face      face     = FT_CMAP_FACE( cmap );
+    FT_Memory    memory   = FT_FACE_MEMORY( face );
 
 
     FT_FREE( unicodes->maps );
@@ -185,25 +182,27 @@
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  cff_cmap_unicode_char_index( PS_Unicodes  unicodes,
-                               FT_UInt32    char_code )
+  cff_cmap_unicode_char_index( FT_CMap    cmap,       /* PS_Unicodes */
+                               FT_UInt32  char_code )
   {
-    TT_Face             face    = (TT_Face)FT_CMAP_FACE( unicodes );
-    CFF_Font            cff     = (CFF_Font)face->extra.data;
-    FT_Service_PsCMaps  psnames = (FT_Service_PsCMaps)cff->psnames;
+    PS_Unicodes         unicodes = (PS_Unicodes)cmap;
+    TT_Face             face     = (TT_Face)FT_CMAP_FACE( cmap );
+    CFF_Font            cff      = (CFF_Font)face->extra.data;
+    FT_Service_PsCMaps  psnames  = (FT_Service_PsCMaps)cff->psnames;
 
 
     return psnames->unicodes_char_index( unicodes, char_code );
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  cff_cmap_unicode_char_next( PS_Unicodes  unicodes,
-                              FT_UInt32   *pchar_code )
+  FT_CALLBACK_DEF( FT_UInt )
+  cff_cmap_unicode_char_next( FT_CMap     cmap,        /* PS_Unicodes */
+                              FT_UInt32  *pchar_code )
   {
-    TT_Face             face    = (TT_Face)FT_CMAP_FACE( unicodes );
-    CFF_Font            cff     = (CFF_Font)face->extra.data;
-    FT_Service_PsCMaps  psnames = (FT_Service_PsCMaps)cff->psnames;
+    PS_Unicodes         unicodes = (PS_Unicodes)cmap;
+    TT_Face             face     = (TT_Face)FT_CMAP_FACE( cmap );
+    CFF_Font            cff      = (CFF_Font)face->extra.data;
+    FT_Service_PsCMaps  psnames  = (FT_Service_PsCMaps)cff->psnames;
 
 
     return psnames->unicodes_char_next( unicodes, pchar_code );
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c
index 4e2e0e00deba8..9898d625ca4ed 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c
@@ -108,20 +108,20 @@
    *   They can be implemented by format-specific interfaces.
    */
   FT_CALLBACK_DEF( FT_Error )
-  cff_get_kerning( FT_Face     ttface,          /* TT_Face */
+  cff_get_kerning( FT_Face     face,          /* CFF_Face */
                    FT_UInt     left_glyph,
                    FT_UInt     right_glyph,
                    FT_Vector*  kerning )
   {
-    TT_Face       face = (TT_Face)ttface;
-    SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
+    CFF_Face      cffface = (CFF_Face)face;
+    SFNT_Service  sfnt    = (SFNT_Service)cffface->sfnt;
 
 
     kerning->x = 0;
     kerning->y = 0;
 
     if ( sfnt )
-      kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph );
+      kerning->x = sfnt->get_kerning( cffface, left_glyph, right_glyph );
 
     return FT_Err_Ok;
   }
@@ -158,23 +158,23 @@
    *   FreeType error code.  0 means success.
    */
   FT_CALLBACK_DEF( FT_Error )
-  cff_glyph_load( FT_GlyphSlot  cffslot,      /* CFF_GlyphSlot */
-                  FT_Size       cffsize,      /* CFF_Size      */
+  cff_glyph_load( FT_GlyphSlot  slot,        /* CFF_GlyphSlot */
+                  FT_Size       size,        /* CFF_Size      */
                   FT_UInt       glyph_index,
                   FT_Int32      load_flags )
   {
     FT_Error       error;
-    CFF_GlyphSlot  slot = (CFF_GlyphSlot)cffslot;
-    CFF_Size       size = (CFF_Size)cffsize;
+    CFF_GlyphSlot  cffslot = (CFF_GlyphSlot)slot;
+    CFF_Size       cffsize = (CFF_Size)size;
 
 
-    if ( !slot )
+    if ( !cffslot )
       return FT_THROW( Invalid_Slot_Handle );
 
     FT_TRACE1(( "cff_glyph_load: glyph index %d\n", glyph_index ));
 
     /* check whether we want a scaled outline or bitmap */
-    if ( !size )
+    if ( !cffsize )
       load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
 
     /* reset the size object if necessary */
@@ -184,12 +184,12 @@
     if ( size )
     {
       /* these two objects must have the same parent */
-      if ( cffsize->face != cffslot->face )
+      if ( size->face != slot->face )
         return FT_THROW( Invalid_Face_Handle );
     }
 
     /* now load the glyph outline if necessary */
-    error = cff_slot_load( slot, size, glyph_index, load_flags );
+    error = cff_slot_load( cffslot, cffsize, glyph_index, load_flags );
 
     /* force drop-out mode to 2 - irrelevant now */
     /* slot->outline.dropout_mode = 2; */
@@ -216,7 +216,7 @@
       /* it is no longer necessary that those values are identical to   */
       /* the values in the `CFF' table                                  */
 
-      TT_Face   ttface = (TT_Face)face;
+      CFF_Face  cffface = (CFF_Face)face;
       FT_Short  dummy;
 
 
@@ -225,7 +225,7 @@
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
         /* no fast retrieval for blended MM fonts without VVAR table */
         if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
-             !( ttface->variation_support & TT_FACE_FLAG_VAR_VADVANCE )  )
+             !( cffface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
           return FT_THROW( Unimplemented_Feature );
 #endif
 
@@ -233,7 +233,7 @@
         /* otherwise we extract the info from the CFF glyphstrings  */
         /* (instead of synthesizing a global value using the `OS/2' */
         /* table)                                                   */
-        if ( !ttface->vertical_info )
+        if ( !cffface->vertical_info )
           goto Missing_Table;
 
         for ( nn = 0; nn < count; nn++ )
@@ -241,11 +241,11 @@
           FT_UShort  ah;
 
 
-          ( (SFNT_Service)ttface->sfnt )->get_metrics( ttface,
-                                                       1,
-                                                       start + nn,
-                                                       &dummy,
-                                                       &ah );
+          ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface,
+                                                        1,
+                                                        start + nn,
+                                                        &dummy,
+                                                        &ah );
 
           FT_TRACE5(( "  idx %d: advance height %d font unit%s\n",
                       start + nn,
@@ -259,12 +259,12 @@
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
         /* no fast retrieval for blended MM fonts without HVAR table */
         if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
-             !( ttface->variation_support & TT_FACE_FLAG_VAR_HADVANCE )  )
+             !( cffface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
           return FT_THROW( Unimplemented_Feature );
 #endif
 
         /* check whether we have data from the `hmtx' table at all */
-        if ( !ttface->horizontal.number_Of_HMetrics )
+        if ( !cffface->horizontal.number_Of_HMetrics )
           goto Missing_Table;
 
         for ( nn = 0; nn < count; nn++ )
@@ -272,11 +272,11 @@
           FT_UShort  aw;
 
 
-          ( (SFNT_Service)ttface->sfnt )->get_metrics( ttface,
-                                                       0,
-                                                       start + nn,
-                                                       &dummy,
-                                                       &aw );
+          ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface,
+                                                        0,
+                                                        start + nn,
+                                                        &dummy,
+                                                        &aw );
 
           FT_TRACE5(( "  idx %d: advance width %d font unit%s\n",
                       start + nn,
@@ -312,13 +312,14 @@
    *
    */
 
-  static FT_Error
-  cff_get_glyph_name( CFF_Face    face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_get_glyph_name( FT_Face     face,        /* CFF_Face */
                       FT_UInt     glyph_index,
                       FT_Pointer  buffer,
                       FT_UInt     buffer_max )
   {
-    CFF_Font    font   = (CFF_Font)face->extra.data;
+    CFF_Face    cffface = (CFF_Face)face;
+    CFF_Font    font    = (CFF_Font)cffface->extra.data;
     FT_String*  gname;
     FT_UShort   sid;
     FT_Error    error;
@@ -338,10 +339,7 @@
 
 
       if ( service && service->get_name )
-        return service->get_name( FT_FACE( face ),
-                                  glyph_index,
-                                  buffer,
-                                  buffer_max );
+        return service->get_name( face, glyph_index, buffer, buffer_max );
       else
       {
         FT_ERROR(( "cff_get_glyph_name:"
@@ -366,7 +364,7 @@
     /* first, locate the sid in the charset table */
     sid = font->charset.sids[glyph_index];
 
-    /* now, lookup the name itself */
+    /* now, look up the name itself */
     gname = cff_index_get_sid_string( font, sid );
 
     if ( gname )
@@ -379,21 +377,19 @@
   }
 
 
-  static FT_UInt
-  cff_get_name_index( CFF_Face          face,
+  FT_CALLBACK_DEF( FT_UInt )
+  cff_get_name_index( FT_Face           face,        /* CFF_Face */
                       const FT_String*  glyph_name )
   {
-    CFF_Font            cff;
-    CFF_Charset         charset;
+    CFF_Face            cffface = (CFF_Face)face;
+    CFF_Font            cff     = (CFF_Font)cffface->extra.data;
+    CFF_Charset         charset = &cff->charset;
     FT_Service_PsCMaps  psnames;
     FT_String*          name;
     FT_UShort           sid;
     FT_UInt             i;
 
 
-    cff     = (CFF_FontRec *)face->extra.data;
-    charset = &cff->charset;
-
     /* CFF2 table does not have glyph names; */
     /* we need to use `post' table method    */
     if ( cff->version_major == 2 )
@@ -408,7 +404,7 @@
 
 
       if ( service && service->name_index )
-        return service->name_index( FT_FACE( face ), glyph_name );
+        return service->name_index( face, glyph_name );
       else
       {
         FT_ERROR(( "cff_get_name_index:"
@@ -446,8 +442,8 @@
   FT_DEFINE_SERVICE_GLYPHDICTREC(
     cff_service_glyph_dict,
 
-    (FT_GlyphDict_GetNameFunc)  cff_get_glyph_name,      /* get_name   */
-    (FT_GlyphDict_NameIndexFunc)cff_get_name_index       /* name_index */
+    cff_get_glyph_name,  /* FT_GlyphDict_GetNameFunc   get_name   */
+    cff_get_name_index   /* FT_GlyphDict_NameIndexFunc name_index */
   )
 
 
@@ -456,25 +452,32 @@
    *
    */
 
-  static FT_Int
+  FT_CALLBACK_DEF( FT_Int )
   cff_ps_has_glyph_names( FT_Face  face )
   {
     return ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) > 0;
   }
 
 
-  static FT_Error
-  cff_ps_get_font_info( CFF_Face         face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_ps_get_font_info( FT_Face          face,        /* CFF_Face */
                         PS_FontInfoRec*  afont_info )
   {
-    CFF_Font  cff   = (CFF_Font)face->extra.data;
-    FT_Error  error = FT_Err_Ok;
+    CFF_Face  cffface = (CFF_Face)face;
+    CFF_Font  cff     = (CFF_Font)cffface->extra.data;
+    FT_Error  error   = FT_Err_Ok;
 
 
+    if ( cffface->is_cff2 )
+    {
+      error = FT_THROW( Invalid_Argument );
+      goto Fail;
+    }
+
     if ( cff && !cff->font_info )
     {
       CFF_FontRecDict  dict      = &cff->top_font.font_dict;
-      FT_Memory        memory    = face->root.memory;
+      FT_Memory        memory    = FT_FACE_MEMORY( face );
       PS_FontInfoRec*  font_info = NULL;
 
 
@@ -507,18 +510,19 @@
   }
 
 
-  static FT_Error
-  cff_ps_get_font_extra( CFF_Face          face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_ps_get_font_extra( FT_Face           face,         /* CFF_Face */
                          PS_FontExtraRec*  afont_extra )
   {
-    CFF_Font  cff   = (CFF_Font)face->extra.data;
-    FT_Error  error = FT_Err_Ok;
+    CFF_Face  cffface = (CFF_Face)face;
+    CFF_Font  cff     = (CFF_Font)cffface->extra.data;
+    FT_Error  error   = FT_Err_Ok;
 
 
     if ( cff && !cff->font_extra )
     {
       CFF_FontRecDict   dict       = &cff->top_font.font_dict;
-      FT_Memory         memory     = face->root.memory;
+      FT_Memory         memory     = FT_FACE_MEMORY( face );
       PS_FontExtraRec*  font_extra = NULL;
       FT_String*        embedded_postscript;
 
@@ -588,13 +592,13 @@
   FT_DEFINE_SERVICE_PSINFOREC(
     cff_service_ps_info,
 
-    (PS_GetFontInfoFunc)   cff_ps_get_font_info,    /* ps_get_font_info    */
-    (PS_GetFontExtraFunc)  cff_ps_get_font_extra,   /* ps_get_font_extra   */
-    (PS_HasGlyphNamesFunc) cff_ps_has_glyph_names,  /* ps_has_glyph_names  */
+    cff_ps_get_font_info,    /* PS_GetFontInfoFunc    ps_get_font_info    */
+    cff_ps_get_font_extra,   /* PS_GetFontExtraFunc   ps_get_font_extra   */
+    cff_ps_has_glyph_names,  /* PS_HasGlyphNamesFunc  ps_has_glyph_names  */
     /* unsupported with CFF fonts */
-    (PS_GetFontPrivateFunc)NULL,                    /* ps_get_font_private */
+    NULL,                    /* PS_GetFontPrivateFunc ps_get_font_private */
     /* not implemented            */
-    (PS_GetFontValueFunc)  NULL                     /* ps_get_font_value   */
+    NULL                     /* PS_GetFontValueFunc   ps_get_font_value   */
   )
 
 
@@ -603,17 +607,18 @@
    *
    */
 
-  static const char*
-  cff_get_ps_name( CFF_Face  face )
+  FT_CALLBACK_DEF( const char* )
+  cff_get_ps_name( FT_Face  face )    /* CFF_Face */
   {
-    CFF_Font      cff  = (CFF_Font)face->extra.data;
-    SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
+    CFF_Face      cffface = (CFF_Face)face;
+    CFF_Font      cff     = (CFF_Font)cffface->extra.data;
+    SFNT_Service  sfnt    = (SFNT_Service)cffface->sfnt;
 
 
     /* following the OpenType specification 1.7, we return the name stored */
     /* in the `name' table for a CFF wrapped into an SFNT container        */
 
-    if ( FT_IS_SFNT( FT_FACE( face ) ) && sfnt )
+    if ( FT_IS_SFNT( face ) && sfnt )
     {
       FT_Library             library     = FT_FACE_LIBRARY( face );
       FT_Module              sfnt_module = FT_Get_Module( library, "sfnt" );
@@ -625,17 +630,17 @@
 
 
       if ( service && service->get_ps_font_name )
-        return service->get_ps_font_name( FT_FACE( face ) );
+        return service->get_ps_font_name( face );
     }
 
-    return (const char*)cff->font_name;
+    return cff ? (const char*)cff->font_name : NULL;
   }
 
 
   FT_DEFINE_SERVICE_PSFONTNAMEREC(
     cff_service_ps_name,
 
-    (FT_PsName_GetFunc)cff_get_ps_name      /* get_ps_font_name */
+    cff_get_ps_name  /* FT_PsName_GetFunc get_ps_font_name */
   )
 
 
@@ -649,7 +654,7 @@
    * Otherwise call the service function in the sfnt module.
    *
    */
-  static FT_Error
+  FT_CALLBACK_DEF( FT_Error )
   cff_get_cmap_info( FT_CharMap    charmap,
                      TT_CMapInfo  *cmap_info )
   {
@@ -683,7 +688,7 @@
   FT_DEFINE_SERVICE_TTCMAPSREC(
     cff_service_get_cmap_info,
 
-    (TT_CMap_Info_GetFunc)cff_get_cmap_info    /* get_cmap_info */
+    cff_get_cmap_info  /* TT_CMap_Info_GetFunc get_cmap_info */
   )
 
 
@@ -691,14 +696,15 @@
    * CID INFO SERVICE
    *
    */
-  static FT_Error
-  cff_get_ros( CFF_Face      face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_get_ros( FT_Face       face,        /* FT_Face */
                const char*  *registry,
                const char*  *ordering,
                FT_Int       *supplement )
   {
-    FT_Error  error = FT_Err_Ok;
-    CFF_Font  cff   = (CFF_Font)face->extra.data;
+    FT_Error  error   = FT_Err_Ok;
+    CFF_Face  cffface = (CFF_Face)face;
+    CFF_Font  cff     = (CFF_Font)cffface->extra.data;
 
 
     if ( cff )
@@ -748,12 +754,13 @@
   }
 
 
-  static FT_Error
-  cff_get_is_cid( CFF_Face  face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_get_is_cid( FT_Face   face,    /* CFF_Face */
                   FT_Bool  *is_cid )
   {
-    FT_Error  error = FT_Err_Ok;
-    CFF_Font  cff   = (CFF_Font)face->extra.data;
+    FT_Error  error   = FT_Err_Ok;
+    CFF_Face  cffface = (CFF_Face)face;
+    CFF_Font  cff     = (CFF_Font)cffface->extra.data;
 
 
     *is_cid = 0;
@@ -771,16 +778,15 @@
   }
 
 
-  static FT_Error
-  cff_get_cid_from_glyph_index( CFF_Face  face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_get_cid_from_glyph_index( FT_Face   face,        /* CFF_Face */
                                 FT_UInt   glyph_index,
                                 FT_UInt  *cid )
   {
-    FT_Error  error = FT_Err_Ok;
-    CFF_Font  cff;
-
+    FT_Error  error   = FT_Err_Ok;
+    CFF_Face  cffface = (CFF_Face)face;
+    CFF_Font  cff     = (CFF_Font)cffface->extra.data;
 
-    cff = (CFF_Font)face->extra.data;
 
     if ( cff )
     {
@@ -814,12 +820,12 @@
   FT_DEFINE_SERVICE_CIDREC(
     cff_service_cid_info,
 
-    (FT_CID_GetRegistryOrderingSupplementFunc)
-      cff_get_ros,                             /* get_ros                  */
-    (FT_CID_GetIsInternallyCIDKeyedFunc)
-      cff_get_is_cid,                          /* get_is_cid               */
-    (FT_CID_GetCIDFromGlyphIndexFunc)
-      cff_get_cid_from_glyph_index             /* get_cid_from_glyph_index */
+    cff_get_ros,
+      /* FT_CID_GetRegistryOrderingSupplementFunc get_ros                  */
+    cff_get_is_cid,
+      /* FT_CID_GetIsInternallyCIDKeyedFunc       get_is_cid               */
+    cff_get_cid_from_glyph_index
+      /* FT_CID_GetCIDFromGlyphIndexFunc          get_cid_from_glyph_index */
   )
 
 
@@ -831,9 +837,9 @@
   FT_DEFINE_SERVICE_PROPERTIESREC(
     cff_service_properties,
 
-    (FT_Properties_SetFunc)ps_property_set,      /* set_property */
-    (FT_Properties_GetFunc)ps_property_get )     /* get_property */
-
+    ps_property_set,  /* FT_Properties_SetFunc set_property */
+    ps_property_get   /* FT_Properties_GetFunc get_property */
+  )
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
 
@@ -842,160 +848,195 @@
    *
    */
 
-  static FT_Error
-  cff_set_mm_blend( CFF_Face   face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_set_mm_blend( FT_Face    face,        /* CFF_Face */
                     FT_UInt    num_coords,
                     FT_Fixed*  coords )
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    return mm->set_mm_blend( FT_FACE( face ), num_coords, coords );
+    return mm->set_mm_blend( face, num_coords, coords );
   }
 
 
-  static FT_Error
-  cff_get_mm_blend( CFF_Face   face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_get_mm_blend( FT_Face    face,       /* CFF_Face */
                     FT_UInt    num_coords,
                     FT_Fixed*  coords )
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    return mm->get_mm_blend( FT_FACE( face ), num_coords, coords );
+    return mm->get_mm_blend( face, num_coords, coords );
   }
 
 
-  static FT_Error
-  cff_set_mm_weightvector( CFF_Face   face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_set_mm_weightvector( FT_Face    face,          /* CFF_Face */
                            FT_UInt    len,
                            FT_Fixed*  weightvector )
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    return mm->set_mm_weightvector( FT_FACE( face ), len, weightvector );
+    return mm->set_mm_weightvector( face, len, weightvector );
   }
 
 
-  static FT_Error
-  cff_get_mm_weightvector( CFF_Face   face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_get_mm_weightvector( FT_Face    face,          /* CFF_Face */
                            FT_UInt*   len,
                            FT_Fixed*  weightvector )
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    return mm->get_mm_weightvector( FT_FACE( face ), len, weightvector );
+    return mm->get_mm_weightvector( face, len, weightvector );
   }
 
 
-  static FT_Error
-  cff_get_mm_var( CFF_Face     face,
+  FT_CALLBACK_DEF( void )
+  cff_construct_ps_name( FT_Face  face )  /* CFF_Face */
+  {
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
+
+
+    mm->construct_ps_name( face );
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  cff_get_mm_var( FT_Face      face,    /* CFF_Face */
                   FT_MM_Var*  *master )
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    return mm->get_mm_var( FT_FACE( face ), master );
+    return mm->get_mm_var( face, master );
   }
 
 
-  static FT_Error
-  cff_set_var_design( CFF_Face   face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_set_var_design( FT_Face    face,       /* CFF_Face */
                       FT_UInt    num_coords,
                       FT_Fixed*  coords )
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    return mm->set_var_design( FT_FACE( face ), num_coords, coords );
+    return mm->set_var_design( face, num_coords, coords );
   }
 
 
-  static FT_Error
-  cff_get_var_design( CFF_Face   face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_get_var_design( FT_Face    face,       /* CFF_Face */
                       FT_UInt    num_coords,
                       FT_Fixed*  coords )
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    return mm->get_var_design( FT_FACE( face ), num_coords, coords );
+    return mm->get_var_design( face, num_coords, coords );
   }
 
 
-  static FT_Error
-  cff_set_instance( CFF_Face  face,
-                    FT_UInt   instance_index )
+  FT_CALLBACK_DEF( FT_Error )
+  cff_set_named_instance( FT_Face   face,            /* CFF_Face */
+                          FT_UInt   instance_index )
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    return mm->set_instance( FT_FACE( face ), instance_index );
+    return mm->set_named_instance( face, instance_index );
   }
 
 
-  static FT_Error
-  cff_load_item_variation_store( CFF_Face         face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_get_default_named_instance( FT_Face   face,            /* CFF_Face */
+                                  FT_UInt  *instance_index )
+  {
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
+
+
+    return mm->get_default_named_instance( face, instance_index );
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  cff_load_item_variation_store( FT_Face          face,       /* CFF_Face */
                                  FT_ULong         offset,
                                  GX_ItemVarStore  itemStore )
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    return mm->load_item_var_store( FT_FACE(face), offset, itemStore );
+    return mm->load_item_var_store( face, offset, itemStore );
   }
 
 
-  static FT_Error
-  cff_load_delta_set_index_mapping( CFF_Face           face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_load_delta_set_index_mapping( FT_Face            face,   /* CFF_Face */
                                     FT_ULong           offset,
                                     GX_DeltaSetIdxMap  map,
                                     GX_ItemVarStore    itemStore,
                                     FT_ULong           table_len )
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    return mm->load_delta_set_idx_map( FT_FACE( face ), offset, map,
+    return mm->load_delta_set_idx_map( face, offset, map,
                                        itemStore, table_len );
   }
 
 
-  static FT_Int
-  cff_get_item_delta( CFF_Face         face,
+  FT_CALLBACK_DEF( FT_Int )
+  cff_get_item_delta( FT_Face          face,        /* CFF_Face */
                       GX_ItemVarStore  itemStore,
                       FT_UInt          outerIndex,
                       FT_UInt          innerIndex )
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    return mm->get_item_delta( FT_FACE( face ), itemStore,
-                               outerIndex, innerIndex );
+    return mm->get_item_delta( face, itemStore, outerIndex, innerIndex );
   }
 
 
-  static void
-  cff_done_item_variation_store( CFF_Face          face,
+  FT_CALLBACK_DEF( void )
+  cff_done_item_variation_store( FT_Face          face,       /* CFF_Face */
                                  GX_ItemVarStore  itemStore )
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    mm->done_item_var_store( FT_FACE( face ), itemStore );
+    mm->done_item_var_store( face, itemStore );
   }
 
 
-  static void
-  cff_done_delta_set_index_map( CFF_Face           face,
+  FT_CALLBACK_DEF( void )
+  cff_done_delta_set_index_map( FT_Face            face,       /* CFF_Face */
                                 GX_DeltaSetIdxMap  deltaSetIdxMap )
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    mm->done_delta_set_idx_map( FT_FACE ( face ), deltaSetIdxMap );
+    mm->done_delta_set_idx_map( face, deltaSetIdxMap );
   }
 
 
@@ -1003,36 +1044,35 @@
   FT_DEFINE_SERVICE_MULTIMASTERSREC(
     cff_service_multi_masters,
 
-    (FT_Get_MM_Func)        NULL,               /* get_mm                    */
-    (FT_Set_MM_Design_Func) NULL,               /* set_mm_design             */
-    (FT_Set_MM_Blend_Func)  cff_set_mm_blend,   /* set_mm_blend              */
-    (FT_Get_MM_Blend_Func)  cff_get_mm_blend,   /* get_mm_blend              */
-    (FT_Get_MM_Var_Func)    cff_get_mm_var,     /* get_mm_var                */
-    (FT_Set_Var_Design_Func)cff_set_var_design, /* set_var_design            */
-    (FT_Get_Var_Design_Func)cff_get_var_design, /* get_var_design            */
-    (FT_Set_Instance_Func)  cff_set_instance,   /* set_instance              */
-    (FT_Set_MM_WeightVector_Func)
-                            cff_set_mm_weightvector,
-                                                /* set_mm_weightvector       */
-    (FT_Get_MM_WeightVector_Func)
-                            cff_get_mm_weightvector,
-                                                /* get_mm_weightvector       */
-    (FT_Var_Load_Delta_Set_Idx_Map_Func)
-                            cff_load_delta_set_index_mapping,
-                                                /* load_delta_set_idx_map    */
-    (FT_Var_Load_Item_Var_Store_Func)
-                            cff_load_item_variation_store,
-                                                /* load_item_variation_store */
-    (FT_Var_Get_Item_Delta_Func)
-                            cff_get_item_delta, /* get_item_delta            */
-    (FT_Var_Done_Item_Var_Store_Func)
-                            cff_done_item_variation_store,
-                                                /* done_item_variation_store */
-    (FT_Var_Done_Delta_Set_Idx_Map_Func)
-                            cff_done_delta_set_index_map,
-                                                /* done_delta_set_index_map  */
-    (FT_Get_Var_Blend_Func) cff_get_var_blend,  /* get_var_blend             */
-    (FT_Done_Blend_Func)    cff_done_blend      /* done_blend                */
+    NULL,                /* FT_Get_MM_Func         get_mm                     */
+    NULL,                /* FT_Set_MM_Design_Func  set_mm_design              */
+    cff_set_mm_blend,    /* FT_Set_MM_Blend_Func   set_mm_blend               */
+    cff_get_mm_blend,    /* FT_Get_MM_Blend_Func   get_mm_blend               */
+    cff_get_mm_var,      /* FT_Get_MM_Var_Func     get_mm_var                 */
+    cff_set_var_design,  /* FT_Set_Var_Design_Func set_var_design             */
+    cff_get_var_design,  /* FT_Get_Var_Design_Func get_var_design             */
+    cff_set_named_instance,
+             /* FT_Set_Named_Instance_Func         set_named_instance         */
+    cff_get_default_named_instance,
+             /* FT_Get_Default_Named_Instance_Func get_default_named_instance */
+    cff_set_mm_weightvector,
+             /* FT_Set_MM_WeightVector_Func        set_mm_weightvector        */
+    cff_get_mm_weightvector,
+             /* FT_Get_MM_WeightVector_Func        get_mm_weightvector        */
+    cff_construct_ps_name,
+             /* FT_Construct_PS_Name_Func          construct_ps_name          */
+    cff_load_delta_set_index_mapping,
+             /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map     */
+    cff_load_item_variation_store,
+             /* FT_Var_Load_Item_Var_Store_Func    load_item_variation_store  */
+    cff_get_item_delta,
+             /* FT_Var_Get_Item_Delta_Func         get_item_delta             */
+    cff_done_item_variation_store,
+             /* FT_Var_Done_Item_Var_Store_Func    done_item_variation_store  */
+    cff_done_delta_set_index_map,
+             /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map   */
+    cff_get_var_blend,   /* FT_Get_Var_Blend_Func  get_var_blend              */
+    cff_done_blend       /* FT_Done_Blend_Func     done_blend                 */
   )
 
 
@@ -1041,41 +1081,46 @@
    *
    */
 
-  static FT_Error
-  cff_hadvance_adjust( CFF_Face  face,
+  FT_CALLBACK_DEF( FT_Error )
+  cff_hadvance_adjust( FT_Face   face,    /* CFF_Face */
                        FT_UInt   gindex,
                        FT_Int   *avalue )
   {
-    FT_Service_MetricsVariations  var = (FT_Service_MetricsVariations)face->var;
+    CFF_Face  cffface = (CFF_Face)face;
+    FT_Service_MetricsVariations
+              var     = (FT_Service_MetricsVariations)cffface->tt_var;
 
 
-    return var->hadvance_adjust( FT_FACE( face ), gindex, avalue );
+    return var->hadvance_adjust( face, gindex, avalue );
   }
 
 
-  static void
-  cff_metrics_adjust( CFF_Face  face )
+  FT_CALLBACK_DEF( void )
+  cff_metrics_adjust( FT_Face  face )    /* CFF_Face */
   {
-    FT_Service_MetricsVariations  var = (FT_Service_MetricsVariations)face->var;
+    CFF_Face  cffface = (CFF_Face)face;
+    FT_Service_MetricsVariations
+              var     = (FT_Service_MetricsVariations)cffface->tt_var;
 
 
-    var->metrics_adjust( FT_FACE( face ) );
+    var->metrics_adjust( face );
   }
 
 
   FT_DEFINE_SERVICE_METRICSVARIATIONSREC(
     cff_service_metrics_variations,
 
-    (FT_HAdvance_Adjust_Func)cff_hadvance_adjust,    /* hadvance_adjust */
-    (FT_LSB_Adjust_Func)     NULL,                   /* lsb_adjust      */
-    (FT_RSB_Adjust_Func)     NULL,                   /* rsb_adjust      */
+    cff_hadvance_adjust,  /* FT_HAdvance_Adjust_Func hadvance_adjust */
+    NULL,                 /* FT_LSB_Adjust_Func      lsb_adjust      */
+    NULL,                 /* FT_RSB_Adjust_Func      rsb_adjust      */
 
-    (FT_VAdvance_Adjust_Func)NULL,                   /* vadvance_adjust */
-    (FT_TSB_Adjust_Func)     NULL,                   /* tsb_adjust      */
-    (FT_BSB_Adjust_Func)     NULL,                   /* bsb_adjust      */
-    (FT_VOrg_Adjust_Func)    NULL,                   /* vorg_adjust     */
+    NULL,                 /* FT_VAdvance_Adjust_Func vadvance_adjust */
+    NULL,                 /* FT_TSB_Adjust_Func      tsb_adjust      */
+    NULL,                 /* FT_BSB_Adjust_Func      bsb_adjust      */
+    NULL,                 /* FT_VOrg_Adjust_Func     vorg_adjust     */
 
-    (FT_Metrics_Adjust_Func) cff_metrics_adjust      /* metrics_adjust  */
+    cff_metrics_adjust,   /* FT_Metrics_Adjust_Func  metrics_adjust  */
+    NULL                  /* FT_Size_Reset_Func      size_reset      */
   )
 #endif
 
@@ -1088,11 +1133,11 @@
   FT_DEFINE_SERVICE_CFFLOADREC(
     cff_service_cff_load,
 
-    (FT_Get_Standard_Encoding_Func)cff_get_standard_encoding,
-    (FT_Load_Private_Dict_Func)    cff_load_private_dict,
-    (FT_FD_Select_Get_Func)        cff_fd_select_get,
-    (FT_Blend_Check_Vector_Func)   cff_blend_check_vector,
-    (FT_Blend_Build_Vector_Func)   cff_blend_build_vector
+    cff_get_standard_encoding,  /* FT_Get_Standard_Encoding_Func get_standard_encoding */
+    cff_load_private_dict,      /* FT_Load_Private_Dict_Func     load_private_dict     */
+    cff_fd_select_get,          /* FT_FD_Select_Get_Func         fd_select_get         */
+    cff_blend_check_vector,     /* FT_Blend_Check_Vector_Func    blend_check_vector    */
+    cff_blend_build_vector      /* FT_Blend_Build_Vector_Func    blend_build_vector    */
   )
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c
index cfa0aaf2b696b..c483d1d1a5912 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c
@@ -356,14 +356,16 @@
 
 #ifdef FT_CONFIG_OPTION_SVG
     /* check for OT-SVG */
-    if ( ( load_flags & FT_LOAD_COLOR ) && face->svg )
+    if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 &&
+         ( load_flags & FT_LOAD_COLOR )       &&
+         face->svg                            )
     {
       /*
        * We load the SVG document and try to grab the advances from the
        * table.  For the bearings we rely on the presetting hook to do that.
        */
 
-      SFNT_Service  sfnt  = (SFNT_Service)face->sfnt;
+      SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
 
 
       if ( size && (size->root.metrics.x_ppem < 1 ||
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffload.c b/src/java.desktop/share/native/libfreetype/src/cff/cffload.c
index 4b8c6e16c58eb..af79082e98cb5 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffload.c
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffload.c
@@ -400,7 +400,7 @@
 
   /* Allocate a table containing pointers to an index's elements. */
   /* The `pool' argument makes this function convert the index    */
-  /* entries to C-style strings (this is, null-terminated).       */
+  /* entries to C-style strings (that is, null-terminated).       */
   static FT_Error
   cff_index_get_pointers( CFF_Index   idx,
                           FT_Byte***  table,
@@ -1361,14 +1361,15 @@
     for ( i = 0; i < numBlends; i++ )
     {
       const FT_Int32*  weight = &blend->BV[1];
-      FT_UInt32        sum;
+      FT_Fixed         sum;
 
 
-      /* convert inputs to 16.16 fixed-point */
-      sum = cff_parse_num( parser, &parser->stack[i + base] ) * 0x10000;
+      /* convert inputs to 16.16 fixed point */
+      sum = cff_parse_fixed( parser, &parser->stack[i + base] );
 
       for ( j = 1; j < blend->lenBV; j++ )
-        sum += cff_parse_num( parser, &parser->stack[delta++] ) * *weight++;
+        sum += FT_MulFix( cff_parse_fixed( parser, &parser->stack[delta++] ),
+                          *weight++ );
 
       /* point parser stack to new value on blend_stack */
       parser->stack[i + base] = subFont->blend_top;
@@ -1589,16 +1590,17 @@
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
 
   FT_LOCAL_DEF( FT_Error )
-  cff_get_var_blend( CFF_Face     face,
+  cff_get_var_blend( FT_Face      face,             /* CFF_Face */
                      FT_UInt     *num_coords,
                      FT_Fixed*   *coords,
                      FT_Fixed*   *normalizedcoords,
                      FT_MM_Var*  *mm_var )
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    return mm->get_var_blend( FT_FACE( face ),
+    return mm->get_var_blend( face,
                               num_coords,
                               coords,
                               normalizedcoords,
@@ -1607,13 +1609,14 @@
 
 
   FT_LOCAL_DEF( void )
-  cff_done_blend( CFF_Face  face )
+  cff_done_blend( FT_Face  face )    /* CFF_Face */
   {
-    FT_Service_MultiMasters  mm = (FT_Service_MultiMasters)face->mm;
+    CFF_Face                 cffface = (CFF_Face)face;
+    FT_Service_MultiMasters  mm      = (FT_Service_MultiMasters)cffface->mm;
 
 
-    if (mm)
-      mm->done_blend( FT_FACE( face ) );
+    if ( mm )
+      mm->done_blend( face );
   }
 
 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
@@ -1650,13 +1653,6 @@
       goto Exit;
     }
 
-    /* Zero out the code to gid/sid mappings. */
-    for ( j = 0; j < 256; j++ )
-    {
-      encoding->sids [j] = 0;
-      encoding->codes[j] = 0;
-    }
-
     /* Note: The encoding table in a CFF font is indexed by glyph index;  */
     /* the first encoded glyph index is 1.  Hence, we read the character  */
     /* code (`glyph_code') at index j and make the assignment:            */
@@ -1671,6 +1667,10 @@
 
     if ( offset > 1 )
     {
+      /* Zero out the code to gid/sid mappings. */
+      FT_ARRAY_ZERO( encoding->sids,  256 );
+      FT_ARRAY_ZERO( encoding->codes, 256 );
+
       encoding->offset = base_offset + offset;
 
       /* we need to parse the table to determine its size */
@@ -2012,7 +2012,7 @@
     /*       Top and Font DICTs are not allowed to have blend operators. */
     error = cff_parser_init( &parser,
                              code,
-                             &subfont->font_dict,
+                             top,
                              font->library,
                              stackSize,
                              0,
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffload.h b/src/java.desktop/share/native/libfreetype/src/cff/cffload.h
index 5a41cdebc8e74..b5286b0c8cb05 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffload.h
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffload.h
@@ -105,14 +105,14 @@ FT_BEGIN_HEADER
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
   FT_LOCAL( FT_Error )
-  cff_get_var_blend( CFF_Face     face,
+  cff_get_var_blend( FT_Face      face,
                      FT_UInt     *num_coords,
                      FT_Fixed*   *coords,
                      FT_Fixed*   *normalizedcoords,
                      FT_MM_Var*  *mm_var );
 
   FT_LOCAL( void )
-  cff_done_blend( CFF_Face  face );
+  cff_done_blend( FT_Face  face );
 #endif
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c
index 40cd9bf91733c..6d08620c487c0 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c
@@ -69,8 +69,8 @@
     FT_Module         module;
 
 
-    module = FT_Get_Module( size->root.face->driver->root.library,
-                            "pshinter" );
+    module = FT_Get_Module( font->library, "pshinter" );
+
     return ( module && pshinter && pshinter->get_globals_funcs )
            ? pshinter->get_globals_funcs( module )
            : 0;
@@ -182,8 +182,7 @@
       goto Exit;
 
     cff_make_private_dict( &font->top_font, &priv );
-    error = funcs->create( cffsize->face->memory, &priv,
-                             &internal->topfont );
+    error = funcs->create( memory, &priv, &internal->topfont );
     if ( error )
       goto Exit;
 
@@ -193,8 +192,7 @@
 
 
       cff_make_private_dict( sub, &priv );
-      error = funcs->create( cffsize->face->memory, &priv,
-                               &internal->subfonts[i - 1] );
+      error = funcs->create( memory, &priv, &internal->subfonts[i - 1] );
       if ( error )
         goto Exit;
     }
@@ -381,8 +379,7 @@
       FT_Module  module;
 
 
-      module = FT_Get_Module( slot->face->driver->root.library,
-                              "pshinter" );
+      module = FT_Get_Module( slot->library, "pshinter" );
       if ( module )
       {
         T2_Hints_Funcs  funcs;
@@ -722,22 +719,15 @@
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
       {
-        FT_Service_MultiMasters       mm  = (FT_Service_MultiMasters)face->mm;
-        FT_Service_MetricsVariations  var = (FT_Service_MetricsVariations)face->var;
-
         FT_UInt  instance_index = (FT_UInt)face_index >> 16;
 
 
         if ( FT_HAS_MULTIPLE_MASTERS( cffface ) &&
-             mm                                 &&
              instance_index > 0                 )
         {
-          error = mm->set_instance( cffface, instance_index );
+          error = FT_Set_Named_Instance( cffface, instance_index );
           if ( error )
             goto Exit;
-
-          if ( var )
-            var->metrics_adjust( cffface );
         }
       }
 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
@@ -1160,7 +1150,7 @@
     }
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-    cff_done_blend( face );
+    cff_done_blend( cffface );
     face->blend = NULL;
 #endif
   }
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c
index e16206fd553ae..3b076704cf732 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c
@@ -63,10 +63,7 @@
 
     /* allocate the stack buffer */
     if ( FT_QNEW_ARRAY( parser->stack, stackSize ) )
-    {
-      FT_FREE( parser->stack );
       goto Exit;
-    }
 
     parser->stackSize = stackSize;
     parser->top       = parser->stack;    /* empty stack */
@@ -76,23 +73,6 @@
   }
 
 
-#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
-  static void
-  finalize_t2_strings( FT_Memory  memory,
-                       void*      data,
-                       void*      user )
-  {
-    CFF_T2_String  t2 = (CFF_T2_String)data;
-
-
-    FT_UNUSED( user );
-
-    memory->free( memory, t2->start );
-    memory->free( memory, data );
-  }
-#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
-
-
   FT_LOCAL_DEF( void )
   cff_parser_done( CFF_Parser  parser )
   {
@@ -102,63 +82,19 @@
     FT_FREE( parser->stack );
 
 #ifdef CFF_CONFIG_OPTION_OLD_ENGINE
-    FT_List_Finalize( &parser->t2_strings,
-                      finalize_t2_strings,
-                      memory,
-                      NULL );
+    FT_List_Finalize( &parser->t2_strings, NULL, memory, NULL );
 #endif
   }
 
 
-  /* Assuming `first >= last'. */
-
-  static FT_Error
-  cff_parser_within_limits( CFF_Parser  parser,
-                            FT_Byte*    first,
-                            FT_Byte*    last )
-  {
-#ifndef CFF_CONFIG_OPTION_OLD_ENGINE
-
-    /* Fast path for regular FreeType builds with the "new" engine; */
-    /*   `first >= parser->start' can be assumed.                   */
-
-    FT_UNUSED( first );
-
-    return last < parser->limit ? FT_Err_Ok : FT_THROW( Invalid_Argument );
-
-#else /* CFF_CONFIG_OPTION_OLD_ENGINE */
-
-    FT_ListNode  node;
-
-
-    if ( first >= parser->start &&
-         last  <  parser->limit )
-      return FT_Err_Ok;
-
-    node = parser->t2_strings.head;
-
-    while ( node )
-    {
-      CFF_T2_String  t2 = (CFF_T2_String)node->data;
-
-
-      if ( first >= t2->start &&
-           last  <  t2->limit )
-        return FT_Err_Ok;
-
-      node = node->next;
-    }
-
-    return FT_THROW( Invalid_Argument );
-
-#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
-  }
-
+  /* The parser limit checks in the next two functions are supposed */
+  /* to detect the immediate crossing of the stream boundary.  They */
+  /* shall not be triggered from the distant t2_strings buffers.    */
 
   /* read an integer */
   static FT_Long
-  cff_parse_integer( CFF_Parser  parser,
-                     FT_Byte*    start )
+  cff_parse_integer( FT_Byte*  start,
+                     FT_Byte*  limit )
   {
     FT_Byte*  p   = start;
     FT_Int    v   = *p++;
@@ -167,14 +103,14 @@
 
     if ( v == 28 )
     {
-      if ( cff_parser_within_limits( parser, p, p + 1 ) )
+      if ( p + 2 > limit && limit >= p )
         goto Bad;
 
       val = (FT_Short)( ( (FT_UShort)p[0] << 8 ) | p[1] );
     }
     else if ( v == 29 )
     {
-      if ( cff_parser_within_limits( parser, p, p + 3 ) )
+      if ( p + 4 > limit && limit >= p )
         goto Bad;
 
       val = (FT_Long)( ( (FT_ULong)p[0] << 24 ) |
@@ -188,14 +124,14 @@
     }
     else if ( v < 251 )
     {
-      if ( cff_parser_within_limits( parser, p, p ) )
+      if ( p + 1 > limit && limit >= p )
         goto Bad;
 
       val = ( v - 247 ) * 256 + p[0] + 108;
     }
     else
     {
-      if ( cff_parser_within_limits( parser, p, p ) )
+      if ( p + 1 > limit && limit >= p )
         goto Bad;
 
       val = -( v - 251 ) * 256 - p[0] - 108;
@@ -244,10 +180,10 @@
 
   /* read a real */
   static FT_Fixed
-  cff_parse_real( CFF_Parser  parser,
-                  FT_Byte*    start,
-                  FT_Long     power_ten,
-                  FT_Long*    scaling )
+  cff_parse_real( FT_Byte*  start,
+                  FT_Byte*  limit,
+                  FT_Long   power_ten,
+                  FT_Long*  scaling )
   {
     FT_Byte*  p = start;
     FT_Int    nib;
@@ -282,7 +218,7 @@
         p++;
 
         /* Make sure we don't read past the end. */
-        if ( cff_parser_within_limits( parser, p, p ) )
+        if ( p + 1 > limit && limit >= p )
           goto Bad;
       }
 
@@ -319,7 +255,7 @@
           p++;
 
           /* Make sure we don't read past the end. */
-          if ( cff_parser_within_limits( parser, p, p ) )
+          if ( p + 1 > limit && limit >= p )
             goto Bad;
         }
 
@@ -358,7 +294,7 @@
           p++;
 
           /* Make sure we don't read past the end. */
-          if ( cff_parser_within_limits( parser, p, p ) )
+          if ( p + 1 > limit && limit >= p )
             goto Bad;
         }
 
@@ -525,7 +461,7 @@
     if ( **d == 30 )
     {
       /* binary-coded decimal is truncated to integer */
-      return cff_parse_real( parser, *d, 0, NULL ) >> 16;
+      return cff_parse_real( *d, parser->limit, 0, NULL ) >> 16;
     }
 
     else if ( **d == 255 )
@@ -551,7 +487,7 @@
     }
 
     else
-      return cff_parse_integer( parser, *d );
+      return cff_parse_integer( *d, parser->limit );
   }
 
 
@@ -562,15 +498,33 @@
             FT_Long     scaling )
   {
     if ( **d == 30 )
-      return cff_parse_real( parser, *d, scaling, NULL );
+      return cff_parse_real( *d, parser->limit, scaling, NULL );
+    else if ( **d == 255 )
+    {
+      FT_Fixed val = ( ( ( (FT_UInt32)*( d[0] + 1 ) << 24 ) |
+                         ( (FT_UInt32)*( d[0] + 2 ) << 16 ) |
+                         ( (FT_UInt32)*( d[0] + 3 ) <<  8 ) |
+                           (FT_UInt32)*( d[0] + 4 )         ) );
+
+      if ( scaling )
+      {
+        if ( FT_ABS( val ) > power_ten_limits[scaling] )
+        {
+           FT_TRACE4(( "!!!OVERFLOW:!!!" ));
+           return val > 0 ? 0x7FFFFFFFL : -0x7FFFFFFFL;
+        }
+        val *= power_tens[scaling];
+      }
+      return val;
+    }
     else
     {
-      FT_Long  val = cff_parse_integer( parser, *d );
+      FT_Long  val = cff_parse_integer( *d, parser->limit );
 
 
       if ( scaling )
       {
-        if ( FT_ABS( val ) > power_ten_limits[scaling] )
+        if ( ( FT_ABS( val ) << 16 ) > power_ten_limits[scaling] )
         {
           val = val > 0 ? 0x7FFFFFFFL : -0x7FFFFFFFL;
           goto Overflow;
@@ -600,7 +554,7 @@
 
 
   /* read a floating point number, either integer or real */
-  static FT_Fixed
+  FT_LOCAL_DEF( FT_Fixed )
   cff_parse_fixed( CFF_Parser  parser,
                    FT_Byte**   d )
   {
@@ -630,14 +584,14 @@
     FT_ASSERT( scaling );
 
     if ( **d == 30 )
-      return cff_parse_real( parser, *d, 0, scaling );
+      return cff_parse_real( *d, parser->limit, 0, scaling );
     else
     {
       FT_Long  number;
       FT_Int   integer_length;
 
 
-      number = cff_parse_integer( parser, d[0] );
+      number = cff_parse_integer( *d, parser->limit );
 
       if ( number > 0x7FFFL )
       {
@@ -686,7 +640,7 @@
 
       dict->has_font_matrix = TRUE;
 
-      /* We expect a well-formed font matrix, this is, the matrix elements */
+      /* We expect a well-formed font matrix, that is, the matrix elements */
       /* `xx' and `yy' are of approximately the same magnitude.  To avoid  */
       /* loss of precision, we use the magnitude of the largest matrix     */
       /* element to scale all other elements.  The scaling factor is then  */
@@ -1264,11 +1218,8 @@
         FT_Byte*     charstring_base;
         FT_ULong     charstring_len;
 
-        FT_Fixed*      stack;
-        FT_ListNode    node;
-        CFF_T2_String  t2;
-        FT_Fixed       t2_size;
-        FT_Byte*       q;
+        FT_Fixed*  stack;
+        FT_Byte*   q = NULL;
 
 
         charstring_base = ++p;
@@ -1309,39 +1260,18 @@
         /* Now copy the stack data in the temporary decoder object,    */
         /* converting it back to charstring number representations     */
         /* (this is ugly, I know).                                     */
+        /* The maximum required size is 5 bytes per stack element.     */
+        if ( FT_QALLOC( q, (FT_Long)( 2 * sizeof ( FT_ListNode ) ) +
+                           5 * ( decoder.top - decoder.stack ) ) )
+          goto Exit;
 
-        node = (FT_ListNode)memory->alloc( memory,
-                                           sizeof ( FT_ListNodeRec ) );
-        if ( !node )
-          goto Out_Of_Memory_Error;
-
-        FT_List_Add( &parser->t2_strings, node );
-
-        t2 = (CFF_T2_String)memory->alloc( memory,
-                                           sizeof ( CFF_T2_StringRec ) );
-        if ( !t2 )
-          goto Out_Of_Memory_Error;
-
-        node->data = t2;
-
-        /* `5' is the conservative upper bound of required bytes per stack */
-        /* element.                                                        */
-
-        t2_size = 5 * ( decoder.top - decoder.stack );
-
-        q = (FT_Byte*)memory->alloc( memory, t2_size );
-        if ( !q )
-          goto Out_Of_Memory_Error;
-
-        t2->start = q;
-        t2->limit = q + t2_size;
+        FT_List_Add( &parser->t2_strings, (FT_ListNode)q );
 
-        stack = decoder.stack;
+        q += 2 * sizeof ( FT_ListNode );
 
-        while ( stack < decoder.top )
+        for ( stack = decoder.stack; stack < decoder.top; stack++ )
         {
-          FT_ULong  num;
-          FT_Bool   neg;
+          FT_Long  num = *stack;
 
 
           if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize )
@@ -1349,69 +1279,37 @@
 
           *parser->top++ = q;
 
-          if ( *stack < 0 )
-          {
-            num = (FT_ULong)NEG_LONG( *stack );
-            neg = 1;
-          }
-          else
-          {
-            num = (FT_ULong)*stack;
-            neg = 0;
-          }
-
           if ( num & 0xFFFFU )
           {
-            if ( neg )
-              num = (FT_ULong)-num;
-
             *q++ = 255;
-            *q++ = ( num & 0xFF000000U ) >> 24;
-            *q++ = ( num & 0x00FF0000U ) >> 16;
-            *q++ = ( num & 0x0000FF00U ) >>  8;
-            *q++ =   num & 0x000000FFU;
+            *q++ = (FT_Byte)( ( num >> 24 ) & 0xFF );
+            *q++ = (FT_Byte)( ( num >> 16 ) & 0xFF );
+            *q++ = (FT_Byte)( ( num >>  8 ) & 0xFF );
+            *q++ = (FT_Byte)( ( num       ) & 0xFF );
           }
           else
           {
             num >>= 16;
 
-            if ( neg )
+            if ( -107 <= num && num <= 107 )
+              *q++ = (FT_Byte)( num + 139 );
+            else if ( 108 <= num && num <= 1131 )
             {
-              if ( num <= 107 )
-                *q++ = (FT_Byte)( 139 - num );
-              else if ( num <= 1131 )
-              {
-                *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 251 );
-                *q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
-              }
-              else
-              {
-                num = (FT_ULong)-num;
-
-                *q++ = 28;
-                *q++ = (FT_Byte)( num >> 8 );
-                *q++ = (FT_Byte)( num & 0xFF );
-              }
+              *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 );
+              *q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
+            }
+            else if ( -1131 <= num && num <= -108 )
+            {
+              *q++ = (FT_Byte)( ( ( -num - 108 ) >> 8 ) + 251 );
+              *q++ = (FT_Byte)( ( -num - 108) & 0xFF );
             }
             else
             {
-              if ( num <= 107 )
-                *q++ = (FT_Byte)( num + 139 );
-              else if ( num <= 1131 )
-              {
-                *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 );
-                *q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
-              }
-              else
-              {
-                *q++ = 28;
-                *q++ = (FT_Byte)( num >> 8 );
-                *q++ = (FT_Byte)( num & 0xFF );
-              }
+              *q++ = 28;
+              *q++ = (FT_Byte)( num >> 8 );
+              *q++ = (FT_Byte)( num & 0xFF );
             }
           }
-
-          stack++;
         }
       }
 #endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
@@ -1598,12 +1496,6 @@
   Exit:
     return error;
 
-#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
-  Out_Of_Memory_Error:
-    error = FT_THROW( Out_Of_Memory );
-    goto Exit;
-#endif
-
   Stack_Overflow:
     error = FT_THROW( Invalid_Argument );
     goto Exit;
diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h
index 58d59fa4ac5e5..418caacc68c94 100644
--- a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h
+++ b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h
@@ -76,6 +76,10 @@ FT_BEGIN_HEADER
   cff_parse_num( CFF_Parser  parser,
                  FT_Byte**   d );
 
+  FT_LOCAL( FT_Fixed )
+  cff_parse_fixed( CFF_Parser  parser,
+                   FT_Byte**   d );
+
   FT_LOCAL( FT_Error )
   cff_parser_init( CFF_Parser  parser,
                    FT_UInt     code,
@@ -133,15 +137,6 @@ FT_BEGIN_HEADER
 FT_END_HEADER
 
 
-#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
-  typedef struct  CFF_T2_String_
-  {
-    FT_Byte*  start;
-    FT_Byte*  limit;
-
-  } CFF_T2_StringRec, *CFF_T2_String;
-#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
-
 #endif /* CFFPARSE_H_ */
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c
index ba4b7565d5479..eaca765ad06c8 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c
@@ -40,6 +40,117 @@
 #define FT_COMPONENT  cidgload
 
 
+  /*
+   * A helper function to compute FD number (`fd_select`), the offset to the
+   * head of the glyph data (`off1`), and the offset to the and of the glyph
+   * data (`off2`).
+   *
+   * The number how many times `cid_get_offset` is invoked can be controlled
+   * by the number of non-NULL arguments.  If `fd_select` is non-NULL but
+   * `off1` and `off2` are NULL, `cid_get_offset` is invoked only for
+   * `fd_select`; `off1` and `off2` are not validated.
+   *
+   */
+  FT_LOCAL_DEF( FT_Error )
+  cid_compute_fd_and_offsets( CID_Face   face,
+                              FT_UInt    glyph_index,
+                              FT_ULong*  fd_select_p,
+                              FT_ULong*  off1_p,
+                              FT_ULong*  off2_p )
+  {
+    FT_Error  error = FT_Err_Ok;
+
+    CID_FaceInfo  cid       = &face->cid;
+    FT_Stream     stream    =  face->cid_stream;
+    FT_UInt       entry_len = cid->fd_bytes + cid->gd_bytes;
+
+    FT_Byte*  p;
+    FT_Bool   need_frame_exit = 0;
+    FT_ULong  fd_select, off1, off2;
+
+
+    /* For ordinary fonts, read the CID font dictionary index */
+    /* and charstring offset from the CIDMap.                 */
+
+    if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset +
+                         glyph_index * entry_len )               ||
+         FT_FRAME_ENTER( 2 * entry_len )                         )
+      goto Exit;
+
+    need_frame_exit = 1;
+
+    p         = (FT_Byte*)stream->cursor;
+    fd_select = cid_get_offset( &p, cid->fd_bytes );
+    off1      = cid_get_offset( &p, cid->gd_bytes );
+
+    p    += cid->fd_bytes;
+    off2  = cid_get_offset( &p, cid->gd_bytes );
+
+    if ( fd_select_p )
+      *fd_select_p = fd_select;
+    if ( off1_p )
+      *off1_p = off1;
+    if ( off2_p )
+      *off2_p = off2;
+
+    if ( fd_select >= cid->num_dicts )
+    {
+      /*
+       * fd_select == 0xFF is often used to indicate that the CID
+       * has no charstring to be rendered, similar to GID = 0xFFFF
+       * in TrueType fonts.
+       */
+      if ( ( cid->fd_bytes == 1 && fd_select == 0xFFU   ) ||
+           ( cid->fd_bytes == 2 && fd_select == 0xFFFFU ) )
+      {
+        FT_TRACE1(( "cid_load_glyph: fail for glyph index %d:\n",
+                    glyph_index ));
+        FT_TRACE1(( "                FD number %ld is the maximum\n",
+                    fd_select ));
+        FT_TRACE1(( "                integer fitting into %d byte%s\n",
+                    cid->fd_bytes, cid->fd_bytes == 1 ? "" : "s" ));
+      }
+      else
+      {
+        FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
+                    glyph_index ));
+        FT_TRACE0(( "                FD number %ld is larger\n",
+                    fd_select ));
+        FT_TRACE0(( "                than number of dictionaries (%d)\n",
+                    cid->num_dicts ));
+      }
+
+      error = FT_THROW( Invalid_Offset );
+      goto Exit;
+    }
+    else if ( off2 > stream->size )
+    {
+      FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
+                  glyph_index ));
+      FT_TRACE0(( "               end of the glyph data\n" ));
+      FT_TRACE0(( "               is beyond the data stream\n" ));
+
+      error = FT_THROW( Invalid_Offset );
+      goto Exit;
+    }
+    else if ( off1 > off2 )
+    {
+      FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
+                  glyph_index ));
+      FT_TRACE0(( "                the end position of glyph data\n" ));
+      FT_TRACE0(( "                is set before the start position\n" ));
+
+      error = FT_THROW( Invalid_Offset );
+    }
+
+    Exit:
+      if ( need_frame_exit )
+        FT_FRAME_EXIT();
+
+    return error;
+  }
+
+
   FT_CALLBACK_DEF( FT_Error )
   cid_load_glyph( T1_Decoder  decoder,
                   FT_UInt     glyph_index )
@@ -97,34 +208,14 @@
     else
 
 #endif /* FT_CONFIG_OPTION_INCREMENTAL */
-
-    /* For ordinary fonts read the CID font dictionary index */
-    /* and charstring offset from the CIDMap.                */
     {
-      FT_UInt   entry_len = cid->fd_bytes + cid->gd_bytes;
       FT_ULong  off1, off2;
 
 
-      if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset +
-                           glyph_index * entry_len )               ||
-           FT_FRAME_ENTER( 2 * entry_len )                         )
-        goto Exit;
-
-      p         = (FT_Byte*)stream->cursor;
-      fd_select = cid_get_offset( &p, cid->fd_bytes );
-      off1      = cid_get_offset( &p, cid->gd_bytes );
-      p        += cid->fd_bytes;
-      off2      = cid_get_offset( &p, cid->gd_bytes );
-      FT_FRAME_EXIT();
-
-      if ( fd_select >= cid->num_dicts ||
-           off2 > stream->size         ||
-           off1 > off2                 )
-      {
-        FT_TRACE0(( "cid_load_glyph: invalid glyph stream offsets\n" ));
-        error = FT_THROW( Invalid_Offset );
+      error = cid_compute_fd_and_offsets( face, glyph_index,
+                                          &fd_select, &off1, &off2 );
+      if ( error )
         goto Exit;
-      }
 
       glyph_length = off2 - off1;
 
@@ -161,7 +252,9 @@
       cs_offset = decoder->lenIV >= 0 ? (FT_UInt)decoder->lenIV : 0;
       if ( cs_offset > glyph_length )
       {
-        FT_TRACE0(( "cid_load_glyph: invalid glyph stream offsets\n" ));
+        FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%d, "
+                    "offset to the charstring is beyond glyph length\n",
+                    glyph_index ));
         error = FT_THROW( Invalid_Offset );
         goto Exit;
       }
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h
index 97954d418ffac..edd6229234c41 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h
@@ -42,6 +42,14 @@ FT_BEGIN_HEADER
                        FT_Int32      load_flags );
 
 
+  FT_LOCAL( FT_Error )
+  cid_compute_fd_and_offsets( CID_Face   face,
+                              FT_UInt    glyph_index,
+                              FT_ULong*  fd_select_p,
+                              FT_ULong*  off1_p,
+                              FT_ULong*  off2_p );
+
+
 FT_END_HEADER
 
 #endif /* CIDGLOAD_H_ */
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidload.c b/src/java.desktop/share/native/libfreetype/src/cid/cidload.c
index 26daa5da7f646..a7da8ea39d5d2 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidload.c
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidload.c
@@ -155,23 +155,24 @@
 
 
   FT_CALLBACK_DEF( void )
-  cid_parse_font_matrix( CID_Face     face,
-                         CID_Parser*  parser )
+  cid_parse_font_matrix( FT_Face  face,     /* CID_Face */
+                         void*    parser_ )
   {
+    CID_Face      cidface = (CID_Face)face;
+    CID_Parser*   parser  = (CID_Parser*)parser_;
     CID_FaceDict  dict;
-    FT_Face       root = (FT_Face)&face->root;
     FT_Fixed      temp[6];
     FT_Fixed      temp_scale;
 
 
-    if ( parser->num_dict < face->cid.num_dicts )
+    if ( parser->num_dict < cidface->cid.num_dicts )
     {
       FT_Matrix*  matrix;
       FT_Vector*  offset;
       FT_Int      result;
 
 
-      dict   = face->cid.font_dicts + parser->num_dict;
+      dict   = cidface->cid.font_dicts + parser->num_dict;
       matrix = &dict->font_matrix;
       offset = &dict->font_offset;
 
@@ -204,7 +205,7 @@
       if ( temp_scale != 0x10000L )
       {
         /* set units per EM based on FontMatrix values */
-        root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
+        face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
 
         temp[0] = FT_DivFix( temp[0], temp_scale );
         temp[1] = FT_DivFix( temp[1], temp_scale );
@@ -237,13 +238,15 @@
 
 
   FT_CALLBACK_DEF( void )
-  parse_fd_array( CID_Face     face,
-                  CID_Parser*  parser )
+  parse_fd_array( FT_Face  face,     /* CID_Face */
+                  void*    parser_ )
   {
-    CID_FaceInfo  cid    = &face->cid;
-    FT_Memory     memory = face->root.memory;
-    FT_Stream     stream = parser->stream;
-    FT_Error      error  = FT_Err_Ok;
+    CID_Face      cidface = (CID_Face)face;
+    CID_Parser*   parser  = (CID_Parser*)parser_;
+    CID_FaceInfo  cid     = &cidface->cid;
+    FT_Memory     memory  = FT_FACE_MEMORY( face );
+    FT_Stream     stream  = parser->stream;
+    FT_Error      error   = FT_Err_Ok;
     FT_Long       num_dicts, max_dicts;
 
 
@@ -313,18 +316,20 @@
 
   /* By mistake, `expansion_factor' appears both in PS_PrivateRec */
   /* and CID_FaceDictRec (both are public header files and can't  */
-  /* changed).  We simply copy the value.                         */
+  /* be thus changed).  We simply copy the value.                 */
 
   FT_CALLBACK_DEF( void )
-  parse_expansion_factor( CID_Face     face,
-                          CID_Parser*  parser )
+  parse_expansion_factor( FT_Face  face,    /* CID_Face */
+                          void*    parser_ )
   {
+    CID_Face      cidface = (CID_Face)face;
+    CID_Parser*   parser  = (CID_Parser*)parser_;
     CID_FaceDict  dict;
 
 
-    if ( parser->num_dict < face->cid.num_dicts )
+    if ( parser->num_dict < cidface->cid.num_dicts )
     {
-      dict = face->cid.font_dicts + parser->num_dict;
+      dict = cidface->cid.font_dicts + parser->num_dict;
 
       dict->expansion_factor              = cid_parser_to_fixed( parser, 0 );
       dict->private_dict.expansion_factor = dict->expansion_factor;
@@ -341,11 +346,15 @@
   /* to catch it for producing better trace output.                */
 
   FT_CALLBACK_DEF( void )
-  parse_font_name( CID_Face     face,
-                   CID_Parser*  parser )
+  parse_font_name( FT_Face  face,     /* CID_Face */
+                   void*    parser_ )
   {
 #ifdef FT_DEBUG_LEVEL_TRACE
-    if ( parser->num_dict < face->cid.num_dicts )
+    CID_Face      cidface = (CID_Face)face;
+    CID_Parser*   parser  = (CID_Parser*)parser_;
+
+
+    if ( parser->num_dict < cidface->cid.num_dicts )
     {
       T1_TokenRec  token;
       FT_UInt      len;
@@ -361,7 +370,7 @@
     }
 #else
     FT_UNUSED( face );
-    FT_UNUSED( parser );
+    FT_UNUSED( parser_ );
 #endif
 
     return;
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c b/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c
index 06b2139a93dc1..f698a419289e0 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c
@@ -69,8 +69,7 @@
       FT_Module  module;
 
 
-      module = FT_Get_Module( slot->face->driver->root.library,
-                              "pshinter" );
+      module = FT_Get_Module( slot->library, "pshinter" );
       if ( module )
       {
         T1_Hints_Funcs  funcs;
@@ -268,7 +267,8 @@
    *
    * @Input:
    *   stream ::
-   *     The source font stream.
+   *     Dummy argument for compatibility with the `FT_Face_InitFunc` API.
+   *     Ignored.  The stream should be passed through `face->root.stream`.
    *
    *   face_index ::
    *     The index of the font face in the resource.
@@ -375,6 +375,14 @@
       if ( info->is_fixed_pitch )
         cidface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
 
+      /*
+       * For the sfnt-wrapped CID fonts for MacOS, currently,
+       * its `cmap' tables are ignored, and the content in
+       * its `CID ' table is treated the same as naked CID-keyed
+       * font.  See ft_lookup_PS_in_sfnt_stream().
+       */
+      cidface->face_flags |= FT_FACE_FLAG_CID_KEYED;
+
       /* XXX: TODO: add kerning with .afm support */
 
       /* get style name -- be careful, some broken fonts only */
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c b/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c
index 16889db9b6fb2..171a886215ad2 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c
@@ -214,18 +214,24 @@
            cur <= limit - STARTDATA_LEN                            &&
            ft_strncmp( (char*)cur, STARTDATA, STARTDATA_LEN ) == 0 )
       {
-        if ( ft_strncmp( (char*)arg1, "(Hex)", 5 ) == 0 )
-        {
-          FT_Long  tmp = ft_strtol( (const char *)arg2, NULL, 10 );
+        T1_TokenRec  type_token;
+        FT_Long      binary_length;
 
 
-          if ( tmp < 0 )
+        parser->root.cursor = arg1;
+        cid_parser_to_token( parser, &type_token );
+        if ( type_token.limit - type_token.start == 5              &&
+             ft_memcmp( (char*)type_token.start, "(Hex)", 5 ) == 0 )
+        {
+          parser->root.cursor = arg2;
+          binary_length = cid_parser_to_int( parser );
+          if ( binary_length < 0 )
           {
             FT_ERROR(( "cid_parser_new: invalid length of hex data\n" ));
             error = FT_THROW( Invalid_File_Format );
           }
           else
-            parser->binary_length = (FT_ULong)tmp;
+            parser->binary_length = (FT_ULong)binary_length;
         }
 
         goto Exit;
diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c b/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c
index f7499237d73c2..99e7b11839511 100644
--- a/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c
+++ b/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c
@@ -48,10 +48,11 @@
    *
    */
 
-  static const char*
-  cid_get_postscript_name( CID_Face  face )
+  FT_CALLBACK_DEF( const char* )
+  cid_get_postscript_name( FT_Face  face )    /* CID_Face */
   {
-    const char*  result = face->cid.cid_font_name;
+    CID_Face     cidface = (CID_Face)face;
+    const char*  result  = cidface->cid.cid_font_name;
 
 
     if ( result && result[0] == '/' )
@@ -72,34 +73,36 @@
    *
    */
 
-  static FT_Error
-  cid_ps_get_font_info( FT_Face          face,
+  FT_CALLBACK_DEF( FT_Error )
+  cid_ps_get_font_info( FT_Face          face,        /* CID_Face */
                         PS_FontInfoRec*  afont_info )
   {
-    *afont_info = ((CID_Face)face)->cid.font_info;
+    *afont_info = ( (CID_Face)face )->cid.font_info;
 
     return FT_Err_Ok;
   }
 
-  static FT_Error
-  cid_ps_get_font_extra( FT_Face          face,
-                        PS_FontExtraRec*  afont_extra )
+
+  FT_CALLBACK_DEF( FT_Error )
+  cid_ps_get_font_extra( FT_Face           face,         /* CID_Face */
+                         PS_FontExtraRec*  afont_extra )
   {
-    *afont_extra = ((CID_Face)face)->font_extra;
+    *afont_extra = ( (CID_Face)face )->font_extra;
 
     return FT_Err_Ok;
   }
 
+
   static const FT_Service_PsInfoRec  cid_service_ps_info =
   {
-    (PS_GetFontInfoFunc)   cid_ps_get_font_info,   /* ps_get_font_info    */
-    (PS_GetFontExtraFunc)  cid_ps_get_font_extra,  /* ps_get_font_extra   */
+    cid_ps_get_font_info,   /* PS_GetFontInfoFunc    ps_get_font_info    */
+    cid_ps_get_font_extra,  /* PS_GetFontExtraFunc   ps_get_font_extra   */
     /* unsupported with CID fonts */
-    (PS_HasGlyphNamesFunc) NULL,                   /* ps_has_glyph_names  */
+    NULL,                   /* PS_HasGlyphNamesFunc  ps_has_glyph_names  */
     /* unsupported                */
-    (PS_GetFontPrivateFunc)NULL,                   /* ps_get_font_private */
+    NULL,                   /* PS_GetFontPrivateFunc ps_get_font_private */
     /* not implemented            */
-    (PS_GetFontValueFunc)  NULL                    /* ps_get_font_value   */
+    NULL                    /* PS_GetFontValueFunc   ps_get_font_value   */
   };
 
 
@@ -107,13 +110,14 @@
    * CID INFO SERVICE
    *
    */
-  static FT_Error
-  cid_get_ros( CID_Face      face,
+  FT_CALLBACK_DEF( FT_Error )
+  cid_get_ros( FT_Face       face,        /* CID_Face */
                const char*  *registry,
                const char*  *ordering,
                FT_Int       *supplement )
   {
-    CID_FaceInfo  cid = &face->cid;
+    CID_Face      cidface = (CID_Face)face;
+    CID_FaceInfo  cid     = &cidface->cid;
 
 
     if ( registry )
@@ -129,32 +133,48 @@
   }
 
 
-  static FT_Error
-  cid_get_is_cid( CID_Face  face,
+  FT_CALLBACK_DEF( FT_Error )
+  cid_get_is_cid( FT_Face   face,    /* CID_Face */
                   FT_Bool  *is_cid )
   {
     FT_Error  error = FT_Err_Ok;
     FT_UNUSED( face );
 
 
+    /*
+     * XXX: If the ROS is Adobe-Identity-H or -V,
+     * the font has no reliable information about
+     * its glyph collection.  Should we not set
+     * *is_cid in such cases?
+     */
     if ( is_cid )
-      *is_cid = 1; /* cid driver is only used for CID keyed fonts */
+      *is_cid = 1;
 
     return error;
   }
 
 
-  static FT_Error
-  cid_get_cid_from_glyph_index( CID_Face  face,
+  FT_CALLBACK_DEF( FT_Error )
+  cid_get_cid_from_glyph_index( FT_Face   face,        /* CID_Face */
                                 FT_UInt   glyph_index,
                                 FT_UInt  *cid )
   {
-    FT_Error  error = FT_Err_Ok;
-    FT_UNUSED( face );
-
-
-    if ( cid )
-      *cid = glyph_index; /* identity mapping */
+    FT_Error  error   = FT_Err_Ok;
+    CID_Face  cidface = (CID_Face)face;
+
+
+    /*
+     * Currently, FreeType does not support incrementally-defined, CID-keyed
+     * fonts that store the glyph description data in a `/GlyphDirectory`
+     * array or dictionary.  Fonts loaded by the incremental loading feature
+     * are thus not handled here.
+     */
+    error = cid_compute_fd_and_offsets( cidface, glyph_index,
+                                        NULL, NULL, NULL );
+    if ( error )
+      *cid = 0;
+    else
+      *cid = glyph_index;
 
     return error;
   }
@@ -162,12 +182,12 @@
 
   static const FT_Service_CIDRec  cid_service_cid_info =
   {
-    (FT_CID_GetRegistryOrderingSupplementFunc)
-      cid_get_ros,                             /* get_ros                  */
-    (FT_CID_GetIsInternallyCIDKeyedFunc)
-      cid_get_is_cid,                          /* get_is_cid               */
-    (FT_CID_GetCIDFromGlyphIndexFunc)
-      cid_get_cid_from_glyph_index             /* get_cid_from_glyph_index */
+    cid_get_ros,
+      /* FT_CID_GetRegistryOrderingSupplementFunc get_ros                  */
+    cid_get_is_cid,
+      /* FT_CID_GetIsInternallyCIDKeyedFunc       get_is_cid               */
+    cid_get_cid_from_glyph_index
+      /* FT_CID_GetCIDFromGlyphIndexFunc          get_cid_from_glyph_index */
   };
 
 
@@ -179,9 +199,9 @@
   FT_DEFINE_SERVICE_PROPERTIESREC(
     cid_service_properties,
 
-    (FT_Properties_SetFunc)ps_property_set,      /* set_property */
-    (FT_Properties_GetFunc)ps_property_get )     /* get_property */
-
+    ps_property_set,  /* FT_Properties_SetFunc set_property */
+    ps_property_get   /* FT_Properties_GetFunc get_property */
+  )
 
   /*
    * SERVICE LIST
@@ -209,7 +229,6 @@
   }
 
 
-
   FT_CALLBACK_TABLE_DEF
   const FT_Driver_ClassRec  t1cid_driver_class =
   {
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c b/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c
index 68f95698e6570..db08941def744 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c
@@ -1086,7 +1086,7 @@
 #else /* T1_CONFIG_OPTION_NO_AFM */
 
   /* ANSI C doesn't like empty source files */
-  typedef int  _afm_parse_dummy;
+  typedef int  afm_parse_dummy_;
 
 #endif /* T1_CONFIG_OPTION_NO_AFM */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c b/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c
index 2cd91c96f357d..562d17d221649 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c
@@ -2153,7 +2153,7 @@
                                       decoder->locals_bias );
 
 
-            FT_TRACE4(( " callsubr (idx %d, entering level %ld)\n",
+            FT_TRACE4(( " callsubr (idx %d, entering level %td)\n",
                         idx,
                         zone - decoder->zones + 1 ));
 
@@ -2197,7 +2197,7 @@
                                       decoder->globals_bias );
 
 
-            FT_TRACE4(( " callgsubr (idx %d, entering level %ld)\n",
+            FT_TRACE4(( " callgsubr (idx %d, entering level %td)\n",
                         idx,
                         zone - decoder->zones + 1 ));
 
@@ -2236,7 +2236,7 @@
           break;
 
         case cff_op_return:
-          FT_TRACE4(( " return (leaving level %ld)\n",
+          FT_TRACE4(( " return (leaving level %td)\n",
                       decoder->zone - decoder->zones ));
 
           if ( decoder->zone <= decoder->zones )
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/pshints.c b/src/java.desktop/share/native/libfreetype/src/psaux/pshints.c
index 6f44d0adbb728..7bd08a9c9bf86 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/pshints.c
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/pshints.c
@@ -310,7 +310,7 @@
       CF2_Hint  hint = &hintmap->edge[i];
 
 
-      FT_TRACE6(( "  %3ld    %7.2f  %7.2f  %5d  %s%s%s%s\n",
+      FT_TRACE6(( "  %3zu    %7.2f  %7.2f  %5d  %s%s%s%s\n",
                   hint->index,
                   hint->csCoord / 65536.0,
                   hint->dsCoord / ( hint->scale * 1.0 ),
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c b/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c
index bf0a393b456e8..c4bcf599ea3ad 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c
@@ -50,8 +50,11 @@
 
 
   FT_CALLBACK_DEF( void )
-  t1_cmap_std_done( T1_CMapStd  cmap )
+  t1_cmap_std_done( FT_CMap  cmap_ )   /* T1_CMapStd */
   {
+    T1_CMapStd  cmap = (T1_CMapStd)cmap_;
+
+
     cmap->num_glyphs    = 0;
     cmap->glyph_names   = NULL;
     cmap->sid_to_string = NULL;
@@ -60,10 +63,11 @@
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  t1_cmap_std_char_index( T1_CMapStd  cmap,
-                          FT_UInt32   char_code )
+  t1_cmap_std_char_index( FT_CMap    cmap,       /* T1_CMapStd */
+                          FT_UInt32  char_code )
   {
-    FT_UInt  result = 0;
+    T1_CMapStd  t1cmap = (T1_CMapStd)cmap;
+    FT_UInt     result = 0;
 
 
     if ( char_code < 256 )
@@ -73,13 +77,13 @@
 
 
       /* convert character code to Adobe SID string */
-      code       = cmap->code_to_sid[char_code];
-      glyph_name = cmap->sid_to_string( code );
+      code       = t1cmap->code_to_sid[char_code];
+      glyph_name = t1cmap->sid_to_string( code );
 
       /* look for the corresponding glyph name */
-      for ( n = 0; n < cmap->num_glyphs; n++ )
+      for ( n = 0; n < t1cmap->num_glyphs; n++ )
       {
-        const char* gname = cmap->glyph_names[n];
+        const char* gname = t1cmap->glyph_names[n];
 
 
         if ( gname && gname[0] == glyph_name[0]  &&
@@ -95,9 +99,9 @@
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  t1_cmap_std_char_next( T1_CMapStd   cmap,
-                         FT_UInt32   *pchar_code )
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_std_char_next( FT_CMap     cmap,
+                         FT_UInt32  *pchar_code )
   {
     FT_UInt    result    = 0;
     FT_UInt32  char_code = *pchar_code + 1;
@@ -120,13 +124,14 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  t1_cmap_standard_init( T1_CMapStd  cmap,
+  t1_cmap_standard_init( FT_CMap     cmap,     /* T1_CMapStd */
                          FT_Pointer  pointer )
   {
+    T1_CMapStd  t1cmap = (T1_CMapStd)cmap;
     FT_UNUSED( pointer );
 
 
-    t1_cmap_std_init( cmap, 0 );
+    t1_cmap_std_init( t1cmap, 0 );
     return 0;
   }
 
@@ -150,13 +155,14 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  t1_cmap_expert_init( T1_CMapStd  cmap,
+  t1_cmap_expert_init( FT_CMap     cmap,     /* T1_CMapStd */
                        FT_Pointer  pointer )
   {
+    T1_CMapStd  t1cmap = (T1_CMapStd)cmap;
     FT_UNUSED( pointer );
 
 
-    t1_cmap_std_init( cmap, 1 );
+    t1_cmap_std_init( t1cmap, 1 );
     return 0;
   }
 
@@ -188,20 +194,21 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  t1_cmap_custom_init( T1_CMapCustom  cmap,
-                       FT_Pointer     pointer )
+  t1_cmap_custom_init( FT_CMap     cmap,     /* T1_CMapCustom */
+                       FT_Pointer  pointer )
   {
-    T1_Face      face     = (T1_Face)FT_CMAP_FACE( cmap );
-    T1_Encoding  encoding = &face->type1.encoding;
+    T1_CMapCustom  t1cmap   = (T1_CMapCustom)cmap;
+    T1_Face        face     = (T1_Face)FT_CMAP_FACE( cmap );
+    T1_Encoding    encoding = &face->type1.encoding;
 
     FT_UNUSED( pointer );
 
 
-    cmap->first   = (FT_UInt)encoding->code_first;
-    cmap->count   = (FT_UInt)encoding->code_last - cmap->first;
-    cmap->indices = encoding->char_index;
+    t1cmap->first   = (FT_UInt)encoding->code_first;
+    t1cmap->count   = (FT_UInt)encoding->code_last - t1cmap->first;
+    t1cmap->indices = encoding->char_index;
 
-    FT_ASSERT( cmap->indices );
+    FT_ASSERT( t1cmap->indices );
     FT_ASSERT( encoding->code_first <= encoding->code_last );
 
     return 0;
@@ -209,45 +216,50 @@
 
 
   FT_CALLBACK_DEF( void )
-  t1_cmap_custom_done( T1_CMapCustom  cmap )
+  t1_cmap_custom_done( FT_CMap  cmap )   /* T1_CMapCustom */
   {
-    cmap->indices = NULL;
-    cmap->first   = 0;
-    cmap->count   = 0;
+    T1_CMapCustom  t1cmap = (T1_CMapCustom)cmap;
+
+
+    t1cmap->indices = NULL;
+    t1cmap->first   = 0;
+    t1cmap->count   = 0;
   }
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  t1_cmap_custom_char_index( T1_CMapCustom  cmap,
-                             FT_UInt32      char_code )
+  t1_cmap_custom_char_index( FT_CMap    cmap,       /* T1_CMapCustom */
+                             FT_UInt32  char_code )
   {
-    FT_UInt    result = 0;
+    T1_CMapCustom  t1cmap = (T1_CMapCustom)cmap;
+    FT_UInt        result = 0;
 
 
-    if ( ( char_code >= cmap->first )                  &&
-         ( char_code < ( cmap->first + cmap->count ) ) )
-      result = cmap->indices[char_code];
+    if ( char_code >= t1cmap->first                    &&
+         char_code < ( t1cmap->first + t1cmap->count ) )
+      result = t1cmap->indices[char_code];
 
     return result;
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  t1_cmap_custom_char_next( T1_CMapCustom  cmap,
-                            FT_UInt32     *pchar_code )
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_custom_char_next( FT_CMap     cmap,        /* T1_CMapCustom */
+                            FT_UInt32  *pchar_code )
   {
-    FT_UInt    result = 0;
-    FT_UInt32  char_code = *pchar_code;
+    T1_CMapCustom  t1cmap    = (T1_CMapCustom)cmap;
+    FT_UInt        result    = 0;
+    FT_UInt32      char_code = *pchar_code;
 
 
     char_code++;
 
-    if ( char_code < cmap->first )
-      char_code = cmap->first;
+    if ( char_code < t1cmap->first )
+      char_code = t1cmap->first;
 
-    for ( ; char_code < ( cmap->first + cmap->count ); char_code++ )
+    for ( ; char_code < ( t1cmap->first + t1cmap->count ); char_code++ )
     {
-      result = cmap->indices[char_code];
+      result = t1cmap->indices[char_code];
       if ( result != 0 )
         goto Exit;
     }
@@ -287,20 +299,24 @@
   /*************************************************************************/
 
   FT_CALLBACK_DEF( const char * )
-  psaux_get_glyph_name( T1_Face  face,
+  psaux_get_glyph_name( void*    face_,
                         FT_UInt  idx )
   {
+    T1_Face  face = (T1_Face)face_;
+
+
     return face->type1.glyph_names[idx];
   }
 
 
   FT_CALLBACK_DEF( FT_Error )
-  t1_cmap_unicode_init( PS_Unicodes  unicodes,
-                        FT_Pointer   pointer )
+  t1_cmap_unicode_init( FT_CMap     cmap,     /* PS_Unicodes */
+                        FT_Pointer  pointer )
   {
-    T1_Face             face    = (T1_Face)FT_CMAP_FACE( unicodes );
-    FT_Memory           memory  = FT_FACE_MEMORY( face );
-    FT_Service_PsCMaps  psnames = (FT_Service_PsCMaps)face->psnames;
+    PS_Unicodes         unicodes = (PS_Unicodes)cmap;
+    T1_Face             face     = (T1_Face)FT_CMAP_FACE( cmap );
+    FT_Memory           memory   = FT_FACE_MEMORY( face );
+    FT_Service_PsCMaps  psnames  = (FT_Service_PsCMaps)face->psnames;
 
     FT_UNUSED( pointer );
 
@@ -311,17 +327,18 @@
     return psnames->unicodes_init( memory,
                                    unicodes,
                                    (FT_UInt)face->type1.num_glyphs,
-                                   (PS_GetGlyphNameFunc)&psaux_get_glyph_name,
+                                   &psaux_get_glyph_name,
                                    (PS_FreeGlyphNameFunc)NULL,
                                    (FT_Pointer)face );
   }
 
 
   FT_CALLBACK_DEF( void )
-  t1_cmap_unicode_done( PS_Unicodes  unicodes )
+  t1_cmap_unicode_done( FT_CMap  cmap )   /* PS_Unicodes */
   {
-    FT_Face    face   = FT_CMAP_FACE( unicodes );
-    FT_Memory  memory = FT_FACE_MEMORY( face );
+    PS_Unicodes  unicodes = (PS_Unicodes)cmap;
+    FT_Face      face     = FT_CMAP_FACE( cmap );
+    FT_Memory    memory   = FT_FACE_MEMORY( face );
 
 
     FT_FREE( unicodes->maps );
@@ -330,23 +347,25 @@
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  t1_cmap_unicode_char_index( PS_Unicodes  unicodes,
-                              FT_UInt32    char_code )
+  t1_cmap_unicode_char_index( FT_CMap    cmap,       /* PS_Unicodes */
+                              FT_UInt32  char_code )
   {
-    T1_Face             face    = (T1_Face)FT_CMAP_FACE( unicodes );
-    FT_Service_PsCMaps  psnames = (FT_Service_PsCMaps)face->psnames;
+    PS_Unicodes         unicodes = (PS_Unicodes)cmap;
+    T1_Face             face     = (T1_Face)FT_CMAP_FACE( cmap );
+    FT_Service_PsCMaps  psnames  = (FT_Service_PsCMaps)face->psnames;
 
 
     return psnames->unicodes_char_index( unicodes, char_code );
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  t1_cmap_unicode_char_next( PS_Unicodes  unicodes,
-                             FT_UInt32   *pchar_code )
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_unicode_char_next( FT_CMap     cmap,        /* PS_Unicodes */
+                             FT_UInt32  *pchar_code )
   {
-    T1_Face             face    = (T1_Face)FT_CMAP_FACE( unicodes );
-    FT_Service_PsCMaps  psnames = (FT_Service_PsCMaps)face->psnames;
+    PS_Unicodes         unicodes = (PS_Unicodes)cmap;
+    T1_Face             face     = (T1_Face)FT_CMAP_FACE( cmap );
+    FT_Service_PsCMaps  psnames  = (FT_Service_PsCMaps)face->psnames;
 
 
     return psnames->unicodes_char_next( unicodes, pchar_code );
diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c b/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c
index bfed45b53a3a2..4b6b969bcb99e 100644
--- a/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c
+++ b/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c
@@ -520,7 +520,7 @@
 #ifdef FT_DEBUG_LEVEL_TRACE
       if ( bol )
       {
-        FT_TRACE5(( " (%ld)", decoder->top - decoder->stack ));
+        FT_TRACE5(( " (%td)", decoder->top - decoder->stack ));
         bol = FALSE;
       }
 #endif
@@ -1165,7 +1165,7 @@
           if ( top - decoder->stack != num_args )
             FT_TRACE0(( "t1_decoder_parse_charstrings:"
                         " too much operands on the stack"
-                        " (seen %ld, expected %d)\n",
+                        " (seen %td, expected %d)\n",
                         top - decoder->stack, num_args ));
           break;
         }
diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c
index a7f321291a94a..4f622e1e440f0 100644
--- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c
+++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c
@@ -516,7 +516,7 @@
             if ( !psh_hint_is_fitted( parent ) )
               psh_hint_align( parent, globals, dimension, glyph );
 
-            /* keep original relation between hints, this is, use the */
+            /* keep original relation between hints, that is, use the */
             /* scaled distance between the centers of the hints to    */
             /* compute the new position                               */
             par_org_center = parent->org_pos + ( parent->org_len >> 1 );
diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c
index a12e485660153..974a99e0186d3 100644
--- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c
+++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c
@@ -37,8 +37,11 @@
 
   /* finalize module */
   FT_CALLBACK_DEF( void )
-  ps_hinter_done( PS_Hinter_Module  module )
+  ps_hinter_done( FT_Module  module_ )    /* PS_Hinter_Module */
   {
+    PS_Hinter_Module  module = (PS_Hinter_Module)module_;
+
+
     module->t1_funcs.hints = NULL;
     module->t2_funcs.hints = NULL;
 
@@ -48,8 +51,10 @@
 
   /* initialize module, create hints recorder and the interface */
   FT_CALLBACK_DEF( FT_Error )
-  ps_hinter_init( PS_Hinter_Module  module )
+  ps_hinter_init( FT_Module  module_ )    /* PS_Hinter_Module */
   {
+    PS_Hinter_Module  module = (PS_Hinter_Module)module_;
+
     FT_Memory  memory = module->root.memory;
     void*      ph     = &module->ps_hints;
 
diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c
index 58c8cf1b4861b..680e6d013588f 100644
--- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c
+++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c
@@ -851,10 +851,11 @@
 
   /* add one Type1 counter stem to the current hints table */
   static void
-  ps_hints_t1stem3( PS_Hints   hints,
+  ps_hints_t1stem3( T1_Hints   hints_,    /* PS_Hints */
                     FT_UInt    dimension,
                     FT_Fixed*  stems )
   {
+    PS_Hints  hints = (PS_Hints)hints_;
     FT_Error  error = FT_Err_Ok;
 
 
@@ -914,9 +915,10 @@
 
   /* reset hints (only with Type 1 hints) */
   static void
-  ps_hints_t1reset( PS_Hints  hints,
+  ps_hints_t1reset( T1_Hints  hints_,     /* PS_Hints */
                     FT_UInt   end_point )
   {
+    PS_Hints  hints = (PS_Hints)hints_;
     FT_Error  error = FT_Err_Ok;
 
 
@@ -953,11 +955,12 @@
 
   /* Type2 "hintmask" operator, add a new hintmask to each direction */
   static void
-  ps_hints_t2mask( PS_Hints        hints,
+  ps_hints_t2mask( T2_Hints        hints_,    /* PS_Hints */
                    FT_UInt         end_point,
                    FT_UInt         bit_count,
                    const FT_Byte*  bytes )
   {
+    PS_Hints  hints = (PS_Hints)hints_;
     FT_Error  error;
 
 
@@ -999,10 +1002,11 @@
 
 
   static void
-  ps_hints_t2counter( PS_Hints        hints,
+  ps_hints_t2counter( T2_Hints        hints_,    /* PS_Hints */
                       FT_UInt         bit_count,
                       const FT_Byte*  bytes )
   {
+    PS_Hints  hints = (PS_Hints)hints_;
     FT_Error  error;
 
 
@@ -1087,6 +1091,13 @@
     ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 );
   }
 
+  static FT_Error
+  t1_hints_close( T1_Hints  hints,
+                  FT_UInt   end_point )
+  {
+    return ps_hints_close( (PS_Hints)hints, end_point );
+  }
+
   static void
   t1_hints_stem( T1_Hints   hints,
                  FT_UInt    dimension,
@@ -1102,17 +1113,27 @@
   }
 
 
+  static FT_Error
+  t1_hints_apply( T1_Hints        hints,
+                  FT_Outline*     outline,
+                  PSH_Globals     globals,
+                  FT_Render_Mode  hint_mode )
+  {
+    return ps_hints_apply( (PS_Hints)hints, outline, globals, hint_mode );
+  }
+
+
   FT_LOCAL_DEF( void )
   t1_hints_funcs_init( T1_Hints_FuncsRec*  funcs )
   {
     FT_ZERO( funcs );
 
     funcs->open  = (T1_Hints_OpenFunc)    t1_hints_open;
-    funcs->close = (T1_Hints_CloseFunc)   ps_hints_close;
+    funcs->close = (T1_Hints_CloseFunc)   t1_hints_close;
     funcs->stem  = (T1_Hints_SetStemFunc) t1_hints_stem;
     funcs->stem3 = (T1_Hints_SetStem3Func)ps_hints_t1stem3;
     funcs->reset = (T1_Hints_ResetFunc)   ps_hints_t1reset;
-    funcs->apply = (T1_Hints_ApplyFunc)   ps_hints_apply;
+    funcs->apply = (T1_Hints_ApplyFunc)   t1_hints_apply;
   }
 
 
@@ -1131,6 +1152,14 @@
   }
 
 
+  static FT_Error
+  t2_hints_close( T2_Hints  hints,
+                  FT_UInt   end_point )
+  {
+    return ps_hints_close( (PS_Hints)hints, end_point );
+  }
+
+
   static void
   t2_hints_stems( T2_Hints   hints,
                   FT_UInt    dimension,
@@ -1168,17 +1197,27 @@
   }
 
 
+  static FT_Error
+  t2_hints_apply( T2_Hints        hints,
+                  FT_Outline*     outline,
+                  PSH_Globals     globals,
+                  FT_Render_Mode  hint_mode )
+  {
+    return ps_hints_apply( (PS_Hints)hints, outline, globals, hint_mode );
+  }
+
+
   FT_LOCAL_DEF( void )
   t2_hints_funcs_init( T2_Hints_FuncsRec*  funcs )
   {
     FT_ZERO( funcs );
 
-    funcs->open    = (T2_Hints_OpenFunc)   t2_hints_open;
-    funcs->close   = (T2_Hints_CloseFunc)  ps_hints_close;
-    funcs->stems   = (T2_Hints_StemsFunc)  t2_hints_stems;
-    funcs->hintmask= (T2_Hints_MaskFunc)   ps_hints_t2mask;
-    funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter;
-    funcs->apply   = (T2_Hints_ApplyFunc)  ps_hints_apply;
+    funcs->open     = (T2_Hints_OpenFunc)   t2_hints_open;
+    funcs->close    = (T2_Hints_CloseFunc)  t2_hints_close;
+    funcs->stems    = (T2_Hints_StemsFunc)  t2_hints_stems;
+    funcs->hintmask = (T2_Hints_MaskFunc)   ps_hints_t2mask;
+    funcs->counter  = (T2_Hints_CounterFunc)ps_hints_t2counter;
+    funcs->apply    = (T2_Hints_ApplyFunc)  t2_hints_apply;
   }
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c b/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c
index db454e558ebb6..8203a0465d25e 100644
--- a/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c
+++ b/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c
@@ -57,7 +57,7 @@
   /* the name, as in `A.swash' or `e.final'; in this case, the           */
   /* VARIANT_BIT is set in the return value.                             */
   /*                                                                     */
-  static FT_UInt32
+  FT_CALLBACK_DEF( FT_UInt32 )
   ps_unicode_value( const char*  glyph_name )
   {
     /* If the name begins with `uni', then the glyph name may be a */
@@ -309,7 +309,7 @@
 
 
   /* Build a table that maps Unicode values to glyph indices. */
-  static FT_Error
+  FT_CALLBACK_DEF( FT_Error )
   ps_unicodes_init( FT_Memory             memory,
                     PS_Unicodes           table,
                     FT_UInt               num_glyphs,
@@ -408,7 +408,7 @@
   }
 
 
-  static FT_UInt
+  FT_CALLBACK_DEF( FT_UInt )
   ps_unicodes_char_index( PS_Unicodes  table,
                           FT_UInt32    unicode )
   {
@@ -453,7 +453,7 @@
   }
 
 
-  static FT_UInt32
+  FT_CALLBACK_DEF( FT_UInt )
   ps_unicodes_char_next( PS_Unicodes  table,
                          FT_UInt32   *unicode )
   {
@@ -518,7 +518,7 @@
 #endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
 
 
-  static const char*
+  FT_CALLBACK_DEF( const char* )
   ps_get_macintosh_name( FT_UInt  name_index )
   {
     if ( name_index >= FT_NUM_MAC_NAMES )
@@ -528,7 +528,7 @@
   }
 
 
-  static const char*
+  FT_CALLBACK_DEF( const char* )
   ps_get_standard_strings( FT_UInt  sid )
   {
     if ( sid >= FT_NUM_SID_NAMES )
@@ -543,13 +543,13 @@
   FT_DEFINE_SERVICE_PSCMAPSREC(
     pscmaps_interface,
 
-    (PS_Unicode_ValueFunc)     ps_unicode_value,        /* unicode_value         */
-    (PS_Unicodes_InitFunc)     ps_unicodes_init,        /* unicodes_init         */
-    (PS_Unicodes_CharIndexFunc)ps_unicodes_char_index,  /* unicodes_char_index   */
-    (PS_Unicodes_CharNextFunc) ps_unicodes_char_next,   /* unicodes_char_next    */
+    ps_unicode_value,         /* PS_Unicode_ValueFunc      unicode_value         */
+    ps_unicodes_init,         /* PS_Unicodes_InitFunc      unicodes_init         */
+    ps_unicodes_char_index,   /* PS_Unicodes_CharIndexFunc unicodes_char_index   */
+    ps_unicodes_char_next,    /* PS_Unicodes_CharNextFunc  unicodes_char_next    */
 
-    (PS_Macintosh_NameFunc)    ps_get_macintosh_name,   /* macintosh_name        */
-    (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, /* adobe_std_strings     */
+    ps_get_macintosh_name,    /* PS_Macintosh_NameFunc     macintosh_name        */
+    ps_get_standard_strings,  /* PS_Adobe_Std_StringsFunc  adobe_std_strings     */
 
     t1_standard_encoding,                               /* adobe_std_encoding    */
     t1_expert_encoding                                  /* adobe_expert_encoding */
@@ -560,13 +560,13 @@
   FT_DEFINE_SERVICE_PSCMAPSREC(
     pscmaps_interface,
 
-    NULL,                                               /* unicode_value         */
-    NULL,                                               /* unicodes_init         */
-    NULL,                                               /* unicodes_char_index   */
-    NULL,                                               /* unicodes_char_next    */
+    NULL,                     /* PS_Unicode_ValueFunc      unicode_value         */
+    NULL,                     /* PS_Unicodes_InitFunc      unicodes_init         */
+    NULL,                     /* PS_Unicodes_CharIndexFunc unicodes_char_index   */
+    NULL,                     /* PS_Unicodes_CharNextFunc  unicodes_char_next    */
 
-    (PS_Macintosh_NameFunc)    ps_get_macintosh_name,   /* macintosh_name        */
-    (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, /* adobe_std_strings     */
+    ps_get_macintosh_name,    /* PS_Macintosh_NameFunc     macintosh_name        */
+    ps_get_standard_strings,  /* PS_Adobe_Std_StringsFunc  adobe_std_strings     */
 
     t1_standard_encoding,                               /* adobe_std_encoding    */
     t1_expert_encoding                                  /* adobe_expert_encoding */
@@ -612,9 +612,9 @@
     PUT_PS_NAMES_SERVICE(
       (void*)&pscmaps_interface ),   /* module specific interface */
 
-    (FT_Module_Constructor)NULL,                                       /* module_init   */
-    (FT_Module_Destructor) NULL,                                       /* module_done   */
-    (FT_Module_Requester)  PUT_PS_NAMES_SERVICE( psnames_get_service ) /* get_interface */
+    NULL,                                        /* FT_Module_Constructor module_init   */
+    NULL,                                        /* FT_Module_Destructor  module_done   */
+    PUT_PS_NAMES_SERVICE( psnames_get_service )  /* FT_Module_Requester   get_interface */
   )
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c
index 67cbfd5d9b7eb..192ca0701a242 100644
--- a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c
+++ b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c
@@ -1742,9 +1742,9 @@
    *   SUCCESS on success, FAILURE on error.
    */
   static Bool
-  Decompose_Curve( RAS_ARGS UShort  first,
-                            UShort  last,
-                            Int     flipped )
+  Decompose_Curve( RAS_ARGS Int  first,
+                            Int  last,
+                            Int  flipped )
   {
     FT_Vector   v_last;
     FT_Vector   v_control;
@@ -1969,8 +1969,8 @@
   static Bool
   Convert_Glyph( RAS_ARGS Int  flipped )
   {
-    Int   i;
-    UInt  start;
+    Int  i;
+    Int  first, last;
 
 
     ras.fProfile = NULL;
@@ -1985,8 +1985,7 @@
     ras.cProfile->offset = ras.top;
     ras.num_Profs        = 0;
 
-    start = 0;
-
+    last = -1;
     for ( i = 0; i < ras.outline.n_contours; i++ )
     {
       PProfile  lastProfile;
@@ -1996,12 +1995,11 @@
       ras.state    = Unknown_State;
       ras.gProfile = NULL;
 
-      if ( Decompose_Curve( RAS_VARS (UShort)start,
-                                     (UShort)ras.outline.contours[i],
-                                     flipped ) )
-        return FAILURE;
+      first = last + 1;
+      last  = ras.outline.contours[i];
 
-      start = (UShort)ras.outline.contours[i] + 1;
+      if ( Decompose_Curve( RAS_VARS first, last, flipped ) )
+        return FAILURE;
 
       /* we must now check whether the extreme arcs join or not */
       if ( FRAC( ras.lastY ) == 0 &&
@@ -3167,9 +3165,12 @@
 
 
   static int
-  ft_black_new( FT_Memory       memory,
-                black_PRaster  *araster )
+  ft_black_new( void*       memory_,    /* FT_Memory     */
+                FT_Raster  *araster_ )  /* black_PRaster */
   {
+    FT_Memory       memory = (FT_Memory)memory_;
+    black_PRaster  *araster = (black_PRaster*)araster_;
+
     FT_Error       error;
     black_PRaster  raster = NULL;
 
@@ -3184,9 +3185,10 @@
 
 
   static void
-  ft_black_done( black_PRaster  raster )
+  ft_black_done( FT_Raster  raster_ )   /* black_PRaster */
   {
-    FT_Memory  memory = (FT_Memory)raster->memory;
+    black_PRaster  raster = (black_PRaster)raster_;
+    FT_Memory      memory = (FT_Memory)raster->memory;
 
 
     FT_FREE( raster );
@@ -3281,11 +3283,11 @@
 
     FT_GLYPH_FORMAT_OUTLINE,
 
-    (FT_Raster_New_Func)     ft_black_new,       /* raster_new      */
-    (FT_Raster_Reset_Func)   ft_black_reset,     /* raster_reset    */
-    (FT_Raster_Set_Mode_Func)ft_black_set_mode,  /* raster_set_mode */
-    (FT_Raster_Render_Func)  ft_black_render,    /* raster_render   */
-    (FT_Raster_Done_Func)    ft_black_done       /* raster_done     */
+    ft_black_new,       /* FT_Raster_New_Func      raster_new      */
+    ft_black_reset,     /* FT_Raster_Reset_Func    raster_reset    */
+    ft_black_set_mode,  /* FT_Raster_Set_Mode_Func raster_set_mode */
+    ft_black_render,    /* FT_Raster_Render_Func   raster_render   */
+    ft_black_done       /* FT_Raster_Done_Func     raster_done     */
   )
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c b/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c
index 0b5d867147847..6d442b1ff8c52 100644
--- a/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c
+++ b/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c
@@ -27,8 +27,11 @@
 
   /* initialize renderer -- init its raster */
   static FT_Error
-  ft_raster1_init( FT_Renderer  render )
+  ft_raster1_init( FT_Module  module )   /* FT_Renderer */
   {
+    FT_Renderer  render = (FT_Renderer)module;
+
+
     render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
 
     return FT_Err_Ok;
@@ -188,18 +191,18 @@
 
       NULL,    /* module specific interface */
 
-      (FT_Module_Constructor)ft_raster1_init,  /* module_init   */
-      (FT_Module_Destructor) NULL,             /* module_done   */
-      (FT_Module_Requester)  NULL,             /* get_interface */
+      ft_raster1_init,  /* FT_Module_Constructor module_init   */
+      NULL,             /* FT_Module_Destructor  module_done   */
+      NULL,             /* FT_Module_Requester   get_interface */
 
     FT_GLYPH_FORMAT_OUTLINE,
 
-    (FT_Renderer_RenderFunc)   ft_raster1_render,     /* render_glyph    */
-    (FT_Renderer_TransformFunc)ft_raster1_transform,  /* transform_glyph */
-    (FT_Renderer_GetCBoxFunc)  ft_raster1_get_cbox,   /* get_glyph_cbox  */
-    (FT_Renderer_SetModeFunc)  ft_raster1_set_mode,   /* set_mode        */
+    ft_raster1_render,     /* FT_Renderer_RenderFunc    render_glyph    */
+    ft_raster1_transform,  /* FT_Renderer_TransformFunc transform_glyph */
+    ft_raster1_get_cbox,   /* FT_Renderer_GetCBoxFunc   get_glyph_cbox  */
+    ft_raster1_set_mode,   /* FT_Renderer_SetModeFunc   set_mode        */
 
-    (FT_Raster_Funcs*)&ft_standard_raster             /* raster_class    */
+    &ft_standard_raster    /* FT_Raster_Funcs*          raster_class    */
   )
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c b/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c
index 423b07b02a574..33712162e00db 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c
@@ -406,10 +406,7 @@
 
     switch ( color_type )
     {
-    default:
-      /* Shouldn't happen, but ... */
-      FALL_THROUGH;
-
+    default:  /* Shouldn't happen, but ... */
     case PNG_COLOR_TYPE_RGB_ALPHA:
       png_set_read_user_transform_fn( png, premultiply_data );
       break;
@@ -457,7 +454,7 @@
 #else /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */
 
   /* ANSI C doesn't like empty source files */
-  typedef int  _pngshim_dummy;
+  typedef int  pngshim_dummy_;
 
 #endif /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c
index 762883db54200..0925940b03f22 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c
@@ -79,41 +79,57 @@
    *
    */
 
-  static void*
-  get_sfnt_table( TT_Face      face,
+  FT_CALLBACK_DEF( FT_Error )
+  sfnt_load_table( FT_Face    face,    /* TT_Face */
+                   FT_ULong   tag,
+                   FT_Long    offset,
+                   FT_Byte*   buffer,
+                   FT_ULong*  length )
+  {
+    TT_Face  ttface = (TT_Face)face;
+
+
+    return tt_face_load_any( ttface, tag, offset, buffer, length );
+  }
+
+
+  FT_CALLBACK_DEF( void* )
+  get_sfnt_table( FT_Face      face,  /* TT_Face */
                   FT_Sfnt_Tag  tag )
   {
+    TT_Face  ttface = (TT_Face)face;
+
     void*  table;
 
 
     switch ( tag )
     {
     case FT_SFNT_HEAD:
-      table = &face->header;
+      table = &ttface->header;
       break;
 
     case FT_SFNT_HHEA:
-      table = &face->horizontal;
+      table = &ttface->horizontal;
       break;
 
     case FT_SFNT_VHEA:
-      table = face->vertical_info ? &face->vertical : NULL;
+      table = ttface->vertical_info ? &ttface->vertical : NULL;
       break;
 
     case FT_SFNT_OS2:
-      table = ( face->os2.version == 0xFFFFU ) ? NULL : &face->os2;
+      table = ( ttface->os2.version == 0xFFFFU ) ? NULL : &ttface->os2;
       break;
 
     case FT_SFNT_POST:
-      table = &face->postscript;
+      table = &ttface->postscript;
       break;
 
     case FT_SFNT_MAXP:
-      table = &face->max_profile;
+      table = &ttface->max_profile;
       break;
 
     case FT_SFNT_PCLT:
-      table = face->pclt.Version ? &face->pclt : NULL;
+      table = ttface->pclt.Version ? &ttface->pclt : NULL;
       break;
 
     default:
@@ -124,26 +140,29 @@
   }
 
 
-  static FT_Error
-  sfnt_table_info( TT_Face    face,
+  FT_CALLBACK_DEF( FT_Error )
+  sfnt_table_info( FT_Face    face,    /* TT_Face */
                    FT_UInt    idx,
                    FT_ULong  *tag,
                    FT_ULong  *offset,
                    FT_ULong  *length )
   {
+    TT_Face  ttface = (TT_Face)face;
+
+
     if ( !offset || !length )
       return FT_THROW( Invalid_Argument );
 
     if ( !tag )
-      *length = face->num_tables;
+      *length = ttface->num_tables;
     else
     {
-      if ( idx >= face->num_tables )
+      if ( idx >= ttface->num_tables )
         return FT_THROW( Table_Missing );
 
-      *tag    = face->dir_tables[idx].Tag;
-      *offset = face->dir_tables[idx].Offset;
-      *length = face->dir_tables[idx].Length;
+      *tag    = ttface->dir_tables[idx].Tag;
+      *offset = ttface->dir_tables[idx].Offset;
+      *length = ttface->dir_tables[idx].Length;
     }
 
     return FT_Err_Ok;
@@ -153,9 +172,9 @@
   FT_DEFINE_SERVICE_SFNT_TABLEREC(
     sfnt_service_sfnt_table,
 
-    (FT_SFNT_TableLoadFunc)tt_face_load_any,     /* load_table */
-    (FT_SFNT_TableGetFunc) get_sfnt_table,       /* get_table  */
-    (FT_SFNT_TableInfoFunc)sfnt_table_info       /* table_info */
+    sfnt_load_table,  /* FT_SFNT_TableLoadFunc load_table */
+    get_sfnt_table,   /* FT_SFNT_TableGetFunc  get_table  */
+    sfnt_table_info   /* FT_SFNT_TableInfoFunc table_info */
   )
 
 
@@ -166,7 +185,7 @@
    *
    */
 
-  static FT_Error
+  FT_CALLBACK_DEF( FT_Error )
   sfnt_get_glyph_name( FT_Face     face,
                        FT_UInt     glyph_index,
                        FT_Pointer  buffer,
@@ -184,7 +203,7 @@
   }
 
 
-  static FT_UInt
+  FT_CALLBACK_DEF( FT_UInt )
   sfnt_get_name_index( FT_Face           face,
                        const FT_String*  glyph_name )
   {
@@ -221,8 +240,8 @@
   FT_DEFINE_SERVICE_GLYPHDICTREC(
     sfnt_service_glyph_dict,
 
-    (FT_GlyphDict_GetNameFunc)  sfnt_get_glyph_name,    /* get_name   */
-    (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index     /* name_index */
+    sfnt_get_glyph_name,  /* FT_GlyphDict_GetNameFunc   get_name   */
+    sfnt_get_name_index   /* FT_GlyphDict_NameIndexFunc name_index */
   )
 
 #endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
@@ -523,15 +542,14 @@
           FT_TRACE0(( "get_win_string:"
                       " Character 0x%X invalid in PS name string\n",
                       ((unsigned)p[0])*256 + (unsigned)p[1] ));
-        break;
+        continue;
       }
     }
-    if ( !len )
-      *r = '\0';
+    *r = '\0';
 
     FT_FRAME_EXIT();
 
-    if ( !len )
+    if ( r != result )
       return result;
 
   get_win_string_error:
@@ -580,15 +598,14 @@
           FT_TRACE0(( "get_apple_string:"
                       " Character `%c' (0x%X) invalid in PS name string\n",
                       *p, *p ));
-        break;
+        continue;
       }
     }
-    if ( !len )
-      *r = '\0';
+    *r = '\0';
 
     FT_FRAME_EXIT();
 
-    if ( !len )
+    if ( r != result )
       return result;
 
   get_apple_string_error:
@@ -602,7 +619,7 @@
   }
 
 
-  static FT_Bool
+  FT_CALLBACK_DEF( FT_Bool )
   sfnt_get_name_id( TT_Face    face,
                     FT_UShort  id,
                     FT_Int    *win,
@@ -819,9 +836,9 @@
 
       if ( !found )
       {
-        /* as a last resort we try the family name; note that this is */
-        /* not in the Adobe TechNote, but GX fonts (which predate the */
-        /* TechNote) benefit from this behaviour                      */
+        /* according to the 'name' documentation in the OpenType   */
+        /* specification the font family name is to be used if the */
+        /* typographic family name is missing, so let's do that    */
         found = sfnt_get_name_id( face,
                                   TT_NAME_ID_FONT_FAMILY,
                                   &win,
@@ -853,6 +870,10 @@
       {
         FT_TRACE0(( "sfnt_get_var_ps_name:"
                     " No valid PS name prefix for font instances found\n" ));
+        /* XXX It probably makes sense to never let this fail */
+        /*     since an arbitrary prefix should work, too.    */
+        /*     On the other hand, it is very unlikely that    */
+        /*     we ever reach this code at all.                */
         return NULL;
       }
 
@@ -1041,47 +1062,49 @@
 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
 
 
-  static const char*
-  sfnt_get_ps_name( TT_Face  face )
+  FT_CALLBACK_DEF( const char* )
+  sfnt_get_ps_name( FT_Face  face )    /* TT_Face */
   {
+    TT_Face  ttface = (TT_Face)face;
+
     FT_Int       found, win, apple;
     const char*  result = NULL;
 
 
-    if ( face->postscript_name )
-      return face->postscript_name;
+    if ( ttface->postscript_name )
+      return ttface->postscript_name;
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-    if ( face->blend                                 &&
-         ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ||
-           FT_IS_VARIATION( FT_FACE( face ) )      ) )
+    if ( ttface->blend                    &&
+         ( FT_IS_NAMED_INSTANCE( face ) ||
+           FT_IS_VARIATION( face )      ) )
     {
-      face->postscript_name = sfnt_get_var_ps_name( face );
-      return face->postscript_name;
+      ttface->postscript_name = sfnt_get_var_ps_name( ttface );
+      return ttface->postscript_name;
     }
 #endif
 
     /* scan the name table to see whether we have a Postscript name here, */
     /* either in Macintosh or Windows platform encodings                  */
-    found = sfnt_get_name_id( face, TT_NAME_ID_PS_NAME, &win, &apple );
+    found = sfnt_get_name_id( ttface, TT_NAME_ID_PS_NAME, &win, &apple );
     if ( !found )
       return NULL;
 
     /* prefer Windows entries over Apple */
     if ( win != -1 )
-      result = get_win_string( face->root.memory,
-                               face->name_table.stream,
-                               face->name_table.names + win,
+      result = get_win_string( FT_FACE_MEMORY( face ),
+                               ttface->name_table.stream,
+                               ttface->name_table.names + win,
                                sfnt_is_postscript,
                                1 );
     if ( !result && apple != -1 )
-      result = get_apple_string( face->root.memory,
-                                 face->name_table.stream,
-                                 face->name_table.names + apple,
+      result = get_apple_string( FT_FACE_MEMORY( face ),
+                                 ttface->name_table.stream,
+                                 ttface->name_table.names + apple,
                                  sfnt_is_postscript,
                                  1 );
 
-    face->postscript_name = result;
+    ttface->postscript_name = result;
 
     return result;
   }
@@ -1090,7 +1113,7 @@
   FT_DEFINE_SERVICE_PSFONTNAMEREC(
     sfnt_service_ps_name,
 
-    (FT_PsName_GetFunc)sfnt_get_ps_name       /* get_ps_font_name */
+    sfnt_get_ps_name  /* FT_PsName_GetFunc get_ps_font_name */
   )
 
 
@@ -1100,14 +1123,14 @@
   FT_DEFINE_SERVICE_TTCMAPSREC(
     tt_service_get_cmap_info,
 
-    (TT_CMap_Info_GetFunc)tt_get_cmap_info    /* get_cmap_info */
+    tt_get_cmap_info  /* TT_CMap_Info_GetFunc get_cmap_info */
   )
 
 
 #ifdef TT_CONFIG_OPTION_BDF
 
   static FT_Error
-  sfnt_get_charset_id( TT_Face       face,
+  sfnt_get_charset_id( FT_Face       face,
                        const char*  *acharset_encoding,
                        const char*  *acharset_registry )
   {
@@ -1145,8 +1168,8 @@
   FT_DEFINE_SERVICE_BDFRec(
     sfnt_service_bdf,
 
-    (FT_BDF_GetCharsetIdFunc)sfnt_get_charset_id,     /* get_charset_id */
-    (FT_BDF_GetPropertyFunc) tt_face_find_bdf_prop    /* get_property   */
+    sfnt_get_charset_id,   /* FT_BDF_GetCharsetIdFunc get_charset_id */
+    tt_face_find_bdf_prop  /* FT_BDF_GetPropertyFunc  get_property   */
   )
 
 
@@ -1337,9 +1360,9 @@
 
     (const void*)&sfnt_interface,  /* module specific interface */
 
-    (FT_Module_Constructor)NULL,               /* module_init   */
-    (FT_Module_Destructor) NULL,               /* module_done   */
-    (FT_Module_Requester)  sfnt_get_interface  /* get_interface */
+    NULL,               /* FT_Module_Constructor module_init   */
+    NULL,               /* FT_Module_Destructor  module_done   */
+    sfnt_get_interface  /* FT_Module_Requester   get_interface */
   )
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c
index e018934ccaa1b..f5d66ef8403a1 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c
@@ -534,17 +534,23 @@
                                         0 );
     }
 
-    if ( !face->var )
+    if ( !face->tt_var )
     {
       /* we want the metrics variations interface */
       /* from the `truetype' module only          */
       FT_Module  tt_module = FT_Get_Module( library, "truetype" );
 
 
-      face->var = ft_module_get_service( tt_module,
-                                         FT_SERVICE_ID_METRICS_VARIATIONS,
-                                         0 );
+      face->tt_var = ft_module_get_service( tt_module,
+                                            FT_SERVICE_ID_METRICS_VARIATIONS,
+                                            0 );
     }
+
+    if ( !face->face_var )
+      face->face_var = ft_module_get_service(
+                         &face->root.driver->root,
+                         FT_SERVICE_ID_METRICS_VARIATIONS,
+                         0 );
 #endif
 
     FT_TRACE2(( "SFNT driver\n" ));
@@ -692,6 +698,9 @@
           instance_offset += instance_size;
         }
 
+        /* named instance indices start with value 1 */
+        face->var_default_named_instance = i + 1;
+
         if ( i == num_instances )
         {
           /* no default instance in named instance table; */
@@ -1054,6 +1063,16 @@
         GET_NAME( FONT_SUBFAMILY, &face->root.style_name );
     }
 
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+    {
+      FT_Memory  memory = face->root.memory;
+
+
+      if ( FT_STRDUP( face->non_var_style_name, face->root.style_name ) )
+        goto Exit;
+    }
+#endif
+
     /* now set up root fields */
     {
       FT_Face  root  = &face->root;
@@ -1221,7 +1240,7 @@
 
         if ( count > 0 )
         {
-          FT_Memory        memory   = face->root.stream->memory;
+          FT_Memory        memory   = face->root.memory;
           FT_UShort        em_size  = face->header.Units_Per_EM;
           FT_Short         avgwidth = face->os2.xAvgCharWidth;
           FT_Size_Metrics  metrics;
@@ -1500,6 +1519,7 @@
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
     FT_FREE( face->var_postscript_prefix );
+    FT_FREE( face->non_var_style_name );
 #endif
 
     /* freeing glyph color palette data */
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c
index 9559bf3421431..7c0ce2205e67b 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c
@@ -426,7 +426,7 @@
 #else /* !FT_CONFIG_OPTION_USE_ZLIB */
 
   /* ANSI C doesn't like empty source files */
-  typedef int  _sfwoff_dummy;
+  typedef int  sfwoff_dummy_;
 
 #endif /* !FT_CONFIG_OPTION_USE_ZLIB */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c
index 7a01977f8667c..2be44a347ad95 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c
@@ -36,6 +36,8 @@
 #undef  FT_COMPONENT
 #define FT_COMPONENT  sfwoff2
 
+  /* An arbitrary, heuristic size limit (67MByte) for expanded WOFF2 data. */
+#define MAX_SFNT_SIZE  ( 1 << 26 )
 
 #define READ_255USHORT( var )  FT_SET_ERROR( Read255UShort( stream, &var ) )
 
@@ -2180,9 +2182,8 @@
       else
         sfnt_size = woff2.totalSfntSize;
 
-      /* Value 1<<26 = 67108864 is heuristic. */
-      if (sfnt_size >= (1 << 26))
-        sfnt_size = 1 << 26;
+      if ( sfnt_size >= MAX_SFNT_SIZE )
+        sfnt_size = MAX_SFNT_SIZE;
 
 #ifdef FT_DEBUG_LEVEL_TRACE
       if ( sfnt_size != woff2.totalSfntSize )
@@ -2257,10 +2258,15 @@
       goto Exit;
     }
 
-    if ( woff2.uncompressed_size > sfnt_size )
+    /* We must not blindly trust `uncompressed_size` since its   */
+    /* value might be corrupted.  If it is too large, reject the */
+    /* font.  In other words, we don't accept a WOFF2 font that  */
+    /* expands to something larger than MAX_SFNT_SIZE.  If ever  */
+    /* necessary, this limit can be easily adjusted.             */
+    if ( woff2.uncompressed_size > MAX_SFNT_SIZE )
     {
-      FT_ERROR(( "woff2_open_font: SFNT table lengths are too large.\n" ));
-      error = FT_THROW( Invalid_Table );
+      FT_ERROR(( "Uncompressed font too large.\n" ));
+      error = FT_THROW( Array_Too_Large );
       goto Exit;
     }
 
@@ -2378,7 +2384,7 @@
 #else /* !FT_CONFIG_OPTION_USE_BROTLI */
 
   /* ANSI C doesn't like empty source files */
-  typedef int  _sfwoff2_dummy;
+  typedef int  sfwoff2_dummy_;
 
 #endif /* !FT_CONFIG_OPTION_USE_BROTLI */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c
index 820cd08e6d51a..9ba25dcbc1385 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c
@@ -59,10 +59,14 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap_init( TT_CMap   cmap,
-                FT_Byte*  table )
+  tt_cmap_init( FT_CMap  cmap,    /* TT_CMap */
+                void*    table_ )
   {
-    cmap->data = table;
+    TT_CMap   ttcmap = (TT_CMap)cmap;
+    FT_Byte*  table  = (FT_Byte*)table_;
+
+
+    ttcmap->data = table;
     return FT_Err_Ok;
   }
 
@@ -128,21 +132,23 @@
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  tt_cmap0_char_index( TT_CMap    cmap,
+  tt_cmap0_char_index( FT_CMap    cmap,       /* TT_CMap */
                        FT_UInt32  char_code )
   {
-    FT_Byte*  table = cmap->data;
+    TT_CMap   ttcmap = (TT_CMap)cmap;
+    FT_Byte*  table  = ttcmap->data;
 
 
     return char_code < 256 ? table[6 + char_code] : 0;
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  tt_cmap0_char_next( TT_CMap     cmap,
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap0_char_next( FT_CMap     cmap,        /* TT_CMap */
                       FT_UInt32  *pchar_code )
   {
-    FT_Byte*   table    = cmap->data;
+    TT_CMap    ttcmap   = (TT_CMap)cmap;
+    FT_Byte*   table    = ttcmap->data;
     FT_UInt32  charcode = *pchar_code;
     FT_UInt32  result   = 0;
     FT_UInt    gindex   = 0;
@@ -165,10 +171,11 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap0_get_info( TT_CMap       cmap,
+  tt_cmap0_get_info( FT_CharMap    cmap,       /* TT_CMap */
                      TT_CMapInfo  *cmap_info )
   {
-    FT_Byte*  p = cmap->data + 4;
+    TT_CMap   ttcmap = (TT_CMap)cmap;
+    FT_Byte*  p      = ttcmap->data + 4;
 
 
     cmap_info->format   = 0;
@@ -453,10 +460,11 @@
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  tt_cmap2_char_index( TT_CMap    cmap,
+  tt_cmap2_char_index( FT_CMap    cmap,       /* TT_CMap */
                        FT_UInt32  char_code )
   {
-    FT_Byte*  table   = cmap->data;
+    TT_CMap   ttcmap  = (TT_CMap)cmap;
+    FT_Byte*  table   = ttcmap->data;
     FT_UInt   result  = 0;
     FT_Byte*  subheader;
 
@@ -491,11 +499,12 @@
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  tt_cmap2_char_next( TT_CMap     cmap,
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap2_char_next( FT_CMap     cmap,       /* TT_CMap */
                       FT_UInt32  *pcharcode )
   {
-    FT_Byte*   table    = cmap->data;
+    TT_CMap    ttcmap   = (TT_CMap)cmap;
+    FT_Byte*   table    = ttcmap->data;
     FT_UInt    gindex   = 0;
     FT_UInt32  result   = 0;
     FT_UInt32  charcode = *pcharcode + 1;
@@ -579,10 +588,11 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap2_get_info( TT_CMap       cmap,
+  tt_cmap2_get_info( FT_CharMap    cmap,       /* TT_CMap */
                      TT_CMapInfo  *cmap_info )
   {
-    FT_Byte*  p = cmap->data + 4;
+    TT_CMap   ttcmap = (TT_CMap)cmap;
+    FT_Byte*  p      = ttcmap->data + 4;
 
 
     cmap_info->format   = 2;
@@ -706,18 +716,20 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap4_init( TT_CMap4  cmap,
-                 FT_Byte*  table )
+  tt_cmap4_init( FT_CMap  cmap,    /* TT_CMap4 */
+                 void*    table_ )
   {
+    TT_CMap4  ttcmap = (TT_CMap4)cmap;
+    FT_Byte*  table  = (FT_Byte*)table_;
     FT_Byte*  p;
 
 
-    cmap->cmap.data    = table;
+    ttcmap->cmap.data = table;
 
-    p                  = table + 6;
-    cmap->num_ranges   = FT_PEEK_USHORT( p ) >> 1;
-    cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL;
-    cmap->cur_gindex   = 0;
+    p                    = table + 6;
+    ttcmap->num_ranges   = FT_PEEK_USHORT( p ) >> 1;
+    ttcmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL;
+    ttcmap->cur_gindex   = 0;
 
     return FT_Err_Ok;
   }
@@ -755,7 +767,7 @@
            cmap->cur_start == 0xFFFFU        &&
            cmap->cur_end   == 0xFFFFU        )
       {
-        TT_Face   face  = (TT_Face)cmap->cmap.cmap.charmap.face;
+        TT_Face   face  = (TT_Face)FT_CMAP_FACE( cmap );
         FT_Byte*  limit = face->cmap_table + face->cmap_size;
 
 
@@ -788,15 +800,12 @@
   static void
   tt_cmap4_next( TT_CMap4  cmap )
   {
-    TT_Face   face  = (TT_Face)cmap->cmap.cmap.charmap.face;
+    TT_Face   face  = (TT_Face)FT_CMAP_FACE( cmap );
     FT_Byte*  limit = face->cmap_table + face->cmap_size;
 
     FT_UInt  charcode;
 
 
-    if ( cmap->cur_charcode >= 0xFFFFUL )
-      goto Fail;
-
     charcode = (FT_UInt)cmap->cur_charcode + 1;
 
     if ( charcode < cmap->cur_start )
@@ -882,7 +891,6 @@
         charcode = cmap->cur_start;
     }
 
-  Fail:
     cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL;
     cmap->cur_gindex   = 0;
   }
@@ -1097,32 +1105,26 @@
                             FT_UInt32*  pcharcode,
                             FT_Bool     next )
   {
-    TT_Face   face  = (TT_Face)cmap->cmap.charmap.face;
+    TT_Face   face  = (TT_Face)FT_CMAP_FACE( cmap );
     FT_Byte*  limit = face->cmap_table + face->cmap_size;
 
 
     FT_UInt    num_segs2, start, end, offset;
     FT_Int     delta;
     FT_UInt    i, num_segs;
-    FT_UInt32  charcode = *pcharcode;
+    FT_UInt32  charcode = *pcharcode + next;
     FT_UInt    gindex   = 0;
     FT_Byte*   p;
     FT_Byte*   q;
 
 
     p = cmap->data + 6;
-    num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
-
-    num_segs = num_segs2 >> 1;
+    num_segs = TT_PEEK_USHORT( p ) >> 1;
 
     if ( !num_segs )
       return 0;
 
-    if ( next )
-      charcode++;
-
-    if ( charcode > 0xFFFFU )
-      return 0;
+    num_segs2 = num_segs << 1;
 
     /* linear search */
     p = cmap->data + 14;               /* ends table   */
@@ -1232,37 +1234,30 @@
                             FT_UInt32*  pcharcode,
                             FT_Bool     next )
   {
-    TT_Face   face  = (TT_Face)cmap->cmap.charmap.face;
+    TT_Face   face  = (TT_Face)FT_CMAP_FACE( cmap );
     FT_Byte*  limit = face->cmap_table + face->cmap_size;
 
     FT_UInt   num_segs2, start, end, offset;
     FT_Int    delta;
     FT_UInt   max, min, mid, num_segs;
-    FT_UInt   charcode = (FT_UInt)*pcharcode;
+    FT_UInt   charcode = (FT_UInt)*pcharcode + next;
     FT_UInt   gindex   = 0;
     FT_Byte*  p;
 
 
     p = cmap->data + 6;
-    num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
+    num_segs = TT_PEEK_USHORT( p ) >> 1;
 
-    if ( !num_segs2 )
+    if ( !num_segs )
       return 0;
 
-    num_segs = num_segs2 >> 1;
-
-    /* make compiler happy */
-    mid = num_segs;
-    end = 0xFFFFU;
-
-    if ( next )
-      charcode++;
+    num_segs2 = num_segs << 1;
 
     min = 0;
     max = num_segs;
 
     /* binary search */
-    while ( min < max )
+    do
     {
       mid    = ( min + max ) >> 1;
       p      = cmap->data + 14 + mid * 2;
@@ -1445,6 +1440,7 @@
         break;
       }
     }
+    while ( min < max );
 
     if ( next )
     {
@@ -1454,12 +1450,8 @@
       /* if `charcode' is not in any segment, then `mid' is */
       /* the segment nearest to `charcode'                  */
 
-      if ( charcode > end )
-      {
-        mid++;
-        if ( mid == num_segs )
-          return 0;
-      }
+      if ( charcode > end && ++mid == num_segs )
+        return 0;
 
       if ( tt_cmap4_set_range( cmap4, mid ) )
       {
@@ -1474,7 +1466,6 @@
           cmap4->cur_gindex = gindex;
         else
         {
-          cmap4->cur_charcode = charcode;
           tt_cmap4_next( cmap4 );
           gindex = cmap4->cur_gindex;
         }
@@ -1489,31 +1480,35 @@
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  tt_cmap4_char_index( TT_CMap    cmap,
+  tt_cmap4_char_index( FT_CMap    cmap,       /* TT_CMap */
                        FT_UInt32  char_code )
   {
+    TT_CMap  ttcmap = (TT_CMap)cmap;
+
+
     if ( char_code >= 0x10000UL )
       return 0;
 
-    if ( cmap->flags & TT_CMAP_FLAG_UNSORTED )
-      return tt_cmap4_char_map_linear( cmap, &char_code, 0 );
+    if ( ttcmap->flags & TT_CMAP_FLAG_UNSORTED )
+      return tt_cmap4_char_map_linear( ttcmap, &char_code, 0 );
     else
-      return tt_cmap4_char_map_binary( cmap, &char_code, 0 );
+      return tt_cmap4_char_map_binary( ttcmap, &char_code, 0 );
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  tt_cmap4_char_next( TT_CMap     cmap,
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap4_char_next( FT_CMap     cmap,        /* TT_CMap */
                       FT_UInt32  *pchar_code )
   {
+    TT_CMap  ttcmap = (TT_CMap)cmap;
     FT_UInt  gindex;
 
 
     if ( *pchar_code >= 0xFFFFU )
       return 0;
 
-    if ( cmap->flags & TT_CMAP_FLAG_UNSORTED )
-      gindex = tt_cmap4_char_map_linear( cmap, pchar_code, 1 );
+    if ( ttcmap->flags & TT_CMAP_FLAG_UNSORTED )
+      gindex = tt_cmap4_char_map_linear( ttcmap, pchar_code, 1 );
     else
     {
       TT_CMap4  cmap4 = (TT_CMap4)cmap;
@@ -1528,7 +1523,7 @@
           *pchar_code = cmap4->cur_charcode;
       }
       else
-        gindex = tt_cmap4_char_map_binary( cmap, pchar_code, 1 );
+        gindex = tt_cmap4_char_map_binary( ttcmap, pchar_code, 1 );
     }
 
     return gindex;
@@ -1536,10 +1531,11 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap4_get_info( TT_CMap       cmap,
+  tt_cmap4_get_info( FT_CharMap    cmap,       /* TT_CMap */
                      TT_CMapInfo  *cmap_info )
   {
-    FT_Byte*  p = cmap->data + 4;
+    TT_CMap   ttcmap = (TT_CMap)cmap;
+    FT_Byte*  p      = ttcmap->data + 4;
 
 
     cmap_info->format   = 4;
@@ -1640,10 +1636,11 @@
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  tt_cmap6_char_index( TT_CMap    cmap,
+  tt_cmap6_char_index( FT_CMap    cmap,       /* TT_CMap */
                        FT_UInt32  char_code )
   {
-    FT_Byte*  table  = cmap->data;
+    TT_CMap   ttcmap = (TT_CMap)cmap;
+    FT_Byte*  table  = ttcmap->data;
     FT_UInt   result = 0;
     FT_Byte*  p      = table + 6;
     FT_UInt   start  = TT_NEXT_USHORT( p );
@@ -1661,11 +1658,12 @@
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  tt_cmap6_char_next( TT_CMap     cmap,
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap6_char_next( FT_CMap     cmap,        /* TT_CMap */
                       FT_UInt32  *pchar_code )
   {
-    FT_Byte*   table     = cmap->data;
+    TT_CMap    ttcmap    = (TT_CMap)cmap;
+    FT_Byte*   table     = ttcmap->data;
     FT_UInt32  result    = 0;
     FT_UInt32  char_code = *pchar_code + 1;
     FT_UInt    gindex    = 0;
@@ -1706,10 +1704,11 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap6_get_info( TT_CMap       cmap,
+  tt_cmap6_get_info( FT_CharMap    cmap,       /* TT_CMap */
                      TT_CMapInfo  *cmap_info )
   {
-    FT_Byte*  p = cmap->data + 4;
+    TT_CMap   ttcmap = (TT_CMap)cmap;
+    FT_Byte*  p      = ttcmap->data + 4;
 
 
     cmap_info->format   = 6;
@@ -1900,10 +1899,11 @@
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  tt_cmap8_char_index( TT_CMap    cmap,
+  tt_cmap8_char_index( FT_CMap    cmap,       /* TT_CMap */
                        FT_UInt32  char_code )
   {
-    FT_Byte*   table      = cmap->data;
+    TT_CMap    ttcmap     = (TT_CMap)cmap;
+    FT_Byte*   table      = ttcmap->data;
     FT_UInt    result     = 0;
     FT_Byte*   p          = table + 8204;
     FT_UInt32  num_groups = TT_NEXT_ULONG( p );
@@ -1932,15 +1932,16 @@
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  tt_cmap8_char_next( TT_CMap     cmap,
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap8_char_next( FT_CMap     cmap,        /* TT_CMap */
                       FT_UInt32  *pchar_code )
   {
-    FT_Face    face       = cmap->cmap.charmap.face;
+    TT_CMap    ttcmap     = (TT_CMap)cmap;
+    FT_Face    face       = FT_CMAP_FACE( cmap );
     FT_UInt32  result     = 0;
     FT_UInt32  char_code;
     FT_UInt    gindex     = 0;
-    FT_Byte*   table      = cmap->data;
+    FT_Byte*   table      = ttcmap->data;
     FT_Byte*   p          = table + 8204;
     FT_UInt32  num_groups = TT_NEXT_ULONG( p );
     FT_UInt32  start, end, start_id;
@@ -2000,10 +2001,11 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap8_get_info( TT_CMap       cmap,
+  tt_cmap8_get_info( FT_CharMap    cmap,       /* TT_CMap */
                      TT_CMapInfo  *cmap_info )
   {
-    FT_Byte*  p = cmap->data + 8;
+    TT_CMap   ttcmap = (TT_CMap)cmap;
+    FT_Byte*  p      = ttcmap->data + 8;
 
 
     cmap_info->format   = 8;
@@ -2104,10 +2106,11 @@
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  tt_cmap10_char_index( TT_CMap    cmap,
+  tt_cmap10_char_index( FT_CMap    cmap,       /* TT_CMap */
                         FT_UInt32  char_code )
   {
-    FT_Byte*   table  = cmap->data;
+    TT_CMap    ttcmap = (TT_CMap)cmap;
+    FT_Byte*   table  = ttcmap->data;
     FT_UInt    result = 0;
     FT_Byte*   p      = table + 12;
     FT_UInt32  start  = TT_NEXT_ULONG( p );
@@ -2130,11 +2133,12 @@
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  tt_cmap10_char_next( TT_CMap     cmap,
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap10_char_next( FT_CMap     cmap,        /* TT_CMap */
                        FT_UInt32  *pchar_code )
   {
-    FT_Byte*   table     = cmap->data;
+    TT_CMap    ttcmap    = (TT_CMap)cmap;
+    FT_Byte*   table     = ttcmap->data;
     FT_UInt32  char_code;
     FT_UInt    gindex    = 0;
     FT_Byte*   p         = table + 12;
@@ -2172,10 +2176,11 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap10_get_info( TT_CMap       cmap,
+  tt_cmap10_get_info( FT_CharMap    cmap,       /* TT_CMap */
                       TT_CMapInfo  *cmap_info )
   {
-    FT_Byte*  p = cmap->data + 8;
+    TT_CMap   ttcmap = (TT_CMap)cmap;
+    FT_Byte*  p      = ttcmap->data + 8;
 
 
     cmap_info->format   = 10;
@@ -2253,15 +2258,19 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap12_init( TT_CMap12  cmap,
-                  FT_Byte*   table )
+  tt_cmap12_init( FT_CMap  cmap,    /* TT_CMap12 */
+                  void*    table_ )
   {
-    cmap->cmap.data  = table;
+    TT_CMap12  ttcmap = (TT_CMap12)cmap;
+    FT_Byte*   table  = (FT_Byte*)table_;
+
 
-    table           += 12;
-    cmap->num_groups = FT_PEEK_ULONG( table );
+    ttcmap->cmap.data  = table;
 
-    cmap->valid      = 0;
+    table             += 12;
+    ttcmap->num_groups = FT_PEEK_ULONG( table );
+
+    ttcmap->valid      = 0;
 
     return FT_Err_Ok;
   }
@@ -2331,23 +2340,21 @@
   /* cmap->cur_group should be set up properly by caller         */
   /*                                                             */
   static void
-  tt_cmap12_next( TT_CMap12  cmap )
+  tt_cmap12_next( FT_CMap  cmap )    /* TT_CMap12 */
   {
-    FT_Face   face = cmap->cmap.cmap.charmap.face;
-    FT_Byte*  p;
-    FT_ULong  start, end, start_id, char_code;
-    FT_ULong  n;
-    FT_UInt   gindex;
-
+    TT_CMap12  ttcmap = (TT_CMap12)cmap;
+    FT_Face    face   = FT_CMAP_FACE( cmap );
+    FT_Byte*   p;
+    FT_ULong   start, end, start_id, char_code;
+    FT_ULong   n;
+    FT_UInt    gindex;
 
-    if ( cmap->cur_charcode >= 0xFFFFFFFFUL )
-      goto Fail;
 
-    char_code = cmap->cur_charcode + 1;
+    char_code = ttcmap->cur_charcode + 1;
 
-    for ( n = cmap->cur_group; n < cmap->num_groups; n++ )
+    for ( n = ttcmap->cur_group; n < ttcmap->num_groups; n++ )
     {
-      p        = cmap->cmap.data + 16 + 12 * n;
+      p        = ttcmap->cmap.data + 16 + 12 * n;
       start    = TT_NEXT_ULONG( p );
       end      = TT_NEXT_ULONG( p );
       start_id = TT_PEEK_ULONG( p );
@@ -2379,16 +2386,16 @@
         if ( gindex >= (FT_UInt)face->num_glyphs )
           continue;
 
-        cmap->cur_charcode = char_code;
-        cmap->cur_gindex   = gindex;
-        cmap->cur_group    = n;
+        ttcmap->cur_charcode = char_code;
+        ttcmap->cur_gindex   = gindex;
+        ttcmap->cur_group    = n;
 
         return;
       }
     }
 
   Fail:
-    cmap->valid = 0;
+    ttcmap->valid = 0;
   }
 
 
@@ -2400,7 +2407,7 @@
     FT_UInt    gindex     = 0;
     FT_Byte*   p          = cmap->data + 12;
     FT_UInt32  num_groups = TT_PEEK_ULONG( p );
-    FT_UInt32  char_code  = *pchar_code;
+    FT_UInt32  char_code  = *pchar_code + next;
     FT_UInt32  start, end, start_id;
     FT_UInt32  max, min, mid;
 
@@ -2408,23 +2415,11 @@
     if ( !num_groups )
       return 0;
 
-    /* make compiler happy */
-    mid = num_groups;
-    end = 0xFFFFFFFFUL;
-
-    if ( next )
-    {
-      if ( char_code >= 0xFFFFFFFFUL )
-        return 0;
-
-      char_code++;
-    }
-
     min = 0;
     max = num_groups;
 
     /* binary search */
-    while ( min < max )
+    do
     {
       mid = ( min + max ) >> 1;
       p   = cmap->data + 16 + 12 * mid;
@@ -2448,22 +2443,19 @@
         break;
       }
     }
+    while ( min < max );
 
     if ( next )
     {
-      FT_Face    face   = cmap->cmap.charmap.face;
+      FT_Face    face   = FT_CMAP_FACE( cmap );
       TT_CMap12  cmap12 = (TT_CMap12)cmap;
 
 
       /* if `char_code' is not in any group, then `mid' is */
       /* the group nearest to `char_code'                  */
 
-      if ( char_code > end )
-      {
-        mid++;
-        if ( mid == num_groups )
-          return 0;
-      }
+      if ( char_code > end && ++mid == num_groups )
+        return 0;
 
       cmap12->valid        = 1;
       cmap12->cur_charcode = char_code;
@@ -2474,7 +2466,7 @@
 
       if ( !gindex )
       {
-        tt_cmap12_next( cmap12 );
+        tt_cmap12_next( FT_CMAP( cmap12 ) );
 
         if ( cmap12->valid )
           gindex = cmap12->cur_gindex;
@@ -2490,25 +2482,28 @@
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  tt_cmap12_char_index( TT_CMap    cmap,
+  tt_cmap12_char_index( FT_CMap    cmap,       /* TT_CMap */
                         FT_UInt32  char_code )
   {
-    return tt_cmap12_char_map_binary( cmap, &char_code, 0 );
+    return tt_cmap12_char_map_binary( (TT_CMap)cmap, &char_code, 0 );
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  tt_cmap12_char_next( TT_CMap     cmap,
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap12_char_next( FT_CMap     cmap,        /* TT_CMap12 */
                        FT_UInt32  *pchar_code )
   {
     TT_CMap12  cmap12 = (TT_CMap12)cmap;
     FT_UInt    gindex;
 
 
+    if ( *pchar_code >= 0xFFFFFFFFUL )
+      return 0;
+
     /* no need to search */
     if ( cmap12->valid && cmap12->cur_charcode == *pchar_code )
     {
-      tt_cmap12_next( cmap12 );
+      tt_cmap12_next( FT_CMAP( cmap12 ) );
       if ( cmap12->valid )
       {
         gindex      = cmap12->cur_gindex;
@@ -2518,17 +2513,18 @@
         gindex = 0;
     }
     else
-      gindex = tt_cmap12_char_map_binary( cmap, pchar_code, 1 );
+      gindex = tt_cmap12_char_map_binary( (TT_CMap)cmap, pchar_code, 1 );
 
     return gindex;
   }
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap12_get_info( TT_CMap       cmap,
+  tt_cmap12_get_info( FT_CharMap    cmap,       /* TT_CMap */
                       TT_CMapInfo  *cmap_info )
   {
-    FT_Byte*  p = cmap->data + 8;
+    TT_CMap   ttcmap = (TT_CMap)cmap;
+    FT_Byte*  p      = ttcmap->data + 8;
 
 
     cmap_info->format   = 12;
@@ -2606,15 +2602,19 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap13_init( TT_CMap13  cmap,
-                  FT_Byte*   table )
+  tt_cmap13_init( FT_CMap  cmap,    /* TT_CMap13 */
+                  void*    table_ )
   {
-    cmap->cmap.data  = table;
+    TT_CMap13  ttcmap = (TT_CMap13)cmap;
+    FT_Byte*   table  = (FT_Byte*)table_;
+
+
+    ttcmap->cmap.data  = table;
 
-    table           += 12;
-    cmap->num_groups = FT_PEEK_ULONG( table );
+    table             += 12;
+    ttcmap->num_groups = FT_PEEK_ULONG( table );
 
-    cmap->valid      = 0;
+    ttcmap->valid      = 0;
 
     return FT_Err_Ok;
   }
@@ -2679,23 +2679,21 @@
   /* cmap->cur_group should be set up properly by caller         */
   /*                                                             */
   static void
-  tt_cmap13_next( TT_CMap13  cmap )
+  tt_cmap13_next( FT_CMap  cmap )    /* TT_CMap13 */
   {
-    FT_Face   face = cmap->cmap.cmap.charmap.face;
-    FT_Byte*  p;
-    FT_ULong  start, end, glyph_id, char_code;
-    FT_ULong  n;
-    FT_UInt   gindex;
-
+    TT_CMap13  ttcmap = (TT_CMap13)cmap;
+    FT_Face    face = FT_CMAP_FACE( cmap );
+    FT_Byte*   p;
+    FT_ULong   start, end, glyph_id, char_code;
+    FT_ULong   n;
+    FT_UInt    gindex;
 
-    if ( cmap->cur_charcode >= 0xFFFFFFFFUL )
-      goto Fail;
 
-    char_code = cmap->cur_charcode + 1;
+    char_code = ttcmap->cur_charcode + 1;
 
-    for ( n = cmap->cur_group; n < cmap->num_groups; n++ )
+    for ( n = ttcmap->cur_group; n < ttcmap->num_groups; n++ )
     {
-      p        = cmap->cmap.data + 16 + 12 * n;
+      p        = ttcmap->cmap.data + 16 + 12 * n;
       start    = TT_NEXT_ULONG( p );
       end      = TT_NEXT_ULONG( p );
       glyph_id = TT_PEEK_ULONG( p );
@@ -2709,17 +2707,16 @@
 
         if ( gindex && gindex < (FT_UInt)face->num_glyphs )
         {
-          cmap->cur_charcode = char_code;
-          cmap->cur_gindex   = gindex;
-          cmap->cur_group    = n;
+          ttcmap->cur_charcode = char_code;
+          ttcmap->cur_gindex   = gindex;
+          ttcmap->cur_group    = n;
 
           return;
         }
       }
     }
 
-  Fail:
-    cmap->valid = 0;
+    ttcmap->valid = 0;
   }
 
 
@@ -2731,7 +2728,7 @@
     FT_UInt    gindex     = 0;
     FT_Byte*   p          = cmap->data + 12;
     FT_UInt32  num_groups = TT_PEEK_ULONG( p );
-    FT_UInt32  char_code  = *pchar_code;
+    FT_UInt32  char_code  = *pchar_code + next;
     FT_UInt32  start, end;
     FT_UInt32  max, min, mid;
 
@@ -2739,23 +2736,11 @@
     if ( !num_groups )
       return 0;
 
-    /* make compiler happy */
-    mid = num_groups;
-    end = 0xFFFFFFFFUL;
-
-    if ( next )
-    {
-      if ( char_code >= 0xFFFFFFFFUL )
-        return 0;
-
-      char_code++;
-    }
-
     min = 0;
     max = num_groups;
 
     /* binary search */
-    while ( min < max )
+    do
     {
       mid = ( min + max ) >> 1;
       p   = cmap->data + 16 + 12 * mid;
@@ -2774,6 +2759,7 @@
         break;
       }
     }
+    while ( min < max );
 
     if ( next )
     {
@@ -2784,12 +2770,8 @@
       /* if `char_code' is not in any group, then `mid' is */
       /* the group nearest to `char_code'                  */
 
-      if ( char_code > end )
-      {
-        mid++;
-        if ( mid == num_groups )
-          return 0;
-      }
+      if ( char_code > end && ++mid == num_groups )
+        return 0;
 
       cmap13->valid        = 1;
       cmap13->cur_charcode = char_code;
@@ -2800,7 +2782,7 @@
 
       if ( !gindex )
       {
-        tt_cmap13_next( cmap13 );
+        tt_cmap13_next( FT_CMAP( cmap13 ) );
 
         if ( cmap13->valid )
           gindex = cmap13->cur_gindex;
@@ -2816,25 +2798,28 @@
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  tt_cmap13_char_index( TT_CMap    cmap,
+  tt_cmap13_char_index( FT_CMap    cmap,       /* TT_CMap */
                         FT_UInt32  char_code )
   {
-    return tt_cmap13_char_map_binary( cmap, &char_code, 0 );
+    return tt_cmap13_char_map_binary( (TT_CMap)cmap, &char_code, 0 );
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  tt_cmap13_char_next( TT_CMap     cmap,
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap13_char_next( FT_CMap     cmap,        /* TT_CMap13 */
                        FT_UInt32  *pchar_code )
   {
     TT_CMap13  cmap13 = (TT_CMap13)cmap;
     FT_UInt    gindex;
 
 
+    if ( *pchar_code >= 0xFFFFFFFFUL )
+      return 0;
+
     /* no need to search */
     if ( cmap13->valid && cmap13->cur_charcode == *pchar_code )
     {
-      tt_cmap13_next( cmap13 );
+      tt_cmap13_next( FT_CMAP( cmap13 ) );
       if ( cmap13->valid )
       {
         gindex      = cmap13->cur_gindex;
@@ -2844,17 +2829,18 @@
         gindex = 0;
     }
     else
-      gindex = tt_cmap13_char_map_binary( cmap, pchar_code, 1 );
+      gindex = tt_cmap13_char_map_binary( (TT_CMap)cmap, pchar_code, 1 );
 
     return gindex;
   }
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap13_get_info( TT_CMap       cmap,
+  tt_cmap13_get_info( FT_CharMap    cmap,       /* TT_CMap */
                       TT_CMapInfo  *cmap_info )
   {
-    FT_Byte*  p = cmap->data + 8;
+    TT_CMap   ttcmap = (TT_CMap)cmap;
+    FT_Byte*  p      = ttcmap->data + 8;
 
 
     cmap_info->format   = 13;
@@ -2969,14 +2955,15 @@
 
 
   FT_CALLBACK_DEF( void )
-  tt_cmap14_done( TT_CMap14  cmap )
+  tt_cmap14_done( FT_CMap  cmap )    /* TT_CMap14 */
   {
-    FT_Memory  memory = cmap->memory;
+    TT_CMap14  ttcmap = (TT_CMap14)cmap;
+    FT_Memory  memory = ttcmap->memory;
 
 
-    cmap->max_results = 0;
-    if ( memory && cmap->results )
-      FT_FREE( cmap->results );
+    ttcmap->max_results = 0;
+    if ( memory && ttcmap->results )
+      FT_FREE( ttcmap->results );
   }
 
 
@@ -3004,15 +2991,19 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap14_init( TT_CMap14  cmap,
-                  FT_Byte*   table )
+  tt_cmap14_init( FT_CMap  cmap,    /* TT_CMap14 */
+                  void*    table_ )
   {
-    cmap->cmap.data = table;
+    TT_CMap14  ttcmap = (TT_CMap14)cmap;
+    FT_Byte*   table  = (FT_Byte*)table_;
+
 
-    table               += 6;
-    cmap->num_selectors  = FT_PEEK_ULONG( table );
-    cmap->max_results    = 0;
-    cmap->results        = NULL;
+    ttcmap->cmap.data = table;
+
+    table                 += 6;
+    ttcmap->num_selectors  = FT_PEEK_ULONG( table );
+    ttcmap->max_results    = 0;
+    ttcmap->results        = NULL;
 
     return FT_Err_Ok;
   }
@@ -3142,7 +3133,7 @@
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  tt_cmap14_char_index( TT_CMap    cmap,
+  tt_cmap14_char_index( FT_CMap    cmap,
                         FT_UInt32  char_code )
   {
     FT_UNUSED( cmap );
@@ -3153,8 +3144,8 @@
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  tt_cmap14_char_next( TT_CMap     cmap,
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap14_char_next( FT_CMap     cmap,
                        FT_UInt32  *pchar_code )
   {
     FT_UNUSED( cmap );
@@ -3166,7 +3157,7 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap14_get_info( TT_CMap       cmap,
+  tt_cmap14_get_info( FT_CharMap    cmap,
                       TT_CMapInfo  *cmap_info )
   {
     FT_UNUSED( cmap );
@@ -3280,12 +3271,16 @@
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  tt_cmap14_char_var_index( TT_CMap    cmap,
-                            TT_CMap    ucmap,
+  tt_cmap14_char_var_index( FT_CMap    cmap,             /* TT_CMap */
+                            FT_CMap    ucmap,            /* TT_CMap */
                             FT_UInt32  charcode,
                             FT_UInt32  variantSelector )
   {
-    FT_Byte*  p = tt_cmap14_find_variant( cmap->data + 6, variantSelector );
+    TT_CMap  ttcmap  = (TT_CMap)cmap;
+    TT_CMap  ttucmap = (TT_CMap)ucmap;
+
+    FT_Byte*  p = tt_cmap14_find_variant( ttcmap->data + 6,
+                                          variantSelector );
     FT_ULong  defOff;
     FT_ULong  nondefOff;
 
@@ -3296,16 +3291,16 @@
     defOff    = TT_NEXT_ULONG( p );
     nondefOff = TT_PEEK_ULONG( p );
 
-    if ( defOff != 0                                                    &&
-         tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) )
+    if ( defOff != 0                                                      &&
+         tt_cmap14_char_map_def_binary( ttcmap->data + defOff, charcode ) )
     {
       /* This is the default variant of this charcode.  GID not stored */
       /* here; stored in the normal Unicode charmap instead.           */
-      return ucmap->cmap.clazz->char_index( &ucmap->cmap, charcode );
+      return ttucmap->cmap.clazz->char_index( &ttucmap->cmap, charcode );
     }
 
     if ( nondefOff != 0 )
-      return tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
+      return tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff,
                                                charcode );
 
     return 0;
@@ -3313,11 +3308,13 @@
 
 
   FT_CALLBACK_DEF( FT_Int )
-  tt_cmap14_char_var_isdefault( TT_CMap    cmap,
+  tt_cmap14_char_var_isdefault( FT_CMap    cmap,             /* TT_CMap */
                                 FT_UInt32  charcode,
                                 FT_UInt32  variantSelector )
   {
-    FT_Byte*  p = tt_cmap14_find_variant( cmap->data + 6, variantSelector );
+    TT_CMap   ttcmap = (TT_CMap)cmap;
+    FT_Byte*  p      = tt_cmap14_find_variant( ttcmap->data + 6,
+                                               variantSelector );
     FT_ULong  defOff;
     FT_ULong  nondefOff;
 
@@ -3328,13 +3325,13 @@
     defOff    = TT_NEXT_ULONG( p );
     nondefOff = TT_NEXT_ULONG( p );
 
-    if ( defOff != 0                                                    &&
-         tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) )
+    if ( defOff != 0                                                      &&
+         tt_cmap14_char_map_def_binary( ttcmap->data + defOff, charcode ) )
       return 1;
 
-    if ( nondefOff != 0                                            &&
-         tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
-                                           charcode ) != 0         )
+    if ( nondefOff != 0                                              &&
+         tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff,
+                                           charcode ) != 0           )
       return 0;
 
     return -1;
@@ -3342,12 +3339,13 @@
 
 
   FT_CALLBACK_DEF( FT_UInt32* )
-  tt_cmap14_variants( TT_CMap    cmap,
+  tt_cmap14_variants( FT_CMap    cmap,    /* TT_CMap14 */
                       FT_Memory  memory )
   {
+    TT_CMap     ttcmap = (TT_CMap)cmap;
     TT_CMap14   cmap14 = (TT_CMap14)cmap;
     FT_UInt32   count  = cmap14->num_selectors;
-    FT_Byte*    p      = cmap->data + 10;
+    FT_Byte*    p      = ttcmap->data + 10;
     FT_UInt32*  result;
     FT_UInt32   i;
 
@@ -3368,13 +3366,14 @@
 
 
   FT_CALLBACK_DEF( FT_UInt32 * )
-  tt_cmap14_char_variants( TT_CMap    cmap,
+  tt_cmap14_char_variants( FT_CMap    cmap,      /* TT_CMap14 */
                            FT_Memory  memory,
                            FT_UInt32  charCode )
   {
-    TT_CMap14   cmap14 = (TT_CMap14)  cmap;
+    TT_CMap     ttcmap = (TT_CMap)cmap;
+    TT_CMap14   cmap14 = (TT_CMap14)cmap;
     FT_UInt32   count  = cmap14->num_selectors;
-    FT_Byte*    p      = cmap->data + 10;
+    FT_Byte*    p      = ttcmap->data + 10;
     FT_UInt32*  q;
 
 
@@ -3388,12 +3387,12 @@
       FT_ULong   nondefOff = TT_NEXT_ULONG( p );
 
 
-      if ( ( defOff != 0                                               &&
-             tt_cmap14_char_map_def_binary( cmap->data + defOff,
-                                            charCode )                 ) ||
-           ( nondefOff != 0                                            &&
-             tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
-                                               charCode ) != 0         ) )
+      if ( ( defOff != 0                                                 &&
+             tt_cmap14_char_map_def_binary( ttcmap->data + defOff,
+                                            charCode )                   ) ||
+           ( nondefOff != 0                                              &&
+             tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff,
+                                               charCode ) != 0           ) )
       {
         q[0] = varSel;
         q++;
@@ -3489,15 +3488,16 @@
 
 
   FT_CALLBACK_DEF( FT_UInt32 * )
-  tt_cmap14_variant_chars( TT_CMap    cmap,
+  tt_cmap14_variant_chars( FT_CMap    cmap,             /* TT_CMap */
                            FT_Memory  memory,
                            FT_UInt32  variantSelector )
   {
-    FT_Byte    *p  = tt_cmap14_find_variant( cmap->data + 6,
-                                             variantSelector );
-    FT_Int      i;
-    FT_ULong    defOff;
-    FT_ULong    nondefOff;
+    TT_CMap   ttcmap = (TT_CMap)cmap;
+    FT_Byte  *p      = tt_cmap14_find_variant( ttcmap->data + 6,
+                                               variantSelector );
+    FT_Int    i;
+    FT_ULong  defOff;
+    FT_ULong  nondefOff;
 
 
     if ( !p )
@@ -3510,16 +3510,16 @@
       return NULL;
 
     if ( defOff == 0 )
-      return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff,
+      return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff,
                                          memory );
     else if ( nondefOff == 0 )
-      return tt_cmap14_get_def_chars( cmap, cmap->data + defOff,
+      return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff,
                                       memory );
     else
     {
       /* Both a default and a non-default glyph set?  That's probably not */
       /* good font design, but the spec allows for it...                  */
-      TT_CMap14  cmap14 = (TT_CMap14) cmap;
+      TT_CMap14  cmap14 = (TT_CMap14)cmap;
       FT_UInt32  numRanges;
       FT_UInt32  numMappings;
       FT_UInt32  duni;
@@ -3531,18 +3531,18 @@
       FT_UInt32  *ret;
 
 
-      p  = cmap->data + nondefOff;
-      dp = cmap->data + defOff;
+      p  = ttcmap->data + nondefOff;
+      dp = ttcmap->data + defOff;
 
       numMappings = (FT_UInt32)TT_NEXT_ULONG( p );
       dcnt        = tt_cmap14_def_char_count( dp );
       numRanges   = (FT_UInt32)TT_NEXT_ULONG( dp );
 
       if ( numMappings == 0 )
-        return tt_cmap14_get_def_chars( cmap, cmap->data + defOff,
+        return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff,
                                         memory );
       if ( dcnt == 0 )
-        return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff,
+        return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff,
                                            memory );
 
       if ( tt_cmap14_ensure( cmap14, ( dcnt + numMappings + 1 ), memory ) )
@@ -3664,9 +3664,10 @@
 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
 
   FT_CALLBACK_DEF( const char * )
-  tt_get_glyph_name( TT_Face  face,
+  tt_get_glyph_name( void*    face_,   /* TT_Face */
                      FT_UInt  idx )
   {
+    TT_Face     face   = (TT_Face)face_;
     FT_String*  PSname = NULL;
 
 
@@ -3677,12 +3678,13 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  tt_cmap_unicode_init( PS_Unicodes  unicodes,
-                        FT_Pointer   pointer )
+  tt_cmap_unicode_init( FT_CMap     cmap,     /* PS_Unicodes */
+                        FT_Pointer  pointer )
   {
-    TT_Face             face    = (TT_Face)FT_CMAP_FACE( unicodes );
-    FT_Memory           memory  = FT_FACE_MEMORY( face );
-    FT_Service_PsCMaps  psnames = (FT_Service_PsCMaps)face->psnames;
+    PS_Unicodes         unicodes = (PS_Unicodes)cmap;
+    TT_Face             face     = (TT_Face)FT_CMAP_FACE( cmap );
+    FT_Memory           memory   = FT_FACE_MEMORY( face );
+    FT_Service_PsCMaps  psnames  = (FT_Service_PsCMaps)face->psnames;
 
     FT_UNUSED( pointer );
 
@@ -3693,17 +3695,18 @@
     return psnames->unicodes_init( memory,
                                    unicodes,
                                    face->root.num_glyphs,
-                                   (PS_GetGlyphNameFunc)&tt_get_glyph_name,
+                                   &tt_get_glyph_name,
                                    (PS_FreeGlyphNameFunc)NULL,
                                    (FT_Pointer)face );
   }
 
 
   FT_CALLBACK_DEF( void )
-  tt_cmap_unicode_done( PS_Unicodes  unicodes )
+  tt_cmap_unicode_done( FT_CMap  cmap )    /* PS_Unicodes */
   {
-    FT_Face    face   = FT_CMAP_FACE( unicodes );
-    FT_Memory  memory = FT_FACE_MEMORY( face );
+    PS_Unicodes  unicodes = (PS_Unicodes)cmap;
+    FT_Face      face     = FT_CMAP_FACE( cmap );
+    FT_Memory    memory   = FT_FACE_MEMORY( face );
 
 
     FT_FREE( unicodes->maps );
@@ -3712,23 +3715,25 @@
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  tt_cmap_unicode_char_index( PS_Unicodes  unicodes,
-                              FT_UInt32    char_code )
+  tt_cmap_unicode_char_index( FT_CMap    cmap,       /* PS_Unicodes */
+                              FT_UInt32  char_code )
   {
-    TT_Face             face    = (TT_Face)FT_CMAP_FACE( unicodes );
-    FT_Service_PsCMaps  psnames = (FT_Service_PsCMaps)face->psnames;
+    PS_Unicodes         unicodes = (PS_Unicodes)cmap;
+    TT_Face             face     = (TT_Face)FT_CMAP_FACE( cmap );
+    FT_Service_PsCMaps  psnames  = (FT_Service_PsCMaps)face->psnames;
 
 
     return psnames->unicodes_char_index( unicodes, char_code );
   }
 
 
-  FT_CALLBACK_DEF( FT_UInt32 )
-  tt_cmap_unicode_char_next( PS_Unicodes  unicodes,
-                             FT_UInt32   *pchar_code )
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap_unicode_char_next( FT_CMap     cmap,        /* PS_Unicodes */
+                             FT_UInt32  *pchar_code )
   {
-    TT_Face             face    = (TT_Face)FT_CMAP_FACE( unicodes );
-    FT_Service_PsCMaps  psnames = (FT_Service_PsCMaps)face->psnames;
+    PS_Unicodes         unicodes = (PS_Unicodes)cmap;
+    TT_Face             face     = (TT_Face)FT_CMAP_FACE( cmap );
+    FT_Service_PsCMaps  psnames  = (FT_Service_PsCMaps)face->psnames;
 
 
     return psnames->unicodes_char_next( unicodes, pchar_code );
@@ -3883,7 +3888,7 @@
   tt_get_cmap_info( FT_CharMap    charmap,
                     TT_CMapInfo  *cmap_info )
   {
-    FT_CMap        cmap  = (FT_CMap)charmap;
+    FT_CMap        cmap  = FT_CMAP( charmap );
     TT_CMap_Class  clazz = (TT_CMap_Class)cmap->clazz;
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c
index 5d98dcab8ffcf..281e7135eea82 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c
@@ -229,7 +229,7 @@
 
       base_glyphs_offset_v1 = FT_NEXT_ULONG( p );
 
-      if ( base_glyphs_offset_v1 + 4 >= table_size )
+      if ( base_glyphs_offset_v1 >= table_size - 4 )
         goto InvalidTable;
 
       p1                 = (FT_Byte*)( table + base_glyphs_offset_v1 );
@@ -249,7 +249,7 @@
 
       if ( layer_offset_v1 )
       {
-        if ( layer_offset_v1 + 4 >= table_size )
+        if ( layer_offset_v1 >= table_size - 4 )
           goto InvalidTable;
 
         p1            = (FT_Byte*)( table + layer_offset_v1 );
@@ -699,7 +699,7 @@
                                              item_deltas ) )
           return 0;
 
-        apaint->u.solid.color.alpha += item_deltas[0];
+        apaint->u.solid.color.alpha += (FT_F2Dot14)item_deltas[0];
       }
 #endif
 
@@ -1646,7 +1646,7 @@
           return 0;
 
         color_stop->stop_offset += F2DOT14_TO_FIXED( item_deltas[0] );
-        color_stop->color.alpha += item_deltas[1];
+        color_stop->color.alpha += (FT_F2Dot14)item_deltas[1];
       }
 #else
       FT_UNUSED( var_index_base );
@@ -1914,7 +1914,7 @@
 #else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
 
   /* ANSI C doesn't like empty source files */
-  typedef int  _tt_colr_dummy;
+  typedef int  tt_colr_dummy_;
 
 #endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c
index 4279bc0bd1033..46ae08596f39b 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c
@@ -303,7 +303,7 @@
 #else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
 
   /* ANSI C doesn't like empty source files */
-  typedef int  _tt_cpal_dummy;
+  typedef int  tt_cpal_dummy_;
 
 #endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c
index 14f625c824352..7b44e9cd2e71c 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c
@@ -504,6 +504,13 @@
 
     FT_FRAME_EXIT();
 
+    if ( !valid_entries )
+    {
+      FT_TRACE2(( "tt_face_load_font_dir: no valid tables found\n" ));
+      error = FT_THROW( Unknown_File_Format );
+      goto Exit;
+    }
+
     FT_TRACE2(( "table directory loaded\n" ));
     FT_TRACE2(( "\n" ));
 
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c
index 5e53e6dd4a317..38ee9ae728a1d 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c
@@ -239,7 +239,7 @@
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
     FT_Service_MetricsVariations  var =
-      (FT_Service_MetricsVariations)face->var;
+      (FT_Service_MetricsVariations)face->tt_var;
 #endif
 
 
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c
index 0e17c6f34aeb5..1dfad4298bd67 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c
@@ -156,86 +156,66 @@
 
 
   static FT_Error
-  load_format_20( TT_Face    face,
-                  FT_Stream  stream,
-                  FT_ULong   post_len )
+  load_format_20( TT_Post_Names  names,
+                  FT_Stream      stream,
+                  FT_UShort      num_glyphs,
+                  FT_ULong       post_len )
   {
     FT_Memory   memory = stream->memory;
     FT_Error    error;
 
-    FT_Int      num_glyphs;
-    FT_UShort   num_names;
+    FT_UShort   n;
+    FT_UShort   num_names = 0;
 
     FT_UShort*  glyph_indices = NULL;
-    FT_Char**   name_strings  = NULL;
-    FT_Byte*    strings       = NULL;
+    FT_Byte**   name_strings  = NULL;
+    FT_Byte*    q;
 
 
-    if ( FT_READ_USHORT( num_glyphs ) )
-      goto Exit;
-
-    /* UNDOCUMENTED!  The number of glyphs in this table can be smaller */
-    /* than the value in the maxp table (cf. cyberbit.ttf).             */
-
-    /* There already exist fonts which have more than 32768 glyph names */
-    /* in this table, so the test for this threshold has been dropped.  */
-
-    if ( num_glyphs > face->max_profile.numGlyphs  ||
-         (FT_ULong)num_glyphs * 2UL > post_len - 2 )
+    if ( (FT_ULong)num_glyphs * 2 > post_len )
     {
       error = FT_THROW( Invalid_File_Format );
       goto Exit;
     }
 
-    /* load the indices */
-    {
-      FT_Int  n;
-
-
-      if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) ||
-           FT_FRAME_ENTER( num_glyphs * 2L )          )
-        goto Fail;
-
-      for ( n = 0; n < num_glyphs; n++ )
-        glyph_indices[n] = FT_GET_USHORT();
+    /* load the indices and note their maximum */
+    if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) ||
+         FT_FRAME_ENTER( num_glyphs * 2 )           )
+      goto Fail;
 
-      FT_FRAME_EXIT();
-    }
+    q = (FT_Byte*)stream->cursor;
 
-    /* compute number of names stored in table */
+    for ( n = 0; n < num_glyphs; n++ )
     {
-      FT_Int  n;
+      FT_UShort  idx = FT_NEXT_USHORT( q );
 
 
-      num_names = 0;
+      if ( idx > num_names )
+        num_names = idx;
 
-      for ( n = 0; n < num_glyphs; n++ )
-      {
-        FT_Int  idx;
+      glyph_indices[n] = idx;
+    }
 
+    FT_FRAME_EXIT();
 
-        idx = glyph_indices[n];
-        if ( idx >= 258 )
-        {
-          idx -= 257;
-          if ( idx > num_names )
-            num_names = (FT_UShort)idx;
-        }
-      }
-    }
+    /* compute number of names stored in the table */
+    num_names = num_names > 257 ? num_names - 257 : 0;
 
     /* now load the name strings */
     if ( num_names )
     {
-      FT_UShort  n;
       FT_ULong   p;
+      FT_Byte*   strings;
 
 
-      post_len -= (FT_ULong)num_glyphs * 2UL + 2;
+      post_len -= (FT_ULong)num_glyphs * 2;
+
+      if ( FT_QALLOC( name_strings, num_names * sizeof ( FT_Byte* ) +
+                                    post_len + 1 ) )
+        goto Fail;
 
-      if ( FT_QALLOC( strings, post_len + 1 )       ||
-           FT_STREAM_READ( strings, post_len )      ||
-           FT_QNEW_ARRAY( name_strings, num_names ) )
+      strings = (FT_Byte*)( name_strings + num_names );
+      if ( FT_STREAM_READ( strings, post_len ) )
         goto Fail;
 
       /* convert from Pascal- to C-strings and set pointers */
@@ -251,7 +231,7 @@
         }
 
         strings[p]      = 0;
-        name_strings[n] = (FT_Char*)strings + p + 1;
+        name_strings[n] = strings + p + 1;
         p              += len + 1;
       }
       strings[post_len] = 0;
@@ -259,40 +239,24 @@
       /* deal with missing or insufficient string data */
       if ( n < num_names )
       {
-        if ( post_len == 0 )
-        {
-          /* fake empty string */
-          if ( FT_QREALLOC( strings, 1, 2 ) )
-            goto Fail;
-
-          post_len          = 1;
-          strings[post_len] = 0;
-        }
+        FT_TRACE4(( "load_format_20: %hu PostScript names are truncated\n",
+                    num_names - n ));
 
-        FT_ERROR(( "load_format_20:"
-                   " all entries in post table are already parsed,"
-                   " using NULL names for gid %d - %d\n",
-                    n, num_names - 1 ));
         for ( ; n < num_names; n++ )
-          name_strings[n] = (FT_Char*)strings + post_len;
+          name_strings[n] = strings + post_len;
       }
     }
 
     /* all right, set table fields and exit successfully */
-    {
-      TT_Post_20  table = &face->postscript_names.names.format_20;
-
+    names->num_glyphs    = num_glyphs;
+    names->num_names     = num_names;
+    names->glyph_indices = glyph_indices;
+    names->glyph_names   = name_strings;
 
-      table->num_glyphs    = (FT_UShort)num_glyphs;
-      table->num_names     = (FT_UShort)num_names;
-      table->glyph_indices = glyph_indices;
-      table->glyph_names   = name_strings;
-    }
     return FT_Err_Ok;
 
   Fail:
     FT_FREE( name_strings );
-    FT_FREE( strings );
     FT_FREE( glyph_indices );
 
   Exit:
@@ -301,66 +265,55 @@
 
 
   static FT_Error
-  load_format_25( TT_Face    face,
-                  FT_Stream  stream,
-                  FT_ULong   post_len )
+  load_format_25( TT_Post_Names  names,
+                  FT_Stream      stream,
+                  FT_UShort      num_glyphs,
+                  FT_ULong       post_len )
   {
     FT_Memory  memory = stream->memory;
     FT_Error   error;
 
-    FT_Int     num_glyphs;
-    FT_Char*   offset_table = NULL;
-
-    FT_UNUSED( post_len );
+    FT_UShort   n;
+    FT_UShort*  glyph_indices = NULL;
+    FT_Byte*    q;
 
 
-    if ( FT_READ_USHORT( num_glyphs ) )
-      goto Exit;
-
-    /* check the number of glyphs */
-    if ( num_glyphs > face->max_profile.numGlyphs ||
-         num_glyphs > 258                         ||
-         num_glyphs < 1                           )
+    /* check the number of glyphs, including the theoretical limit */
+    if ( num_glyphs > post_len  ||
+         num_glyphs > 258 + 128 )
     {
       error = FT_THROW( Invalid_File_Format );
       goto Exit;
     }
 
-    if ( FT_QNEW_ARRAY( offset_table, num_glyphs )  ||
-         FT_STREAM_READ( offset_table, num_glyphs ) )
+    /* load the indices and check their Mac range */
+    if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) ||
+         FT_FRAME_ENTER( num_glyphs )               )
       goto Fail;
 
-    /* now check the offset table */
-    {
-      FT_Int  n;
+    q = (FT_Byte*)stream->cursor;
 
+    for ( n = 0; n < num_glyphs; n++ )
+    {
+      FT_Int  idx = n + FT_NEXT_CHAR( q );
 
-      for ( n = 0; n < num_glyphs; n++ )
-      {
-        FT_Long  idx = (FT_Long)n + offset_table[n];
 
+      if ( idx < 0 || idx > 257 )
+        idx = 0;
 
-        if ( idx < 0 || idx > num_glyphs )
-        {
-          error = FT_THROW( Invalid_File_Format );
-          goto Fail;
-        }
-      }
+      glyph_indices[n] = (FT_UShort)idx;
     }
 
-    /* OK, set table fields and exit successfully */
-    {
-      TT_Post_25  table = &face->postscript_names.names.format_25;
-
+    FT_FRAME_EXIT();
 
-      table->num_glyphs = (FT_UShort)num_glyphs;
-      table->offsets    = offset_table;
-    }
+    /* OK, set table fields and exit successfully */
+    names->num_glyphs    = num_glyphs;
+    names->glyph_indices = glyph_indices;
 
     return FT_Err_Ok;
 
   Fail:
-    FT_FREE( offset_table );
+    FT_FREE( glyph_indices );
 
   Exit:
     return error;
@@ -370,37 +323,37 @@
   static FT_Error
   load_post_names( TT_Face  face )
   {
-    FT_Stream  stream;
-    FT_Error   error;
-    FT_Fixed   format;
+    FT_Error   error = FT_Err_Ok;
+    FT_Stream  stream = face->root.stream;
+    FT_Fixed   format = face->postscript.FormatType;
     FT_ULong   post_len;
+    FT_UShort  num_glyphs;
 
 
-    /* get a stream for the face's resource */
-    stream = face->root.stream;
-
     /* seek to the beginning of the PS names table */
     error = face->goto_table( face, TTAG_post, stream, &post_len );
     if ( error )
       goto Exit;
 
-    format = face->postscript.FormatType;
-
-    /* go to beginning of subtable */
-    if ( FT_STREAM_SKIP( 32 ) )
+    /* UNDOCUMENTED!  The number of glyphs in this table can be smaller */
+    /* than the value in the maxp table (cf. cyberbit.ttf).             */
+    if ( post_len < 34                            ||
+         FT_STREAM_SKIP( 32 )                     ||
+         FT_READ_USHORT( num_glyphs )             ||
+         num_glyphs > face->max_profile.numGlyphs ||
+         num_glyphs == 0 )
       goto Exit;
 
-    /* now read postscript table */
-    if ( format == 0x00020000L && post_len >= 34 )
-      error = load_format_20( face, stream, post_len - 32 );
-    else if ( format == 0x00025000L && post_len >= 34 )
-      error = load_format_25( face, stream, post_len - 32 );
-    else
-      error = FT_THROW( Invalid_File_Format );
-
-    face->postscript_names.loaded = 1;
+    /* now read postscript names data */
+    if ( format == 0x00020000L )
+      error = load_format_20( &face->postscript_names, stream,
+                              num_glyphs, post_len - 34 );
+    else if ( format == 0x00025000L )
+      error = load_format_25( &face->postscript_names, stream,
+                              num_glyphs, post_len - 34 );
 
   Exit:
+    face->postscript_names.loaded = 1;  /* even if failed */
     return error;
   }
 
@@ -410,39 +363,20 @@
   {
     FT_Memory      memory = face->root.memory;
     TT_Post_Names  names  = &face->postscript_names;
-    FT_Fixed       format;
 
 
-    if ( names->loaded )
+    if ( names->num_glyphs )
     {
-      format = face->postscript.FormatType;
-
-      if ( format == 0x00020000L )
-      {
-        TT_Post_20  table = &names->names.format_20;
-
-
-        FT_FREE( table->glyph_indices );
-        table->num_glyphs = 0;
-
-        if ( table->num_names )
-        {
-          table->glyph_names[0]--;
-          FT_FREE( table->glyph_names[0] );
-
-          FT_FREE( table->glyph_names );
-          table->num_names = 0;
-        }
-      }
-      else if ( format == 0x00025000L )
-      {
-        TT_Post_25  table = &names->names.format_25;
-
+      FT_FREE( names->glyph_indices );
+      names->num_glyphs = 0;
+    }
 
-        FT_FREE( table->offsets );
-        table->num_glyphs = 0;
-      }
+    if ( names->num_names )
+    {
+      FT_FREE( names->glyph_names );
+      names->num_names = 0;
     }
+
     names->loaded = 0;
   }
 
@@ -478,7 +412,6 @@
                        FT_String**  PSname )
   {
     FT_Error       error;
-    TT_Post_Names  names;
     FT_Fixed       format;
 
 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
@@ -498,8 +431,6 @@
       return FT_THROW( Unimplemented_Feature );
 #endif
 
-    names = &face->postscript_names;
-
     /* `.notdef' by default */
     *PSname = MAC_NAME( 0 );
 
@@ -510,9 +441,10 @@
       if ( idx < 258 )                    /* paranoid checking */
         *PSname = MAC_NAME( idx );
     }
-    else if ( format == 0x00020000L )
+    else if ( format == 0x00020000L ||
+              format == 0x00025000L )
     {
-      TT_Post_20  table = &names->names.format_20;
+      TT_Post_Names  names = &face->postscript_names;
 
 
       if ( !names->loaded )
@@ -522,43 +454,29 @@
           goto End;
       }
 
-      if ( idx < (FT_UInt)table->num_glyphs )
+      if ( idx < (FT_UInt)names->num_glyphs )
       {
-        FT_UShort  name_index = table->glyph_indices[idx];
+        FT_UShort  name_index = names->glyph_indices[idx];
 
 
         if ( name_index < 258 )
           *PSname = MAC_NAME( name_index );
-        else
-          *PSname = (FT_String*)table->glyph_names[name_index - 258];
-      }
-    }
-    else if ( format == 0x00025000L )
-    {
-      TT_Post_25  table = &names->names.format_25;
-
-
-      if ( !names->loaded )
-      {
-        error = load_post_names( face );
-        if ( error )
-          goto End;
+        else  /* only for version 2.0 */
+          *PSname = (FT_String*)names->glyph_names[name_index - 258];
       }
-
-      if ( idx < (FT_UInt)table->num_glyphs )    /* paranoid checking */
-        *PSname = MAC_NAME( (FT_Int)idx + table->offsets[idx] );
     }
 
     /* nothing to do for format == 0x00030000L */
 
   End:
+    /* post format errors ignored */
     return FT_Err_Ok;
   }
 
 #else /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
 
   /* ANSI C doesn't like empty source files */
-  typedef int  _tt_post_dummy;
+  typedef int  tt_post_dummy_;
 
 #endif /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c
index 3c06955131578..03f90a628d6e6 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c
@@ -1677,7 +1677,7 @@
 #else /* !TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
 
   /* ANSI C doesn't like empty source files */
-  typedef int  _tt_sbit_dummy;
+  typedef int  tt_sbit_dummy_;
 
 #endif /* !TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c b/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c
index 7a0a351f06c03..eeedd9906be5a 100644
--- a/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c
+++ b/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c
@@ -111,7 +111,7 @@
 #else /* !FT_CONFIG_OPTION_USE_BROTLI */
 
   /* ANSI C doesn't like empty source files */
-  typedef int  _woff2tags_dummy;
+  typedef int  woff2tags_dummy_;
 
 #endif /* !FT_CONFIG_OPTION_USE_BROTLI */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c
index d9f20eef131d2..0918272f87046 100644
--- a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c
+++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c
@@ -1006,10 +1006,11 @@ typedef ptrdiff_t  FT_PtrDist;
    *
    * For other cases, using binary splits is actually slightly faster.
    */
-#if defined( __SSE2__ )                          || \
-    defined( __x86_64__ )                        || \
-    defined( _M_AMD64 )                          || \
-    ( defined( _M_IX86_FP ) && _M_IX86_FP >= 2 )
+#if ( defined( __SSE2__ )                          ||   \
+      defined( __x86_64__ )                        ||   \
+      defined( _M_AMD64 )                          ||   \
+      ( defined( _M_IX86_FP ) && _M_IX86_FP >= 2 ) ) && \
+    !defined( __VMS )
 #  define FT_SSE2 1
 #else
 #  define FT_SSE2 0
@@ -1427,8 +1428,10 @@ typedef ptrdiff_t  FT_PtrDist;
 
   static int
   gray_move_to( const FT_Vector*  to,
-                gray_PWorker      worker )
+                void*             worker_ )  /* gray_PWorker */
   {
+    gray_PWorker  worker = (gray_PWorker)worker_;
+
     TPos  x, y;
 
 
@@ -1446,8 +1449,11 @@ typedef ptrdiff_t  FT_PtrDist;
 
   static int
   gray_line_to( const FT_Vector*  to,
-                gray_PWorker      worker )
+                void*             worker_ )   /* gray_PWorker */
   {
+    gray_PWorker  worker = (gray_PWorker)worker_;
+
+
     gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
     return 0;
   }
@@ -1456,8 +1462,11 @@ typedef ptrdiff_t  FT_PtrDist;
   static int
   gray_conic_to( const FT_Vector*  control,
                  const FT_Vector*  to,
-                 gray_PWorker      worker )
+                 void*             worker_ )   /* gray_PWorker */
   {
+    gray_PWorker  worker = (gray_PWorker)worker_;
+
+
     gray_render_conic( RAS_VAR_ control, to );
     return 0;
   }
@@ -1467,8 +1476,11 @@ typedef ptrdiff_t  FT_PtrDist;
   gray_cubic_to( const FT_Vector*  control1,
                  const FT_Vector*  control2,
                  const FT_Vector*  to,
-                 gray_PWorker      worker )
+                 void*             worker_ )   /* gray_PWorker */
   {
+    gray_PWorker  worker = (gray_PWorker)worker_;
+
+
     gray_render_cubic( RAS_VAR_ control1, control2, to );
     return 0;
   }
@@ -1666,6 +1678,8 @@ typedef ptrdiff_t  FT_PtrDist;
 
     int   n;         /* index of contour in outline     */
     int   first;     /* index of first point in contour */
+    int   last;      /* index of last point in contour  */
+
     char  tag;       /* current point's state           */
 
     int   shift;
@@ -1680,18 +1694,17 @@ typedef ptrdiff_t  FT_PtrDist;
 
     shift = func_interface->shift;
     delta = func_interface->delta;
-    first = 0;
 
+    last = -1;
     for ( n = 0; n < outline->n_contours; n++ )
     {
-      int  last;  /* index of last point in contour */
-
-
-      FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
+      FT_TRACE5(( "FT_Outline_Decompose: Contour %d\n", n ));
 
+      first = last + 1;
       last  = outline->contours[n];
-      if ( last < 0 )
+      if ( last < first )
         goto Invalid_Outline;
+
       limit = outline->points + last;
 
       v_start   = outline->points[first];
@@ -1874,11 +1887,9 @@ typedef ptrdiff_t  FT_PtrDist;
                   v_start.x / 64.0, v_start.y / 64.0 ));
       error = func_interface->line_to( &v_start, user );
 
-   Close:
+    Close:
       if ( error )
         goto Exit;
-
-      first = last + 1;
     }
 
     FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
@@ -1923,7 +1934,7 @@ typedef ptrdiff_t  FT_PtrDist;
       if ( continued )
         FT_Trace_Enable();
 
-      FT_TRACE7(( "band [%d..%d]: %ld cell%s remaining/\n",
+      FT_TRACE7(( "band [%d..%d]: %td cell%s remaining/\n",
                   ras.min_ey,
                   ras.max_ey,
                   ras.cell_null - ras.cell_free,
@@ -2156,9 +2167,12 @@ typedef ptrdiff_t  FT_PtrDist;
 #else /* !STANDALONE_ */
 
   static int
-  gray_raster_new( FT_Memory      memory,
-                   gray_PRaster*  araster )
+  gray_raster_new( void*       memory_,
+                   FT_Raster*  araster_ )
   {
+    FT_Memory      memory  = (FT_Memory)memory_;
+    gray_PRaster*  araster = (gray_PRaster*)araster_;
+
     FT_Error      error;
     gray_PRaster  raster = NULL;
 
diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c
index cdbc78c3e538d..9b0e8886cb332 100644
--- a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c
+++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c
@@ -87,8 +87,10 @@
 
   /* initialize renderer -- init its raster */
   static FT_Error
-  ft_smooth_init( FT_Renderer  render )
+  ft_smooth_init( FT_Module  module )   /* FT_Renderer */
   {
+    FT_Renderer  render = (FT_Renderer)module;
+
     FT_Vector*  sub = render->root.library->lcd_geometry;
 
 
@@ -111,8 +113,10 @@
   ft_smooth_lcd_spans( int             y,
                        int             count,
                        const FT_Span*  spans,
-                       TOrigin*        target )
+                       void*           target_ )   /* TOrigin* */
   {
+    TOrigin*  target = (TOrigin*)target_;
+
     unsigned char*  dst_line = target->origin - y * target->pitch;
     unsigned char*  dst;
     unsigned short  w;
@@ -141,7 +145,7 @@
     /* Set up direct rendering to record them on each third byte. */
     params.source     = outline;
     params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
-    params.gray_spans = (FT_SpanFunc)ft_smooth_lcd_spans;
+    params.gray_spans = ft_smooth_lcd_spans;
     params.user       = ⌖
 
     params.clip_box.xMin = 0;
@@ -256,8 +260,11 @@
 
   /* initialize renderer -- init its raster */
   static FT_Error
-  ft_smooth_init( FT_Renderer  render )
+  ft_smooth_init( FT_Module  module )   /* FT_Renderer */
   {
+    FT_Renderer  render = (FT_Renderer)module;
+
+
     /* set up default LCD filtering */
     FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT );
 
@@ -340,8 +347,11 @@
   ft_smooth_overlap_spans( int             y,
                            int             count,
                            const FT_Span*  spans,
-                           TOrigin*        target )
+                           void*           target_ )
   {
+    TOrigin*  target = (TOrigin*)target_;
+
+
     unsigned char*  dst = target->origin - ( y / SCALE ) * target->pitch;
     unsigned short  x;
     unsigned int    cover, sum;
@@ -386,7 +396,7 @@
     /* Set up direct rendering to average oversampled spans. */
     params.source     = outline;
     params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
-    params.gray_spans = (FT_SpanFunc)ft_smooth_overlap_spans;
+    params.gray_spans = ft_smooth_overlap_spans;
     params.user       = ⌖
 
     params.clip_box.xMin = 0;
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c
index 4bea63ef84391..d1496fec7fad7 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c
@@ -57,7 +57,7 @@
    * PROPERTY SERVICE
    *
    */
-  static FT_Error
+  FT_CALLBACK_DEF( FT_Error )
   tt_property_set( FT_Module    module,         /* TT_Driver */
                    const char*  property_name,
                    const void*  value,
@@ -93,17 +93,22 @@
         interpreter_version = *iv;
       }
 
-      if ( interpreter_version == TT_INTERPRETER_VERSION_35
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-           || interpreter_version == TT_INTERPRETER_VERSION_38
-#endif
+      switch ( interpreter_version )
+      {
+      case TT_INTERPRETER_VERSION_35:
+        driver->interpreter_version = TT_INTERPRETER_VERSION_35;
+        break;
+
+      case TT_INTERPRETER_VERSION_38:
+      case TT_INTERPRETER_VERSION_40:
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-           || interpreter_version == TT_INTERPRETER_VERSION_40
+        driver->interpreter_version = TT_INTERPRETER_VERSION_40;
+      break;
 #endif
-         )
-        driver->interpreter_version = interpreter_version;
-      else
+
+      default:
         error = FT_ERR( Unimplemented_Feature );
+      }
 
       return error;
     }
@@ -114,10 +119,10 @@
   }
 
 
-  static FT_Error
+  FT_CALLBACK_DEF( FT_Error )
   tt_property_get( FT_Module    module,         /* TT_Driver */
                    const char*  property_name,
-                   const void*  value )
+                   void*        value )
   {
     FT_Error   error  = FT_Err_Ok;
     TT_Driver  driver = (TT_Driver)module;
@@ -144,8 +149,8 @@
   FT_DEFINE_SERVICE_PROPERTIESREC(
     tt_service_properties,
 
-    (FT_Properties_SetFunc)tt_property_set,     /* set_property */
-    (FT_Properties_GetFunc)tt_property_get      /* get_property */
+    tt_property_set,  /* FT_Properties_SetFunc set_property */
+    tt_property_get   /* FT_Properties_GetFunc get_property */
   )
 
 
@@ -198,35 +203,35 @@
    *
    *   They can be implemented by format-specific interfaces.
    */
-  static FT_Error
-  tt_get_kerning( FT_Face     ttface,          /* TT_Face */
+  FT_CALLBACK_DEF( FT_Error )
+  tt_get_kerning( FT_Face     face,        /* TT_Face */
                   FT_UInt     left_glyph,
                   FT_UInt     right_glyph,
                   FT_Vector*  kerning )
   {
-    TT_Face       face = (TT_Face)ttface;
-    SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
+    TT_Face       ttface = (TT_Face)face;
+    SFNT_Service  sfnt   = (SFNT_Service)ttface->sfnt;
 
 
     kerning->x = 0;
     kerning->y = 0;
 
     if ( sfnt )
-      kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph );
+      kerning->x = sfnt->get_kerning( ttface, left_glyph, right_glyph );
 
     return 0;
   }
 
 
-  static FT_Error
-  tt_get_advances( FT_Face    ttface,
+  FT_CALLBACK_DEF( FT_Error )
+  tt_get_advances( FT_Face    face,      /* TT_Face */
                    FT_UInt    start,
                    FT_UInt    count,
                    FT_Int32   flags,
                    FT_Fixed  *advances )
   {
     FT_UInt  nn;
-    TT_Face  face = (TT_Face)ttface;
+    TT_Face  ttface = (TT_Face)face;
 
 
     /* XXX: TODO: check for sbits */
@@ -235,8 +240,8 @@
     {
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
       /* no fast retrieval for blended MM fonts without VVAR table */
-      if ( ( FT_IS_NAMED_INSTANCE( ttface ) || FT_IS_VARIATION( ttface ) ) &&
-           !( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE )        )
+      if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
+           !( ttface->variation_support & TT_FACE_FLAG_VAR_VADVANCE )  )
         return FT_THROW( Unimplemented_Feature );
 #endif
 
@@ -247,7 +252,7 @@
 
 
         /* since we don't need `tsb', we use zero for `yMax' parameter */
-        TT_Get_VMetrics( face, start + nn, 0, &tsb, &ah );
+        TT_Get_VMetrics( ttface, start + nn, 0, &tsb, &ah );
         advances[nn] = ah;
       }
     }
@@ -255,8 +260,8 @@
     {
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
       /* no fast retrieval for blended MM fonts without HVAR table */
-      if ( ( FT_IS_NAMED_INSTANCE( ttface ) || FT_IS_VARIATION( ttface ) ) &&
-           !( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE )        )
+      if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
+           !( ttface->variation_support & TT_FACE_FLAG_VAR_HADVANCE )  )
         return FT_THROW( Unimplemented_Feature );
 #endif
 
@@ -266,7 +271,7 @@
         FT_UShort  aw;
 
 
-        TT_Get_HMetrics( face, start + nn, &lsb, &aw );
+        TT_Get_HMetrics( ttface, start + nn, &lsb, &aw );
         advances[nn] = aw;
       }
     }
@@ -290,7 +295,7 @@
 
 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
 
-  static FT_Error
+  FT_CALLBACK_DEF( FT_Error )
   tt_size_select( FT_Size   size,
                   FT_ULong  strike_index )
   {
@@ -306,7 +311,7 @@
       /* use the scaled metrics, even when tt_size_reset fails */
       FT_Select_Metrics( size->face, strike_index );
 
-      tt_size_reset( ttsize, 0 ); /* ignore return value */
+      tt_size_reset( ttsize ); /* ignore return value */
     }
     else
     {
@@ -327,7 +332,7 @@
 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
 
 
-  static FT_Error
+  FT_CALLBACK_DEF( FT_Error )
   tt_size_request( FT_Size          size,
                    FT_Size_Request  req )
   {
@@ -367,7 +372,7 @@
 
     if ( FT_IS_SCALABLE( size->face ) )
     {
-      error = tt_size_reset( ttsize, 0 );
+      error = tt_size_reset( ttsize );
 
 #ifdef TT_USE_BYTECODE_INTERPRETER
       /* for the `MPS' bytecode instruction we need the point size */
@@ -426,15 +431,15 @@
    * @Return:
    *   FreeType error code.  0 means success.
    */
-  static FT_Error
-  tt_glyph_load( FT_GlyphSlot  ttslot,      /* TT_GlyphSlot */
-                 FT_Size       ttsize,      /* TT_Size      */
+  FT_CALLBACK_DEF( FT_Error )
+  tt_glyph_load( FT_GlyphSlot  slot,        /* TT_GlyphSlot */
+                 FT_Size       size,        /* TT_Size      */
                  FT_UInt       glyph_index,
                  FT_Int32      load_flags )
   {
-    TT_GlyphSlot  slot = (TT_GlyphSlot)ttslot;
-    TT_Size       size = (TT_Size)ttsize;
-    FT_Face       face = ttslot->face;
+    TT_GlyphSlot  ttslot = (TT_GlyphSlot)slot;
+    TT_Size       ttsize = (TT_Size)size;
+    FT_Face       face   = ttslot->face;
     FT_Error      error;
 
 
@@ -476,12 +481,12 @@
     }
 
     /* use hinted metrics only if we load a glyph with hinting */
-    size->metrics = ( load_flags & FT_LOAD_NO_HINTING )
-                      ? &ttsize->metrics
-                      : &size->hinted_metrics;
+    ttsize->metrics = ( load_flags & FT_LOAD_NO_HINTING )
+                        ? &size->metrics
+                        : &ttsize->hinted_metrics;
 
     /* now fill in the glyph slot with outline/bitmap/layered */
-    error = TT_Load_Glyph( size, slot, glyph_index, load_flags );
+    error = TT_Load_Glyph( ttsize, ttslot, glyph_index, load_flags );
 
     /* force drop-out mode to 2 - irrelevant now */
     /* slot->outline.dropout_mode = 2; */
@@ -507,49 +512,47 @@
   FT_DEFINE_SERVICE_MULTIMASTERSREC(
     tt_service_gx_multi_masters,
 
-    (FT_Get_MM_Func)        NULL,                  /* get_mm                    */
-    (FT_Set_MM_Design_Func) NULL,                  /* set_mm_design             */
-    (FT_Set_MM_Blend_Func)  TT_Set_MM_Blend,       /* set_mm_blend              */
-    (FT_Get_MM_Blend_Func)  TT_Get_MM_Blend,       /* get_mm_blend              */
-    (FT_Get_MM_Var_Func)    TT_Get_MM_Var,         /* get_mm_var                */
-    (FT_Set_Var_Design_Func)TT_Set_Var_Design,     /* set_var_design            */
-    (FT_Get_Var_Design_Func)TT_Get_Var_Design,     /* get_var_design            */
-    (FT_Set_Instance_Func)  TT_Set_Named_Instance, /* set_instance              */
-    (FT_Set_MM_WeightVector_Func)
-                            NULL,                  /* set_mm_weightvector       */
-    (FT_Get_MM_WeightVector_Func)
-                            NULL,                  /* get_mm_weightvector       */
-    (FT_Var_Load_Delta_Set_Idx_Map_Func)
-                            tt_var_load_delta_set_index_mapping,
-                                                   /* load_delta_set_idx_map    */
-    (FT_Var_Load_Item_Var_Store_Func)
-                            tt_var_load_item_variation_store,
-                                                   /* load_item_variation_store */
-    (FT_Var_Get_Item_Delta_Func)
-                            tt_var_get_item_delta, /* get_item_delta            */
-    (FT_Var_Done_Item_Var_Store_Func)
-                            tt_var_done_item_variation_store,
-                                                   /* done_item_variation_store */
-    (FT_Var_Done_Delta_Set_Idx_Map_Func)
-                            tt_var_done_delta_set_index_map,
-                                                   /* done_delta_set_index_map  */
-    (FT_Get_Var_Blend_Func) tt_get_var_blend,      /* get_var_blend             */
-    (FT_Done_Blend_Func)    tt_done_blend          /* done_blend                */
+    NULL,                  /* FT_Get_MM_Func              get_mm                     */
+    NULL,                  /* FT_Set_MM_Design_Func       set_mm_design              */
+    TT_Set_MM_Blend,       /* FT_Set_MM_Blend_Func        set_mm_blend               */
+    TT_Get_MM_Blend,       /* FT_Get_MM_Blend_Func        get_mm_blend               */
+    TT_Get_MM_Var,         /* FT_Get_MM_Var_Func          get_mm_var                 */
+    TT_Set_Var_Design,     /* FT_Set_Var_Design_Func      set_var_design             */
+    TT_Get_Var_Design,     /* FT_Get_Var_Design_Func      get_var_design             */
+    TT_Set_Named_Instance, /* FT_Set_Named_Instance_Func  set_named_instance         */
+    TT_Get_Default_Named_Instance,
+                    /* FT_Get_Default_Named_Instance_Func get_default_named_instance */
+    NULL,                  /* FT_Set_MM_WeightVector_Func set_mm_weightvector        */
+    NULL,                  /* FT_Get_MM_WeightVector_Func get_mm_weightvector        */
+
+    tt_construct_ps_name,  /* FT_Construct_PS_Name_Func   construct_ps_name          */
+    tt_var_load_delta_set_index_mapping,
+                    /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map     */
+    tt_var_load_item_variation_store,
+                    /* FT_Var_Load_Item_Var_Store_Func    load_item_variation_store  */
+    tt_var_get_item_delta, /* FT_Var_Get_Item_Delta_Func  get_item_delta             */
+    tt_var_done_item_variation_store,
+                    /* FT_Var_Done_Item_Var_Store_Func    done_item_variation_store  */
+    tt_var_done_delta_set_index_map,
+                    /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map   */
+    tt_get_var_blend,      /* FT_Get_Var_Blend_Func       get_var_blend              */
+    tt_done_blend          /* FT_Done_Blend_Func          done_blend                 */
   )
 
   FT_DEFINE_SERVICE_METRICSVARIATIONSREC(
     tt_service_metrics_variations,
 
-    (FT_HAdvance_Adjust_Func)tt_hadvance_adjust,     /* hadvance_adjust */
-    (FT_LSB_Adjust_Func)     NULL,                   /* lsb_adjust      */
-    (FT_RSB_Adjust_Func)     NULL,                   /* rsb_adjust      */
+    tt_hadvance_adjust,   /* FT_HAdvance_Adjust_Func hadvance_adjust */
+    NULL,                 /* FT_LSB_Adjust_Func      lsb_adjust      */
+    NULL,                 /* FT_RSB_Adjust_Func      rsb_adjust      */
 
-    (FT_VAdvance_Adjust_Func)tt_vadvance_adjust,     /* vadvance_adjust */
-    (FT_TSB_Adjust_Func)     NULL,                   /* tsb_adjust      */
-    (FT_BSB_Adjust_Func)     NULL,                   /* bsb_adjust      */
-    (FT_VOrg_Adjust_Func)    NULL,                   /* vorg_adjust     */
+    tt_vadvance_adjust,   /* FT_VAdvance_Adjust_Func vadvance_adjust */
+    NULL,                 /* FT_TSB_Adjust_Func      tsb_adjust      */
+    NULL,                 /* FT_BSB_Adjust_Func      bsb_adjust      */
+    NULL,                 /* FT_VOrg_Adjust_Func     vorg_adjust     */
 
-    (FT_Metrics_Adjust_Func) tt_apply_mvar           /* metrics_adjust  */
+    tt_apply_mvar,        /* FT_Metrics_Adjust_Func  metrics_adjust  */
+    tt_size_reset_height  /* FT_Size_Reset_Func      size_reset      */
   )
 
 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c
index d33bdad642793..dc427e8a1160a 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c
@@ -35,7 +35,6 @@
 #endif
 
 #include "tterrors.h"
-#include "ttsubpix.h"
 
 
   /**************************************************************************
@@ -152,9 +151,6 @@
                   FT_UInt    glyph_index )
   {
     TT_Face    face   = loader->face;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
-#endif
 
     FT_Error   error;
     FT_Stream  stream = loader->stream;
@@ -183,20 +179,6 @@
     loader->top_bearing  = top_bearing;
     loader->vadvance     = advance_height;
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 &&
-         loader->exec                                             )
-    {
-      loader->exec->sph_tweak_flags = 0;
-
-      /* This may not be the right place for this, but it works...  */
-      /* Note that we have to unconditionally load the tweaks since */
-      /* it is possible that glyphs individually switch ClearType's */
-      /* backward compatibility mode on and off.                    */
-      sph_set_tweaks( loader, glyph_index );
-    }
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
 #ifdef FT_CONFIG_OPTION_INCREMENTAL
     /* With the incremental interface, these values are set by  */
     /* a call to `tt_get_metrics_incremental'.                  */
@@ -362,17 +344,16 @@
     FT_Byte*        p          = load->cursor;
     FT_Byte*        limit      = load->limit;
     FT_GlyphLoader  gloader    = load->gloader;
+    FT_Outline*     outline    = &gloader->current.outline;
     FT_Int          n_contours = load->n_contours;
-    FT_Outline*     outline;
-    FT_UShort       n_ins;
     FT_Int          n_points;
+    FT_UShort       n_ins;
 
     FT_Byte         *flag, *flag_limit;
     FT_Byte         c, count;
     FT_Vector       *vec, *vec_limit;
     FT_Pos          x, y;
-    FT_Short        *cont, *cont_limit, prev_cont;
-    FT_Int          xy_size = 0;
+    FT_Short        *cont, *cont_limit, last;
 
 
     /* check that we can add the contours to the glyph */
@@ -380,41 +361,27 @@
     if ( error )
       goto Fail;
 
-    /* reading the contours' endpoints & number of points */
-    cont       = gloader->current.outline.contours;
-    cont_limit = cont + n_contours;
-
     /* check space for contours array + instructions count */
-    if ( n_contours >= 0xFFF || p + ( n_contours + 1 ) * 2 > limit )
+    if ( n_contours >= 0xFFF || p + 2 * n_contours + 2 > limit )
       goto Invalid_Outline;
 
-    prev_cont = FT_NEXT_SHORT( p );
-
-    if ( n_contours > 0 )
-      cont[0] = prev_cont;
-
-    if ( prev_cont < 0 )
-      goto Invalid_Outline;
+    /* reading the contours' endpoints & number of points */
+    cont       = outline->contours;
+    cont_limit = cont + n_contours;
 
-    for ( cont++; cont < cont_limit; cont++ )
+    last = -1;
+    for ( ; cont < cont_limit; cont++ )
     {
-      cont[0] = FT_NEXT_SHORT( p );
-      if ( cont[0] <= prev_cont )
-      {
-        /* unordered contours: this is invalid */
-        goto Invalid_Outline;
-      }
-      prev_cont = cont[0];
-    }
+      *cont = FT_NEXT_SHORT( p );
 
-    n_points = 0;
-    if ( n_contours > 0 )
-    {
-      n_points = cont[-1] + 1;
-      if ( n_points < 0 )
+      if ( *cont <= last )
         goto Invalid_Outline;
+
+      last = *cont;
     }
 
+    n_points = last + 1;
+
     FT_TRACE5(( "  # of points: %d\n", n_points ));
 
     /* note that we will add four phantom points later */
@@ -422,59 +389,48 @@
     if ( error )
       goto Fail;
 
-    /* reading the bytecode instructions */
-    load->glyph->control_len  = 0;
-    load->glyph->control_data = NULL;
-
-    if ( p + 2 > limit )
-      goto Invalid_Outline;
-
+    /* space checked above */
     n_ins = FT_NEXT_USHORT( p );
 
     FT_TRACE5(( "  Instructions size: %u\n", n_ins ));
 
+    /* check instructions size */
+    if ( p + n_ins > limit )
+    {
+      FT_TRACE1(( "TT_Load_Simple_Glyph: excessive instruction count\n" ));
+      error = FT_THROW( Too_Many_Hints );
+      goto Fail;
+    }
+
 #ifdef TT_USE_BYTECODE_INTERPRETER
 
     if ( IS_HINTED( load->load_flags ) )
     {
-      FT_ULong  tmp;
+      TT_ExecContext  exec = load->exec;
+      FT_Memory       memory = exec->memory;
 
 
-      /* check instructions size */
-      if ( ( limit - p ) < n_ins )
-      {
-        FT_TRACE1(( "TT_Load_Simple_Glyph: instruction count mismatch\n" ));
-        error = FT_THROW( Too_Many_Hints );
-        goto Fail;
-      }
+      if ( exec->glyphSize )
+        FT_FREE( exec->glyphIns );
+      exec->glyphSize = 0;
 
       /* we don't trust `maxSizeOfInstructions' in the `maxp' table */
-      /* and thus update the bytecode array size by ourselves       */
-
-      tmp   = load->exec->glyphSize;
-      error = Update_Max( load->exec->memory,
-                          &tmp,
-                          sizeof ( FT_Byte ),
-                          (void*)&load->exec->glyphIns,
-                          n_ins );
-
-      load->exec->glyphSize = (FT_UInt)tmp;
-      if ( error )
-        return error;
+      /* and thus allocate the bytecode array size by ourselves     */
+      if ( n_ins )
+      {
+        if ( FT_QNEW_ARRAY( exec->glyphIns, n_ins ) )
+          return error;
 
-      load->glyph->control_len  = n_ins;
-      load->glyph->control_data = load->exec->glyphIns;
+        FT_MEM_COPY( exec->glyphIns, p, (FT_Long)n_ins );
 
-      if ( n_ins )
-        FT_MEM_COPY( load->exec->glyphIns, p, (FT_Long)n_ins );
+        exec->glyphSize  = n_ins;
+      }
     }
 
 #endif /* TT_USE_BYTECODE_INTERPRETER */
 
     p += n_ins;
 
-    outline = &gloader->current.outline;
-
     /* reading the point tags */
     flag       = (FT_Byte*)outline->tags;
     flag_limit = flag + n_points;
@@ -512,9 +468,6 @@
     flag      = (FT_Byte*)outline->tags;
     x         = 0;
 
-    if ( p + xy_size > limit )
-      goto Invalid_Outline;
-
     for ( ; vec < vec_limit; vec++, flag++ )
     {
       FT_Pos   delta = 0;
@@ -544,7 +497,7 @@
 
     /* reading the Y coordinates */
 
-    vec       = gloader->current.outline.points;
+    vec       = outline->points;
     vec_limit = vec + n_points;
     flag      = (FT_Byte*)outline->tags;
     y         = 0;
@@ -827,8 +780,7 @@
   TT_Hint_Glyph( TT_Loader  loader,
                  FT_Bool    is_composite )
   {
-#if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \
-    defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
+#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
     TT_Face    face   = loader->face;
     TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
 #endif
@@ -836,35 +788,34 @@
     TT_GlyphZone  zone = &loader->zone;
 
 #ifdef TT_USE_BYTECODE_INTERPRETER
-    FT_Long       n_ins;
+    TT_ExecContext  exec  = loader->exec;
+    FT_Long         n_ins = exec->glyphSize;
 #else
     FT_UNUSED( is_composite );
 #endif
 
 
 #ifdef TT_USE_BYTECODE_INTERPRETER
-    n_ins = loader->glyph->control_len;
-
     /* save original point positions in `org' array */
     if ( n_ins > 0 )
       FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points );
 
     /* Reset graphics state. */
-    loader->exec->GS = loader->size->GS;
+    exec->GS = loader->size->GS;
 
     /* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */
     /*      completely refer to the (already) hinted subglyphs.     */
     if ( is_composite )
     {
-      loader->exec->metrics.x_scale = 1 << 16;
-      loader->exec->metrics.y_scale = 1 << 16;
+      exec->metrics.x_scale = 1 << 16;
+      exec->metrics.y_scale = 1 << 16;
 
       FT_ARRAY_COPY( zone->orus, zone->cur, zone->n_points );
     }
     else
     {
-      loader->exec->metrics.x_scale = loader->size->metrics->x_scale;
-      loader->exec->metrics.y_scale = loader->size->metrics->y_scale;
+      exec->metrics.x_scale = loader->size->metrics->x_scale;
+      exec->metrics.y_scale = loader->size->metrics->y_scale;
     }
 #endif
 
@@ -884,53 +835,37 @@
     {
       FT_Error  error;
 
-      FT_GlyphLoader  gloader         = loader->gloader;
-      FT_Outline      current_outline = gloader->current.outline;
-
 
-      TT_Set_CodeRange( loader->exec, tt_coderange_glyph,
-                        loader->exec->glyphIns, n_ins );
+      TT_Set_CodeRange( exec, tt_coderange_glyph, exec->glyphIns, n_ins );
 
-      loader->exec->is_composite = is_composite;
-      loader->exec->pts          = *zone;
+      exec->is_composite = is_composite;
+      exec->pts          = *zone;
 
-      error = TT_Run_Context( loader->exec );
-      if ( error && loader->exec->pedantic_hinting )
+      error = TT_Run_Context( exec );
+      if ( error && exec->pedantic_hinting )
         return error;
 
       /* store drop-out mode in bits 5-7; set bit 2 also as a marker */
-      current_outline.tags[0] |=
-        ( loader->exec->GS.scan_type << 5 ) | FT_CURVE_TAG_HAS_SCANMODE;
+      loader->gloader->current.outline.tags[0] |=
+        ( exec->GS.scan_type << 5 ) | FT_CURVE_TAG_HAS_SCANMODE;
     }
 
 #endif
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
     /* Save possibly modified glyph phantom points unless in v40 backward  */
     /* compatibility mode, where no movement on the x axis means no reason */
     /* to change bearings or advance widths.                               */
-    if ( !( driver->interpreter_version == TT_INTERPRETER_VERSION_40 &&
-            loader->exec->backward_compatibility ) )
-    {
-#endif
-      loader->pp1 = zone->cur[zone->n_points - 4];
-      loader->pp2 = zone->cur[zone->n_points - 3];
-      loader->pp3 = zone->cur[zone->n_points - 2];
-      loader->pp4 = zone->cur[zone->n_points - 1];
+
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-    }
+    if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 &&
+         exec->backward_compatibility )
+      return FT_Err_Ok;
 #endif
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
-    {
-      if ( loader->exec->sph_tweak_flags & SPH_TWEAK_DEEMBOLDEN )
-        FT_Outline_EmboldenXY( &loader->gloader->current.outline, -24, 0 );
-
-      else if ( loader->exec->sph_tweak_flags & SPH_TWEAK_EMBOLDEN )
-        FT_Outline_EmboldenXY( &loader->gloader->current.outline, 24, 0 );
-    }
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
+    loader->pp1 = zone->cur[zone->n_points - 4];
+    loader->pp2 = zone->cur[zone->n_points - 3];
+    loader->pp3 = zone->cur[zone->n_points - 2];
+    loader->pp4 = zone->cur[zone->n_points - 1];
 
     return FT_Err_Ok;
   }
@@ -949,10 +884,10 @@
   static FT_Error
   TT_Process_Simple_Glyph( TT_Loader  loader )
   {
-    FT_GlyphLoader  gloader = loader->gloader;
-    FT_Error        error   = FT_Err_Ok;
-    FT_Outline*     outline;
-    FT_Int          n_points;
+    FT_Error        error    = FT_Err_Ok;
+    FT_GlyphLoader  gloader  = loader->gloader;
+    FT_Outline*     outline  = &gloader->current.outline;
+    FT_Int          n_points = outline->n_points;
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
     FT_Memory   memory    = loader->face->root.memory;
@@ -960,11 +895,7 @@
 #endif
 
 
-    outline  = &gloader->current.outline;
-    n_points = outline->n_points;
-
     /* set phantom points */
-
     outline->points[n_points    ] = loader->pp1;
     outline->points[n_points + 1] = loader->pp2;
     outline->points[n_points + 2] = loader->pp3;
@@ -976,7 +907,7 @@
 
     if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) )
     {
-      if ( FT_NEW_ARRAY( unrounded, n_points ) )
+      if ( FT_QNEW_ARRAY( unrounded, n_points ) )
         goto Exit;
 
       /* Deltas apply to the unscaled data. */
@@ -998,16 +929,6 @@
     }
 
     {
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      TT_Face    face   = loader->face;
-      TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
-
-      FT_String*  family         = face->root.family_name;
-      FT_UInt     ppem           = loader->size->metrics->x_ppem;
-      FT_String*  style          = face->root.style_name;
-      FT_UInt     x_scale_factor = 1000;
-#endif
-
       FT_Vector*  vec   = outline->points;
       FT_Vector*  limit = outline->points + n_points;
 
@@ -1017,52 +938,6 @@
       FT_Bool  do_scale = FALSE;
 
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
-      if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
-      {
-        /* scale, but only if enabled and only if TT hinting is being used */
-        if ( IS_HINTED( loader->load_flags ) )
-          x_scale_factor = sph_test_tweak_x_scaling( face,
-                                                     family,
-                                                     ppem,
-                                                     style,
-                                                     loader->glyph_index );
-        /* scale the glyph */
-        if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ||
-             x_scale_factor != 1000                         )
-        {
-          x_scale = FT_MulDiv( loader->size->metrics->x_scale,
-                               (FT_Long)x_scale_factor, 1000 );
-          y_scale = loader->size->metrics->y_scale;
-
-          /* compensate for any scaling by de/emboldening; */
-          /* the amount was determined via experimentation */
-          if ( x_scale_factor != 1000 && ppem > 11 )
-          {
-#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-            FT_Vector*  orig_points = outline->points;
-
-
-            if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) )
-              outline->points = unrounded;
-#endif
-            FT_Outline_EmboldenXY( outline,
-                                   FT_MulFix( 1280 * ppem,
-                                              1000 - x_scale_factor ),
-                                   0 );
-#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-            if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) )
-              outline->points = orig_points;
-#endif
-          }
-          do_scale = TRUE;
-        }
-      }
-      else
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
       {
         /* scale the glyph */
         if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
@@ -1331,12 +1206,12 @@
                               FT_UInt    start_contour )
   {
     FT_Error     error;
-    FT_Outline*  outline;
+    FT_Outline*  outline = &loader->gloader->base.outline;
+    FT_Stream    stream = loader->stream;
+    FT_UShort    n_ins;
     FT_UInt      i;
 
 
-    outline = &loader->gloader->base.outline;
-
     /* make room for phantom points */
     error = FT_GLYPHLOADER_CHECK_POINTS( loader->gloader,
                                          outline->n_points + 4,
@@ -1352,10 +1227,13 @@
 #ifdef TT_USE_BYTECODE_INTERPRETER
 
     {
-      FT_Stream  stream = loader->stream;
-      FT_UShort  n_ins, max_ins;
-      FT_ULong   tmp;
+      TT_ExecContext  exec = loader->exec;
+      FT_Memory       memory = exec->memory;
+
 
+      if ( exec->glyphSize )
+        FT_FREE( exec->glyphIns );
+      exec->glyphSize = 0;
 
       /* TT_Load_Composite_Glyph only gives us the offset of instructions */
       /* so we read them here                                             */
@@ -1365,39 +1243,24 @@
 
       FT_TRACE5(( "  Instructions size = %hu\n", n_ins ));
 
-      /* check it */
-      max_ins = loader->face->max_profile.maxSizeOfInstructions;
-      if ( n_ins > max_ins )
-      {
-        /* don't trust `maxSizeOfInstructions'; */
-        /* only do a rough safety check         */
-        if ( n_ins > loader->byte_len )
-        {
-          FT_TRACE1(( "TT_Process_Composite_Glyph:"
-                      " too many instructions (%hu) for glyph with length %u\n",
-                      n_ins, loader->byte_len ));
-          return FT_THROW( Too_Many_Hints );
-        }
-
-        tmp   = loader->exec->glyphSize;
-        error = Update_Max( loader->exec->memory,
-                            &tmp,
-                            sizeof ( FT_Byte ),
-                            (void*)&loader->exec->glyphIns,
-                            n_ins );
+      if ( !n_ins )
+        return FT_Err_Ok;
 
-        loader->exec->glyphSize = (FT_UShort)tmp;
-        if ( error )
-          return error;
+      /* don't trust `maxSizeOfInstructions'; */
+      /* only do a rough safety check         */
+      if ( n_ins > loader->byte_len )
+      {
+        FT_TRACE1(( "TT_Process_Composite_Glyph:"
+                    " too many instructions (%hu) for glyph with length %u\n",
+                    n_ins, loader->byte_len ));
+        return FT_THROW( Too_Many_Hints );
       }
-      else if ( n_ins == 0 )
-        return FT_Err_Ok;
 
-      if ( FT_STREAM_READ( loader->exec->glyphIns, n_ins ) )
+      if ( FT_QNEW_ARRAY( exec->glyphIns, n_ins )  ||
+           FT_STREAM_READ( exec->glyphIns, n_ins ) )
         return error;
 
-      loader->glyph->control_data = loader->exec->glyphIns;
-      loader->glyph->control_len  = n_ins;
+      exec->glyphSize = n_ins;
     }
 
 #endif
@@ -1501,45 +1364,31 @@
   static void
   tt_loader_set_pp( TT_Loader  loader )
   {
-    FT_Bool  subpixel_hinting = 0;
-    FT_Bool  grayscale        = 0;
-    FT_Bool  use_aw_2         = 0;
-
-#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( loader->face );
-#endif
-
-
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
-    {
-      subpixel_hinting = loader->exec ? loader->exec->subpixel_hinting
-                                      : 0;
-      grayscale        = loader->exec ? loader->exec->grayscale
-                                      : 0;
-    }
-#endif
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-    if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
-    {
-      subpixel_hinting = loader->exec ? loader->exec->subpixel_hinting_lean
-                                      : 0;
-      grayscale        = loader->exec ? loader->exec->grayscale_cleartype
-                                      : 0;
-    }
-#endif
-
-    use_aw_2 = FT_BOOL( subpixel_hinting && grayscale );
-
     loader->pp1.x = loader->bbox.xMin - loader->left_bearing;
     loader->pp1.y = 0;
     loader->pp2.x = loader->pp1.x + loader->advance;
     loader->pp2.y = 0;
 
-    loader->pp3.x = use_aw_2 ? loader->advance / 2 : 0;
+    loader->pp3.x = 0;
     loader->pp3.y = loader->bbox.yMax + loader->top_bearing;
-    loader->pp4.x = use_aw_2 ? loader->advance / 2 : 0;
+    loader->pp4.x = 0;
     loader->pp4.y = loader->pp3.y - loader->vadvance;
+
+#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
+    {
+      TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( loader->face );
+
+
+      if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 &&
+           loader->exec                                             &&
+           loader->exec->subpixel_hinting_lean                      &&
+           loader->exec->grayscale_cleartype                        )
+      {
+        loader->pp3.x = loader->advance / 2;
+        loader->pp4.x = loader->advance / 2;
+      }
+    }
+#endif
   }
 
 
@@ -1662,8 +1511,14 @@
     else
 
 #endif /* FT_CONFIG_OPTION_INCREMENTAL */
+    {
+      FT_ULong  len;
+
 
-      offset = tt_face_get_location( face, glyph_index, &loader->byte_len );
+      offset = tt_face_get_location( FT_FACE( face ), glyph_index, &len );
+
+      loader->byte_len = (FT_UInt)len;
+    }
 
     if ( loader->byte_len > 0 )
     {
@@ -1889,10 +1744,7 @@
         short        i, limit;
         FT_SubGlyph  subglyph;
 
-        FT_Outline  outline;
-        FT_Vector*  points    = NULL;
-        char*       tags      = NULL;
-        short*      contours  = NULL;
+        FT_Outline  outline = { 0, 0, NULL, NULL, NULL, 0 };
         FT_Vector*  unrounded = NULL;
 
 
@@ -1900,18 +1752,14 @@
 
         /* construct an outline structure for              */
         /* communication with `TT_Vary_Apply_Glyph_Deltas' */
-        outline.n_contours = outline.n_points = limit;
-
-        outline.points   = NULL;
-        outline.tags     = NULL;
-        outline.contours = NULL;
-
-        if ( FT_NEW_ARRAY( points, limit + 4 )    ||
-             FT_NEW_ARRAY( tags, limit + 4 )      ||
-             FT_NEW_ARRAY( contours, limit + 4 )  ||
-             FT_NEW_ARRAY( unrounded, limit + 4 ) )
+        if ( FT_QNEW_ARRAY( outline.points, limit + 4 ) ||
+             FT_QNEW_ARRAY( outline.tags, limit )       ||
+             FT_QNEW_ARRAY( outline.contours, limit )   ||
+             FT_QNEW_ARRAY( unrounded, limit + 4 )      )
           goto Exit1;
 
+        outline.n_contours = outline.n_points = limit;
+
         subglyph = gloader->current.subglyphs;
 
         for ( i = 0; i < limit; i++, subglyph++ )
@@ -1919,20 +1767,16 @@
           /* applying deltas for anchor points doesn't make sense, */
           /* but we don't have to specially check this since       */
           /* unused delta values are zero anyways                  */
-          points[i].x = subglyph->arg1;
-          points[i].y = subglyph->arg2;
-          tags[i]     = 1;
-          contours[i] = i;
+          outline.points[i].x = subglyph->arg1;
+          outline.points[i].y = subglyph->arg2;
+          outline.tags[i]     = ON_CURVE_POINT;
+          outline.contours[i] = i;
         }
 
-        points[i++] = loader->pp1;
-        points[i++] = loader->pp2;
-        points[i++] = loader->pp3;
-        points[i  ] = loader->pp4;
-
-        outline.points   = points;
-        outline.tags     = tags;
-        outline.contours = contours;
+        outline.points[i++] = loader->pp1;
+        outline.points[i++] = loader->pp2;
+        outline.points[i++] = loader->pp3;
+        outline.points[i  ] = loader->pp4;
 
         /* this call provides additional offsets */
         /* for each component's translation      */
@@ -1947,8 +1791,8 @@
         {
           if ( subglyph->flags & ARGS_ARE_XY_VALUES )
           {
-            subglyph->arg1 = (FT_Int16)points[i].x;
-            subglyph->arg2 = (FT_Int16)points[i].y;
+            subglyph->arg1 = (FT_Int16)outline.points[i].x;
+            subglyph->arg2 = (FT_Int16)outline.points[i].y;
           }
         }
 
@@ -2332,8 +2176,7 @@
 #ifdef TT_USE_BYTECODE_INTERPRETER
     FT_Error   error;
     FT_Bool    pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC );
-#if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \
-    defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
+#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
     TT_Driver  driver   = (TT_Driver)FT_FACE_DRIVER( glyph->face );
 #endif
 #endif
@@ -2353,20 +2196,6 @@
       FT_Bool         grayscale_cleartype;
 #endif
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      FT_Bool  subpixel_hinting = FALSE;
-
-#if 0
-      /* not used yet */
-      FT_Bool  compatible_widths;
-      FT_Bool  symmetrical_smoothing;
-      FT_Bool  bgr;
-      FT_Bool  vertical_lcd;
-      FT_Bool  subpixel_positioned;
-      FT_Bool  gray_cleartype;
-#endif
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
       FT_Bool  reexecute = FALSE;
 
 
@@ -2386,6 +2215,9 @@
       if ( !exec )
         return FT_THROW( Could_Not_Find_Context );
 
+      grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
+                             FT_RENDER_MODE_MONO             );
+
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
       if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
       {
@@ -2402,6 +2234,7 @@
           FT_BOOL( subpixel_hinting_lean    &&
                    ( load_flags           &
                      FT_LOAD_TARGET_LCD_V ) );
+        grayscale = FT_BOOL( grayscale && !subpixel_hinting_lean );
       }
       else
       {
@@ -2411,111 +2244,11 @@
       }
 #endif
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
-      if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
-      {
-        subpixel_hinting = FT_BOOL( ( FT_LOAD_TARGET_MODE( load_flags ) !=
-                                      FT_RENDER_MODE_MONO               )  &&
-                                    SPH_OPTION_SET_SUBPIXEL                );
-
-        if ( subpixel_hinting )
-          grayscale = FALSE;
-        else if ( SPH_OPTION_SET_GRAYSCALE )
-        {
-          grayscale        = TRUE;
-          subpixel_hinting = FALSE;
-        }
-        else
-          grayscale = FALSE;
-
-        if ( FT_IS_TRICKY( glyph->face ) )
-          subpixel_hinting = FALSE;
-
-        exec->ignore_x_mode      = subpixel_hinting || grayscale;
-        exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
-        if ( exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 )
-          exec->rasterizer_version = TT_INTERPRETER_VERSION_35;
-
-#if 1
-        exec->compatible_widths     = SPH_OPTION_SET_COMPATIBLE_WIDTHS;
-        exec->symmetrical_smoothing = TRUE;
-        exec->bgr                   = FALSE;
-        exec->vertical_lcd          = FALSE;
-        exec->subpixel_positioned   = TRUE;
-        exec->gray_cleartype        = FALSE;
-#else /* 0 */
-        exec->compatible_widths =
-          FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
-                   TT_LOAD_COMPATIBLE_WIDTHS );
-        exec->symmetrical_smoothing =
-          FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
-                   TT_LOAD_SYMMETRICAL_SMOOTHING );
-        exec->bgr =
-          FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
-                   TT_LOAD_BGR );
-        exec->vertical_lcd =
-          FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
-                   TT_LOAD_VERTICAL_LCD );
-        exec->subpixel_positioned =
-          FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
-                   TT_LOAD_SUBPIXEL_POSITIONED );
-        exec->gray_cleartype =
-          FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
-                   TT_LOAD_GRAY_CLEARTYPE );
-#endif /* 0 */
-
-      }
-      else
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-      if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
-        grayscale = FT_BOOL( !subpixel_hinting_lean               &&
-                             FT_LOAD_TARGET_MODE( load_flags ) !=
-                               FT_RENDER_MODE_MONO                );
-      else
-#endif
-        grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
-                               FT_RENDER_MODE_MONO             );
-
       error = TT_Load_Context( exec, face, size );
       if ( error )
         return error;
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
-      if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
-      {
-        /* a change from mono to subpixel rendering (and vice versa) */
-        /* requires a re-execution of the CVT program                */
-        if ( subpixel_hinting != exec->subpixel_hinting )
-        {
-          FT_TRACE4(( "tt_loader_init: subpixel hinting change,"
-                      " re-executing `prep' table\n" ));
-
-          exec->subpixel_hinting = subpixel_hinting;
-          reexecute              = TRUE;
-        }
-
-        /* a change from mono to grayscale rendering (and vice versa) */
-        /* requires a re-execution of the CVT program                 */
-        if ( grayscale != exec->grayscale )
-        {
-          FT_TRACE4(( "tt_loader_init: grayscale hinting change,"
-                      " re-executing `prep' table\n" ));
-
-          exec->grayscale = grayscale;
-          reexecute       = TRUE;
-        }
-      }
-      else
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
       {
-
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
         if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
         {
@@ -2573,14 +2306,6 @@
       if ( exec->GS.instruct_control & 2 )
         exec->GS = tt_default_graphics_state;
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      /* check whether we have a font hinted for ClearType --           */
-      /* note that this flag can also be modified in a glyph's bytecode */
-      if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 &&
-           exec->GS.instruct_control & 4                            )
-        exec->ignore_x_mode = FALSE;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
       /*
        * Toggle backward compatibility according to what font wants, except
@@ -2616,13 +2341,6 @@
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
            !( driver->interpreter_version == TT_INTERPRETER_VERSION_40  &&
               exec->backward_compatibility                              ) &&
-#endif
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-           !( driver->interpreter_version == TT_INTERPRETER_VERSION_38  &&
-              !SPH_OPTION_BITMAP_WIDTHS                                 &&
-              FT_LOAD_TARGET_MODE( loader->load_flags ) !=
-                                                   FT_RENDER_MODE_MONO  &&
-              exec->compatible_widths                                   ) &&
 #endif
            !face->postscript.isFixedPitch                                 )
       {
@@ -2857,7 +2575,9 @@
 #ifdef FT_CONFIG_OPTION_SVG
 
     /* check for OT-SVG */
-    if ( ( load_flags & FT_LOAD_COLOR ) && face->svg )
+    if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 &&
+         ( load_flags & FT_LOAD_COLOR )       &&
+         face->svg                            )
     {
       SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
 
@@ -2955,6 +2675,9 @@
 
       if ( IS_HINTED( load_flags ) )
       {
+        glyph->control_data = loader.exec->glyphIns;
+        glyph->control_len  = loader.exec->glyphSize;
+
         if ( loader.exec->GS.scan_control )
         {
           /* convert scan conversion mode to FT_OUTLINE_XXX flags */
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c
index fc957320c843b..9d149ea365cf1 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c
@@ -45,6 +45,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -465,7 +466,7 @@
     if ( store_offset )
     {
       error = tt_var_load_item_variation_store(
-                face,
+                FT_FACE( face ),
                 table_offset + store_offset,
                 &table->itemStore );
       if ( error )
@@ -475,7 +476,7 @@
     if ( axisMap_offset )
     {
       error = tt_var_load_delta_set_index_mapping(
-                face,
+                FT_FACE( face ),
                 table_offset + axisMap_offset,
                 &table->axisMap,
                 &table->itemStore,
@@ -492,10 +493,11 @@
 
 
   FT_LOCAL_DEF( FT_Error )
-  tt_var_load_item_variation_store( TT_Face          face,
+  tt_var_load_item_variation_store( FT_Face          face,      /* TT_Face */
                                     FT_ULong         offset,
                                     GX_ItemVarStore  itemStore )
   {
+    TT_Face    ttface = (TT_Face)face;
     FT_Stream  stream = FT_FACE_STREAM( face );
     FT_Memory  memory = stream->memory;
 
@@ -507,10 +509,10 @@
     FT_UShort  axis_count;
     FT_UInt    region_count;
 
-    FT_UInt  i, j, k;
+    FT_UInt  i, j;
     FT_Bool  long_words;
 
-    GX_Blend   blend           = face->blend;
+    GX_Blend   blend           = ttface->blend;
     FT_ULong*  dataOffsetArray = NULL;
 
 
@@ -619,9 +621,10 @@
     {
       GX_ItemVarData  varData = &itemStore->varData[i];
 
-      FT_UInt  item_count;
-      FT_UInt  word_delta_count;
-      FT_UInt  region_idx_count;
+      FT_UInt    item_count;
+      FT_UShort  word_delta_count;
+      FT_UInt    region_idx_count;
+      FT_UInt    per_region_size;
 
 
       if ( FT_STREAM_SEEK( offset + dataOffsetArray[i] ) )
@@ -658,6 +661,8 @@
       if ( FT_NEW_ARRAY( varData->regionIndices, region_idx_count ) )
         goto Exit;
       varData->regionIdxCount = region_idx_count;
+      varData->wordDeltaCount = word_delta_count;
+      varData->longWords      = long_words;
 
       for ( j = 0; j < varData->regionIdxCount; j++ )
       {
@@ -673,37 +678,22 @@
         }
       }
 
-      /* Parse delta set.                                                  */
-      /*                                                                   */
-      /* On input, deltas are (word_delta_count + region_idx_count) bytes  */
-      /* each if `long_words` isn't set, and twice as much otherwise.      */
-      /*                                                                   */
-      /* On output, deltas are expanded to `region_idx_count` shorts each. */
-      if ( FT_NEW_ARRAY( varData->deltaSet, item_count * region_idx_count ) )
-        goto Exit;
-      varData->itemCount = item_count;
+      per_region_size = word_delta_count + region_idx_count;
+      if ( long_words )
+        per_region_size *= 2;
 
-      for ( j = 0; j < item_count * region_idx_count; )
+      if ( FT_NEW_ARRAY( varData->deltaSet, per_region_size * item_count ) )
+        goto Exit;
+      if ( FT_Stream_Read( stream,
+                           varData->deltaSet,
+                           per_region_size * item_count ) )
       {
-        if ( long_words )
-        {
-          for ( k = 0; k < word_delta_count; k++, j++ )
-            if ( FT_READ_LONG( varData->deltaSet[j] ) )
-              goto Exit;
-          for ( ; k < region_idx_count; k++, j++ )
-            if ( FT_READ_SHORT( varData->deltaSet[j] ) )
-              goto Exit;
-        }
-        else
-        {
-          for ( k = 0; k < word_delta_count; k++, j++ )
-            if ( FT_READ_SHORT( varData->deltaSet[j] ) )
-              goto Exit;
-          for ( ; k < region_idx_count; k++, j++ )
-            if ( FT_READ_CHAR( varData->deltaSet[j] ) )
-              goto Exit;
-        }
+        FT_TRACE2(( "deltaSet read failed." ));
+        error = FT_THROW( Invalid_Table );
+        goto Exit;
       }
+
+      varData->itemCount = item_count;
     }
 
   Exit:
@@ -714,7 +704,7 @@
 
 
   FT_LOCAL_DEF( FT_Error )
-  tt_var_load_delta_set_index_mapping( TT_Face            face,
+  tt_var_load_delta_set_index_mapping( FT_Face            face, /* TT_Face */
                                        FT_ULong           offset,
                                        GX_DeltaSetIdxMap  map,
                                        GX_ItemVarStore    itemStore,
@@ -941,7 +931,7 @@
     }
 
     error = tt_var_load_item_variation_store(
-              face,
+              FT_FACE( face ),
               table_offset + store_offset,
               &table->itemStore );
     if ( error )
@@ -950,7 +940,7 @@
     if ( widthMap_offset )
     {
       error = tt_var_load_delta_set_index_mapping(
-                face,
+                FT_FACE( face ),
                 table_offset + widthMap_offset,
                 &table->widthMap,
                 &table->itemStore,
@@ -992,24 +982,30 @@
 
 
   FT_LOCAL_DEF( FT_ItemVarDelta )
-  tt_var_get_item_delta( TT_Face          face,
+  tt_var_get_item_delta( FT_Face          face,        /* TT_Face */
                          GX_ItemVarStore  itemStore,
                          FT_UInt          outerIndex,
                          FT_UInt          innerIndex )
   {
+    TT_Face    ttface = (TT_Face)face;
     FT_Stream  stream = FT_FACE_STREAM( face );
     FT_Memory  memory = stream->memory;
     FT_Error   error  = FT_Err_Ok;
 
     GX_ItemVarData    varData;
-    FT_ItemVarDelta*  deltaSet;
+    FT_ItemVarDelta*  deltaSet = NULL;
+    FT_ItemVarDelta   deltaSetStack[16];
+
+    FT_Fixed*  scalars = NULL;
+    FT_Fixed   scalarsStack[16];
 
     FT_UInt          master, j;
-    FT_Fixed*        scalars = NULL;
-    FT_ItemVarDelta  returnValue;
+    FT_ItemVarDelta  returnValue = 0;
+    FT_UInt          per_region_size;
+    FT_Byte*         bytes;
 
 
-    if ( !face->blend || !face->blend->normalizedcoords )
+    if ( !ttface->blend || !ttface->blend->normalizedcoords )
       return 0;
 
     /* OpenType 1.8.4+: No variation data for this item */
@@ -1023,15 +1019,48 @@
     if ( outerIndex >= itemStore->dataCount )
       return 0; /* Out of range. */
 
-    varData  = &itemStore->varData[outerIndex];
-    deltaSet = FT_OFFSET( varData->deltaSet,
-                          varData->regionIdxCount * innerIndex );
+    varData = &itemStore->varData[outerIndex];
 
     if ( innerIndex >= varData->itemCount )
       return 0; /* Out of range. */
 
-    if ( FT_QNEW_ARRAY( scalars, varData->regionIdxCount ) )
-      return 0;
+    if ( varData->regionIdxCount < 16 )
+    {
+      deltaSet = deltaSetStack;
+      scalars  = scalarsStack;
+    }
+    else
+    {
+      if ( FT_QNEW_ARRAY( deltaSet, varData->regionIdxCount ) )
+        goto Exit;
+      if ( FT_QNEW_ARRAY( scalars, varData->regionIdxCount ) )
+        goto Exit;
+    }
+
+    /* Parse delta set.                                            */
+    /*                                                             */
+    /* Deltas are (word_delta_count + region_idx_count) bytes each */
+    /* if `longWords` isn't set, and twice as much otherwise.      */
+    per_region_size = varData->wordDeltaCount + varData->regionIdxCount;
+    if ( varData->longWords )
+      per_region_size *= 2;
+
+    bytes = varData->deltaSet + per_region_size * innerIndex;
+
+    if ( varData->longWords )
+    {
+      for ( master = 0; master < varData->wordDeltaCount; master++ )
+        deltaSet[master] = FT_NEXT_LONG( bytes );
+      for ( ; master < varData->regionIdxCount; master++ )
+        deltaSet[master] = FT_NEXT_SHORT( bytes );
+    }
+    else
+    {
+      for ( master = 0; master < varData->wordDeltaCount; master++ )
+        deltaSet[master] = FT_NEXT_SHORT( bytes );
+      for ( ; master < varData->regionIdxCount; master++ )
+        deltaSet[master] = FT_NEXT_CHAR( bytes );
+    }
 
     /* outer loop steps through master designs to be blended */
     for ( master = 0; master < varData->regionIdxCount; master++ )
@@ -1060,27 +1089,27 @@
         else if ( axis->peakCoord == 0 )
           continue;
 
-        else if ( face->blend->normalizedcoords[j] == axis->peakCoord )
+        else if ( ttface->blend->normalizedcoords[j] == axis->peakCoord )
           continue;
 
         /* ignore this region if coords are out of range */
-        else if ( face->blend->normalizedcoords[j] <= axis->startCoord ||
-                  face->blend->normalizedcoords[j] >= axis->endCoord   )
+        else if ( ttface->blend->normalizedcoords[j] <= axis->startCoord ||
+                  ttface->blend->normalizedcoords[j] >= axis->endCoord   )
         {
           scalar = 0;
           break;
         }
 
         /* cumulative product of all the axis scalars */
-        else if ( face->blend->normalizedcoords[j] < axis->peakCoord )
+        else if ( ttface->blend->normalizedcoords[j] < axis->peakCoord )
           scalar =
             FT_MulDiv( scalar,
-                       face->blend->normalizedcoords[j] - axis->startCoord,
+                       ttface->blend->normalizedcoords[j] - axis->startCoord,
                        axis->peakCoord - axis->startCoord );
         else
           scalar =
             FT_MulDiv( scalar,
-                       axis->endCoord - face->blend->normalizedcoords[j],
+                       axis->endCoord - ttface->blend->normalizedcoords[j],
                        axis->endCoord - axis->peakCoord );
 
       } /* per-axis loop */
@@ -1106,7 +1135,11 @@
      */
     returnValue = FT_MulAddFix( scalars, deltaSet, varData->regionIdxCount );
 
-    FT_FREE( scalars );
+  Exit:
+    if ( scalars != scalarsStack )
+      FT_FREE( scalars );
+    if ( deltaSet != deltaSetStack )
+      FT_FREE( deltaSet );
 
     return returnValue;
   }
@@ -1206,7 +1239,7 @@
       innerIndex = gindex;
     }
 
-    delta = tt_var_get_item_delta( face,
+    delta = tt_var_get_item_delta( FT_FACE( face ),
                                    &table->itemStore,
                                    outerIndex,
                                    innerIndex );
@@ -1229,20 +1262,20 @@
 
 
   FT_LOCAL_DEF( FT_Error )
-  tt_hadvance_adjust( TT_Face  face,
+  tt_hadvance_adjust( FT_Face  face,    /* TT_Face */
                       FT_UInt  gindex,
                       FT_Int  *avalue )
   {
-    return tt_hvadvance_adjust( face, gindex, avalue, 0 );
+    return tt_hvadvance_adjust( (TT_Face)face, gindex, avalue, 0 );
   }
 
 
   FT_LOCAL_DEF( FT_Error )
-  tt_vadvance_adjust( TT_Face  face,
+  tt_vadvance_adjust( FT_Face  face,    /* TT_Face */
                       FT_UInt  gindex,
                       FT_Int  *avalue )
   {
-    return tt_hvadvance_adjust( face, gindex, avalue, 1 );
+    return tt_hvadvance_adjust( (TT_Face)face, gindex, avalue, 1 );
   }
 
 
@@ -1389,7 +1422,7 @@
     records_offset = FT_STREAM_POS();
 
     error = tt_var_load_item_variation_store(
-              face,
+              FT_FACE( face ),
               table_offset + store_offset,
               &blend->mvar_table->itemStore );
     if ( error )
@@ -1462,15 +1495,14 @@
 
 
   static FT_Error
-  tt_size_reset_iterator( FT_ListNode  node,
+  ft_size_reset_iterator( FT_ListNode  node,
                           void*        user )
   {
-    TT_Size  size = (TT_Size)node->data;
-
-    FT_UNUSED( user );
+    FT_Size                       size = (FT_Size)node->data;
+    FT_Service_MetricsVariations  var  = (FT_Service_MetricsVariations)user;
 
 
-    tt_size_reset( size, 1 );
+    var->size_reset( size );
 
     return FT_Err_Ok;
   }
@@ -1489,16 +1521,19 @@
    *     The font face.
    */
   FT_LOCAL_DEF( void )
-  tt_apply_mvar( TT_Face  face )
+  tt_apply_mvar( FT_Face  face )  /* TT_Face */
   {
-    GX_Blend  blend = face->blend;
+    TT_Face  ttface = (TT_Face)face;
+
+    GX_Blend  blend = ttface->blend;
     GX_Value  value, limit;
+
     FT_Short  mvar_hasc_delta = 0;
     FT_Short  mvar_hdsc_delta = 0;
     FT_Short  mvar_hlgp_delta = 0;
 
 
-    if ( !( face->variation_support & TT_FACE_FLAG_VAR_MVAR ) )
+    if ( !( ttface->variation_support & TT_FACE_FLAG_VAR_MVAR ) )
       return;
 
     value = blend->mvar_table->values;
@@ -1506,7 +1541,7 @@
 
     for ( ; value < limit; value++ )
     {
-      FT_Short*  p = ft_var_get_value_pointer( face, value->tag );
+      FT_Short*  p = ft_var_get_value_pointer( ttface, value->tag );
       FT_Int     delta;
 
 
@@ -1543,7 +1578,8 @@
 
     /* adjust all derived values */
     {
-      FT_Face  root = &face->root;
+      FT_Service_MetricsVariations  var =
+        (FT_Service_MetricsVariations)ttface->face_var;
 
       /*
        * Apply the deltas of hasc, hdsc and hlgp to the FT_Face's ascender,
@@ -1571,24 +1607,25 @@
        *    whether they were actually changed or the font had the OS/2 table's
        *    fsSelection's bit 7 (USE_TYPO_METRICS) set.
        */
-      FT_Short  current_line_gap = root->height - root->ascender +
-                                   root->descender;
+      FT_Short  current_line_gap = face->height - face->ascender +
+                                   face->descender;
 
 
-      root->ascender  = root->ascender + mvar_hasc_delta;
-      root->descender = root->descender + mvar_hdsc_delta;
-      root->height    = root->ascender - root->descender +
+      face->ascender  = face->ascender + mvar_hasc_delta;
+      face->descender = face->descender + mvar_hdsc_delta;
+      face->height    = face->ascender - face->descender +
                         current_line_gap + mvar_hlgp_delta;
 
-      root->underline_position  = face->postscript.underlinePosition -
-                                  face->postscript.underlineThickness / 2;
-      root->underline_thickness = face->postscript.underlineThickness;
+      face->underline_position  = ttface->postscript.underlinePosition -
+                                  ttface->postscript.underlineThickness / 2;
+      face->underline_thickness = ttface->postscript.underlineThickness;
 
-      /* iterate over all FT_Size objects and call `tt_size_reset' */
-      /* to propagate the metrics changes                          */
-      FT_List_Iterate( &root->sizes_list,
-                       tt_size_reset_iterator,
-                       NULL );
+      /* iterate over all FT_Size objects and call `var->size_reset' */
+      /* to propagate the metrics changes                            */
+      if ( var && var->size_reset )
+        FT_List_Iterate( &face->sizes_list,
+                         ft_size_reset_iterator,
+                         (void*)var );
     }
   }
 
@@ -2099,7 +2136,7 @@
             innerIndex = table->axisMap.innerIndex[idx];
           }
 
-          delta = tt_var_get_item_delta( face,
+          delta = tt_var_get_item_delta( FT_FACE( face ),
                                          &table->itemStore,
                                          outerIndex,
                                          innerIndex );
@@ -2261,11 +2298,12 @@
    *   FreeType error code.  0 means success.
    */
   FT_LOCAL_DEF( FT_Error )
-  TT_Get_MM_Var( TT_Face      face,
+  TT_Get_MM_Var( FT_Face      face,    /* TT_Face */
                  FT_MM_Var*  *master )
   {
-    FT_Stream            stream     = face->root.stream;
-    FT_Memory            memory     = face->root.memory;
+    TT_Face              ttface     = (TT_Face)face;
+    FT_Stream            stream     = FT_FACE_STREAM( face );
+    FT_Memory            memory     = FT_FACE_MEMORY( face );
     FT_ULong             table_len;
     FT_Error             error      = FT_Err_Ok;
     FT_ULong             fvar_start = 0;
@@ -2329,19 +2367,19 @@
     /* the default instance, which might be missing in the table of named */
     /* instances (in 'fvar').  This value is validated in `sfobjs.c` and  */
     /* may be reset to 0 if consistency checks fail.                      */
-    num_instances = (FT_UInt)face->root.style_flags >> 16;
+    num_instances = (FT_UInt)face->style_flags >> 16;
 
     /* read the font data and set up the internal representation */
     /* if not already done                                       */
 
-    need_init = !face->blend;
+    need_init = !ttface->blend;
 
     if ( need_init )
     {
       FT_TRACE2(( "FVAR " ));
 
-      if ( FT_SET_ERROR( face->goto_table( face, TTAG_fvar,
-                                           stream, &table_len ) ) )
+      if ( FT_SET_ERROR( ttface->goto_table( ttface, TTAG_fvar,
+                                             stream, &table_len ) ) )
       {
         FT_TRACE1(( "is missing\n" ));
         goto Exit;
@@ -2374,14 +2412,14 @@
                   fvar_head.axisCount,
                   fvar_head.axisCount == 1 ? "is" : "es" ));
 
-      if ( FT_NEW( face->blend ) )
+      if ( FT_NEW( ttface->blend ) )
         goto Exit;
 
-      num_axes              = fvar_head.axisCount;
-      face->blend->num_axis = num_axes;
+      num_axes                = fvar_head.axisCount;
+      ttface->blend->num_axis = num_axes;
     }
     else
-      num_axes = face->blend->num_axis;
+      num_axes = ttface->blend->num_axis;
 
     /* prepare storage area for MM data; this cannot overflow   */
     /* 32-bit arithmetic because of the size limits used in the */
@@ -2410,16 +2448,16 @@
 
     if ( need_init )
     {
-      face->blend->mmvar_len = mmvar_size       +
-                               axis_flags_size  +
-                               axis_size        +
-                               namedstyle_size  +
-                               next_coords_size +
-                               next_name_size;
-
-      if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
+      ttface->blend->mmvar_len = mmvar_size       +
+                                 axis_flags_size  +
+                                 axis_size        +
+                                 namedstyle_size  +
+                                 next_coords_size +
+                                 next_name_size;
+
+      if ( FT_ALLOC( mmvar, ttface->blend->mmvar_len ) )
         goto Exit;
-      face->blend->mmvar = mmvar;
+      ttface->blend->mmvar = mmvar;
 
       /* set up pointers and offsets into the `mmvar' array; */
       /* the data gets filled in later on                    */
@@ -2525,27 +2563,27 @@
 
       /* named instance coordinates are stored as design coordinates; */
       /* we have to convert them to normalized coordinates also       */
-      if ( FT_NEW_ARRAY( face->blend->normalized_stylecoords,
+      if ( FT_NEW_ARRAY( ttface->blend->normalized_stylecoords,
                          num_axes * num_instances ) )
         goto Exit;
 
-      if ( fvar_head.instanceCount && !face->blend->avar_loaded )
+      if ( fvar_head.instanceCount && !ttface->blend->avar_loaded )
       {
         FT_ULong  offset = FT_STREAM_POS();
 
 
-        ft_var_load_avar( face );
+        ft_var_load_avar( ttface );
 
         if ( FT_STREAM_SEEK( offset ) )
           goto Exit;
       }
 
-      FT_TRACE5(( "%d instance%s\n",
+      FT_TRACE5(( "%d named instance%s\n",
                   fvar_head.instanceCount,
                   fvar_head.instanceCount == 1 ? "" : "s" ));
 
       ns  = mmvar->namedstyle;
-      nsc = face->blend->normalized_stylecoords;
+      nsc = ttface->blend->normalized_stylecoords;
       for ( i = 0; i < fvar_head.instanceCount; i++, ns++ )
       {
         /* PostScript names add 2 bytes to the instance record size */
@@ -2568,7 +2606,7 @@
 
 #ifdef FT_DEBUG_LEVEL_TRACE
         {
-          SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
+          SFNT_Service  sfnt = (SFNT_Service)ttface->sfnt;
 
           FT_String*  strname = NULL;
           FT_String*  psname  = NULL;
@@ -2580,7 +2618,7 @@
 
           if ( ns->strid != 0xFFFF )
           {
-            (void)sfnt->get_name( face,
+            (void)sfnt->get_name( ttface,
                                   (FT_UShort)ns->strid,
                                   &strname );
             if ( strname && !ft_strcmp( strname, ".notdef" ) )
@@ -2589,7 +2627,7 @@
 
           if ( ns->psid != 0xFFFF )
           {
-            (void)sfnt->get_name( face,
+            (void)sfnt->get_name( ttface,
                                   (FT_UShort)ns->psid,
                                   &psname );
             if ( psname && !ft_strcmp( psname, ".notdef" ) )
@@ -2598,7 +2636,7 @@
 
           (void)FT_STREAM_SEEK( pos );
 
-          FT_TRACE5(( "  instance %d (%s%s%s, %s%s%s)\n",
+          FT_TRACE5(( "  named instance %d (%s%s%s, %s%s%s)\n",
                       i,
                       strname ? "name: `" : "",
                       strname ? strname : "unnamed",
@@ -2612,7 +2650,7 @@
         }
 #endif /* FT_DEBUG_LEVEL_TRACE */
 
-        ft_var_to_normalized( face, num_axes, ns->coords, nsc );
+        ft_var_to_normalized( ttface, num_axes, ns->coords, nsc );
         nsc += num_axes;
 
         FT_FRAME_EXIT();
@@ -2620,15 +2658,17 @@
 
       if ( num_instances != fvar_head.instanceCount )
       {
-        SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
+        SFNT_Service  sfnt = (SFNT_Service)ttface->sfnt;
 
         FT_Int   found, dummy1, dummy2;
         FT_UInt  strid = ~0U;
 
 
-        /* the default instance is missing in array the   */
-        /* of named instances; try to synthesize an entry */
-        found = sfnt->get_name_id( face,
+        /* The default instance is missing in array the    */
+        /* of named instances; try to synthesize an entry. */
+        /* If this fails, `default_named_instance` remains */
+        /* at value zero, which doesn't do any harm.       */
+        found = sfnt->get_name_id( ttface,
                                    TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY,
                                    &dummy1,
                                    &dummy2 );
@@ -2636,7 +2676,7 @@
           strid = TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY;
         else
         {
-          found = sfnt->get_name_id( face,
+          found = sfnt->get_name_id( ttface,
                                      TT_NAME_ID_FONT_SUBFAMILY,
                                      &dummy1,
                                      &dummy2 );
@@ -2646,7 +2686,7 @@
 
         if ( found )
         {
-          found = sfnt->get_name_id( face,
+          found = sfnt->get_name_id( ttface,
                                      TT_NAME_ID_PS_NAME,
                                      &dummy1,
                                      &dummy2 );
@@ -2655,6 +2695,9 @@
             FT_TRACE5(( "TT_Get_MM_Var:"
                         " Adding default instance to named instances\n" ));
 
+            /* named instance indices start with value 1 */
+            ttface->var_default_named_instance = num_instances;
+
             ns = &mmvar->namedstyle[fvar_head.instanceCount];
 
             ns->strid = strid;
@@ -2668,7 +2711,7 @@
         }
       }
 
-      ft_var_load_mvar( face );
+      ft_var_load_mvar( ttface );
     }
 
     /* fill the output array if requested */
@@ -2678,9 +2721,9 @@
       FT_UInt  n;
 
 
-      if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
+      if ( FT_ALLOC( mmvar, ttface->blend->mmvar_len ) )
         goto Exit;
-      FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len );
+      FT_MEM_COPY( mmvar, ttface->blend->mmvar, ttface->blend->mmvar_len );
 
       axis_flags =
         (FT_UShort*)( (char*)mmvar + mmvar_size );
@@ -2756,7 +2799,7 @@
 
     if ( !face->blend )
     {
-      if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
+      if ( FT_SET_ERROR( TT_Get_MM_Var( FT_FACE( face ), NULL ) ) )
         goto Exit;
     }
 
@@ -2841,26 +2884,29 @@
         }
       }
 
-      if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) )
+      if ( !have_diff )
       {
-        FT_UInt  instance_index = (FT_UInt)face->root.face_index >> 16;
+        if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) )
+        {
+          FT_UInt  instance_index = (FT_UInt)face->root.face_index >> 16;
 
 
-        c = blend->normalizedcoords + i;
-        n = blend->normalized_stylecoords            +
-            ( instance_index - 1 ) * mmvar->num_axis +
-            i;
+          c = blend->normalizedcoords + i;
+          n = blend->normalized_stylecoords            +
+              ( instance_index - 1 ) * mmvar->num_axis +
+              i;
 
-        for ( j = i; j < mmvar->num_axis; j++, n++, c++ )
-          if ( *c != *n )
-            have_diff = 1;
-      }
-      else
-      {
-        c = blend->normalizedcoords + i;
-        for ( j = i; j < mmvar->num_axis; j++, c++ )
-          if ( *c != 0 )
-            have_diff = 1;
+          for ( j = i; j < mmvar->num_axis; j++, n++, c++ )
+            if ( *c != *n )
+              have_diff = 1;
+        }
+        else
+        {
+          c = blend->normalizedcoords + i;
+          for ( j = i; j < mmvar->num_axis; j++, c++ )
+            if ( *c != 0 )
+              have_diff = 1;
+        }
       }
 
       /* return value -1 indicates `no change' */
@@ -2924,9 +2970,6 @@
       }
     }
 
-    /* enforce recomputation of the PostScript name; */
-    FT_FREE( face->postscript_name );
-
   Exit:
     return error;
   }
@@ -2958,26 +3001,15 @@
    *     An array of `num_coords', each between [-1,1].
    *
    * @Return:
-   *   FreeType error code.  0 means success.
+   *   FreeType error code.  0 means success, -1 means success and unchanged
+   *   axis values.
    */
   FT_LOCAL_DEF( FT_Error )
-  TT_Set_MM_Blend( TT_Face    face,
+  TT_Set_MM_Blend( FT_Face    face,       /* TT_Face */
                    FT_UInt    num_coords,
                    FT_Fixed*  coords )
   {
-    FT_Error  error;
-
-
-    error = tt_set_mm_blend( face, num_coords, coords, 1 );
-    if ( error )
-      return error;
-
-    if ( num_coords )
-      face->root.face_flags |= FT_FACE_FLAG_VARIATION;
-    else
-      face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
-
-    return FT_Err_Ok;
+    return tt_set_mm_blend( (TT_Face)face, num_coords, coords, 1 );
   }
 
 
@@ -3005,31 +3037,34 @@
    *     An array of `num_coords', each between [-1,1].
    *
    * @Return:
-   *   FreeType error code.  0 means success.
+   *   FreeType error code.  0 means success, -1 means success and unchanged
+   *   axis values.
    */
   FT_LOCAL_DEF( FT_Error )
-  TT_Get_MM_Blend( TT_Face    face,
+  TT_Get_MM_Blend( FT_Face    face,       /* TT_Face */
                    FT_UInt    num_coords,
                    FT_Fixed*  coords )
   {
+    TT_Face  ttface = (TT_Face)face;
+
     FT_Error  error = FT_Err_Ok;
     GX_Blend  blend;
     FT_UInt   i, nc;
 
 
-    if ( !face->blend )
+    if ( !ttface->blend )
     {
       if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
         return error;
     }
 
-    blend = face->blend;
+    blend = ttface->blend;
 
     if ( !blend->coords )
     {
       /* select default instance coordinates */
       /* if no instance is selected yet      */
-      if ( FT_SET_ERROR( tt_set_mm_blend( face, 0, NULL, 1 ) ) )
+      if ( FT_SET_ERROR( tt_set_mm_blend( ttface, 0, NULL, 1 ) ) )
         return error;
     }
 
@@ -3042,7 +3077,7 @@
       nc = blend->num_axis;
     }
 
-    if ( face->doblend )
+    if ( ttface->doblend )
     {
       for ( i = 0; i < nc; i++ )
         coords[i] = blend->normalizedcoords[i];
@@ -3089,15 +3124,16 @@
    *   FreeType error code.  0 means success.
    */
   FT_LOCAL_DEF( FT_Error )
-  TT_Set_Var_Design( TT_Face    face,
+  TT_Set_Var_Design( FT_Face    face,       /* TT_Face */
                      FT_UInt    num_coords,
                      FT_Fixed*  coords )
   {
+    TT_Face     ttface = (TT_Face)face;
     FT_Error    error  = FT_Err_Ok;
     GX_Blend    blend;
     FT_MM_Var*  mmvar;
     FT_UInt     i;
-    FT_Memory   memory = face->root.memory;
+    FT_Memory   memory = FT_FACE_MEMORY( face );
 
     FT_Fixed*  c;
     FT_Fixed*  n;
@@ -3106,13 +3142,13 @@
     FT_Bool  have_diff = 0;
 
 
-    if ( !face->blend )
+    if ( !ttface->blend )
     {
       if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
         goto Exit;
     }
 
-    blend = face->blend;
+    blend = ttface->blend;
     mmvar = blend->mmvar;
 
     if ( num_coords > mmvar->num_axis )
@@ -3140,13 +3176,13 @@
       }
     }
 
-    if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) )
+    if ( FT_IS_NAMED_INSTANCE( face ) )
     {
       FT_UInt              instance_index;
       FT_Var_Named_Style*  named_style;
 
 
-      instance_index = (FT_UInt)face->root.face_index >> 16;
+      instance_index = (FT_UInt)face->face_index >> 16;
       named_style    = mmvar->namedstyle + instance_index - 1;
 
       n = named_style->coords + num_coords;
@@ -3183,22 +3219,17 @@
     if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) )
       goto Exit;
 
-    if ( !face->blend->avar_loaded )
-      ft_var_load_avar( face );
+    if ( !ttface->blend->avar_loaded )
+      ft_var_load_avar( ttface );
 
     FT_TRACE5(( "TT_Set_Var_Design:\n" ));
     FT_TRACE5(( "  normalized design coordinates:\n" ));
-    ft_var_to_normalized( face, num_coords, blend->coords, normalized );
+    ft_var_to_normalized( ttface, num_coords, blend->coords, normalized );
 
-    error = tt_set_mm_blend( face, mmvar->num_axis, normalized, 0 );
+    error = tt_set_mm_blend( ttface, mmvar->num_axis, normalized, 0 );
     if ( error )
       goto Exit;
 
-    if ( num_coords )
-      face->root.face_flags |= FT_FACE_FLAG_VARIATION;
-    else
-      face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
-
   Exit:
     FT_FREE( normalized );
     return error;
@@ -3231,28 +3262,29 @@
    *   FreeType error code.  0~means success.
    */
   FT_LOCAL_DEF( FT_Error )
-  TT_Get_Var_Design( TT_Face    face,
+  TT_Get_Var_Design( FT_Face    face,       /* TT_Face */
                      FT_UInt    num_coords,
                      FT_Fixed*  coords )
   {
-    FT_Error  error = FT_Err_Ok;
+    TT_Face   ttface = (TT_Face)face;
+    FT_Error  error  = FT_Err_Ok;
     GX_Blend  blend;
     FT_UInt   i, nc;
 
 
-    if ( !face->blend )
+    if ( !ttface->blend )
     {
       if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
         return error;
     }
 
-    blend = face->blend;
+    blend = ttface->blend;
 
     if ( !blend->coords )
     {
       /* select default instance coordinates */
       /* if no instance is selected yet      */
-      if ( FT_SET_ERROR( tt_set_mm_blend( face, 0, NULL, 1 ) ) )
+      if ( FT_SET_ERROR( tt_set_mm_blend( ttface, 0, NULL, 1 ) ) )
         return error;
     }
 
@@ -3265,7 +3297,7 @@
       nc = blend->num_axis;
     }
 
-    if ( face->doblend )
+    if ( ttface->doblend )
     {
       for ( i = 0; i < nc; i++ )
         coords[i] = blend->coords[i];
@@ -3301,29 +3333,33 @@
    *     Value 0 indicates to not use an instance.
    *
    * @Return:
-   *   FreeType error code.  0~means success.
+   *   FreeType error code.  0~means success, -1 means success and unchanged
+   *   axis values.
    */
   FT_LOCAL_DEF( FT_Error )
-  TT_Set_Named_Instance( TT_Face  face,
+  TT_Set_Named_Instance( FT_Face  face,            /* TT_Face */
                          FT_UInt  instance_index )
   {
+    TT_Face     ttface = (TT_Face)face;
     FT_Error    error;
     GX_Blend    blend;
     FT_MM_Var*  mmvar;
 
+    FT_Memory  memory = FT_FACE_MEMORY( face );
+
     FT_UInt  num_instances;
 
 
-    if ( !face->blend )
+    if ( !ttface->blend )
     {
       if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
         goto Exit;
     }
 
-    blend = face->blend;
+    blend = ttface->blend;
     mmvar = blend->mmvar;
 
-    num_instances = (FT_UInt)face->root.style_flags >> 16;
+    num_instances = (FT_UInt)face->style_flags >> 16;
 
     /* `instance_index' starts with value 1, thus `>' */
     if ( instance_index > num_instances )
@@ -3334,8 +3370,7 @@
 
     if ( instance_index > 0 )
     {
-      FT_Memory     memory = face->root.memory;
-      SFNT_Service  sfnt   = (SFNT_Service)face->sfnt;
+      SFNT_Service  sfnt = (SFNT_Service)ttface->sfnt;
 
       FT_Var_Named_Style*  named_style;
       FT_String*           style_name;
@@ -3343,40 +3378,89 @@
 
       named_style = mmvar->namedstyle + instance_index - 1;
 
-      error = sfnt->get_name( face,
+      error = sfnt->get_name( ttface,
                               (FT_UShort)named_style->strid,
                               &style_name );
       if ( error )
         goto Exit;
 
       /* set (or replace) style name */
-      FT_FREE( face->root.style_name );
-      face->root.style_name = style_name;
+      FT_FREE( face->style_name );
+      face->style_name = style_name;
 
       /* finally, select the named instance */
       error = TT_Set_Var_Design( face,
                                  mmvar->num_axis,
                                  named_style->coords );
-      if ( error )
-      {
-        /* internal error code -1 means `no change' */
-        if ( error == -1 )
-          error = FT_Err_Ok;
-        goto Exit;
-      }
     }
     else
+    {
+      /* restore non-VF style name */
+      FT_FREE( face->style_name );
+      if ( FT_STRDUP( face->style_name, ttface->non_var_style_name ) )
+        goto Exit;
       error = TT_Set_Var_Design( face, 0, NULL );
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /**************************************************************************
+   *
+   * @Function:
+   *   TT_Get_Default_Named_Instance
+   *
+   * @Description:
+   *   Get the default named instance.
+   *
+   * @Input:
+   *   face ::
+   *     A handle to the source face.
+   *
+   * @Output:
+   *   instance_index ::
+   *     The default named instance index.
+   *
+   * @Return:
+   *   FreeType error code.  0~means success.
+   */
+  FT_LOCAL_DEF( FT_Error )
+  TT_Get_Default_Named_Instance( FT_Face   face,
+                                 FT_UInt  *instance_index )
+  {
+    TT_Face   ttface = (TT_Face)face;
+    FT_Error  error  = FT_Err_Ok;
 
-    face->root.face_index  = ( instance_index << 16 )             |
-                             ( face->root.face_index & 0xFFFFL );
-    face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
+
+    if ( !ttface->blend )
+    {
+      if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
+        goto Exit;
+    }
+
+    *instance_index = ttface->var_default_named_instance;
 
   Exit:
     return error;
   }
 
 
+  /* This function triggers (lazy) recomputation of the `postscript_name` */
+  /* field in `TT_Face`.                                                  */
+
+  FT_LOCAL_DEF( void )
+  tt_construct_ps_name( FT_Face  face )
+  {
+    TT_Face    ttface = (TT_Face)face;
+    FT_Memory  memory = FT_FACE_MEMORY( face );
+
+
+    FT_FREE( ttface->postscript_name );
+  }
+
+
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -4409,22 +4493,25 @@
    *   the MM machinery in case it isn't loaded yet.
    */
   FT_LOCAL_DEF( FT_Error )
-  tt_get_var_blend( TT_Face      face,
+  tt_get_var_blend( FT_Face      face,             /* TT_Face */
                     FT_UInt     *num_coords,
                     FT_Fixed*   *coords,
                     FT_Fixed*   *normalizedcoords,
                     FT_MM_Var*  *mm_var )
   {
-    if ( face->blend )
+    TT_Face  ttface = (TT_Face)face;
+
+
+    if ( ttface->blend )
     {
       if ( num_coords )
-        *num_coords       = face->blend->num_axis;
+        *num_coords       = ttface->blend->num_axis;
       if ( coords )
-        *coords           = face->blend->coords;
+        *coords           = ttface->blend->coords;
       if ( normalizedcoords )
-        *normalizedcoords = face->blend->normalizedcoords;
+        *normalizedcoords = ttface->blend->normalizedcoords;
       if ( mm_var )
-        *mm_var           = face->blend->mmvar;
+        *mm_var           = ttface->blend->mmvar;
     }
     else
     {
@@ -4441,7 +4528,7 @@
 
 
   FT_LOCAL_DEF( void )
-  tt_var_done_item_variation_store( TT_Face          face,
+  tt_var_done_item_variation_store( FT_Face          face,
                                     GX_ItemVarStore  itemStore )
   {
     FT_Memory  memory = FT_FACE_MEMORY( face );
@@ -4470,7 +4557,7 @@
 
 
   FT_LOCAL_DEF( void )
-  tt_var_done_delta_set_index_map( TT_Face            face,
+  tt_var_done_delta_set_index_map( FT_Face            face,
                                    GX_DeltaSetIdxMap  deltaSetIdxMap )
   {
     FT_Memory  memory = FT_FACE_MEMORY( face );
@@ -4490,10 +4577,11 @@
    *   Free the blend internal data structure.
    */
   FT_LOCAL_DEF( void )
-  tt_done_blend( TT_Face  face )
+  tt_done_blend( FT_Face  face )
   {
+    TT_Face    ttface = (TT_Face)face;
     FT_Memory  memory = FT_FACE_MEMORY( face );
-    GX_Blend   blend  = face->blend;
+    GX_Blend   blend  = ttface->blend;
 
 
     if ( blend )
@@ -4565,7 +4653,7 @@
 #else /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */
 
   /* ANSI C doesn't like empty source files */
-  typedef int  _tt_gxvar_dummy;
+  typedef int  tt_gxvar_dummy_;
 
 #endif /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h
index 4fec980dcc066..e3da6d1705cc7 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h
@@ -347,33 +347,40 @@ FT_BEGIN_HEADER
 
 
   FT_LOCAL( FT_Error )
-  TT_Set_MM_Blend( TT_Face    face,
+  TT_Set_MM_Blend( FT_Face    face,
                    FT_UInt    num_coords,
                    FT_Fixed*  coords );
 
   FT_LOCAL( FT_Error )
-  TT_Get_MM_Blend( TT_Face    face,
+  TT_Get_MM_Blend( FT_Face    face,
                    FT_UInt    num_coords,
                    FT_Fixed*  coords );
 
   FT_LOCAL( FT_Error )
-  TT_Set_Var_Design( TT_Face    face,
+  TT_Set_Var_Design( FT_Face    face,
                      FT_UInt    num_coords,
                      FT_Fixed*  coords );
 
   FT_LOCAL( FT_Error )
-  TT_Get_MM_Var( TT_Face      face,
+  TT_Get_MM_Var( FT_Face      face,
                  FT_MM_Var*  *master );
 
   FT_LOCAL( FT_Error )
-  TT_Get_Var_Design( TT_Face    face,
+  TT_Get_Var_Design( FT_Face    face,
                      FT_UInt    num_coords,
                      FT_Fixed*  coords );
 
   FT_LOCAL( FT_Error )
-  TT_Set_Named_Instance( TT_Face  face,
+  TT_Set_Named_Instance( FT_Face  face,
                          FT_UInt  instance_index );
 
+  FT_LOCAL( FT_Error )
+  TT_Get_Default_Named_Instance( FT_Face   face,
+                                 FT_UInt  *instance_index );
+
+  FT_LOCAL( void )
+  tt_construct_ps_name( FT_Face  face );
+
   FT_LOCAL( FT_Error )
   tt_face_vary_cvt( TT_Face    face,
                     FT_Stream  stream );
@@ -385,55 +392,54 @@ FT_BEGIN_HEADER
                               FT_Vector*   unrounded );
 
   FT_LOCAL( FT_Error )
-  tt_hadvance_adjust( TT_Face  face,
+  tt_hadvance_adjust( FT_Face  face,
                       FT_UInt  gindex,
                       FT_Int  *adelta );
 
   FT_LOCAL( FT_Error )
-  tt_vadvance_adjust( TT_Face  face,
+  tt_vadvance_adjust( FT_Face  face,
                       FT_UInt  gindex,
                       FT_Int  *adelta );
 
   FT_LOCAL( void )
-  tt_apply_mvar( TT_Face  face );
-
+  tt_apply_mvar( FT_Face  face );
 
   FT_LOCAL( FT_Error )
-  tt_var_load_item_variation_store( TT_Face          face,
+  tt_var_load_item_variation_store( FT_Face          face,
                                     FT_ULong         offset,
                                     GX_ItemVarStore  itemStore );
 
   FT_LOCAL( FT_Error )
-  tt_var_load_delta_set_index_mapping( TT_Face            face,
+  tt_var_load_delta_set_index_mapping( FT_Face            face,
                                        FT_ULong           offset,
                                        GX_DeltaSetIdxMap  map,
                                        GX_ItemVarStore    itemStore,
                                        FT_ULong           table_len );
 
   FT_LOCAL( FT_ItemVarDelta )
-  tt_var_get_item_delta( TT_Face          face,
+  tt_var_get_item_delta( FT_Face          face,
                          GX_ItemVarStore  itemStore,
                          FT_UInt          outerIndex,
                          FT_UInt          innerIndex );
 
   FT_LOCAL( void )
-  tt_var_done_item_variation_store( TT_Face          face,
+  tt_var_done_item_variation_store( FT_Face          face,
                                     GX_ItemVarStore  itemStore );
 
   FT_LOCAL( void )
-  tt_var_done_delta_set_index_map( TT_Face            face,
+  tt_var_done_delta_set_index_map( FT_Face            face,
                                    GX_DeltaSetIdxMap  deltaSetIdxMap );
 
 
   FT_LOCAL( FT_Error )
-  tt_get_var_blend( TT_Face      face,
+  tt_get_var_blend( FT_Face      face,
                     FT_UInt     *num_coords,
                     FT_Fixed*   *coords,
                     FT_Fixed*   *normalizedcoords,
                     FT_MM_Var*  *mm_var );
 
   FT_LOCAL( void )
-  tt_done_blend( TT_Face  face );
+  tt_done_blend( FT_Face  face );
 
 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c
index 4fcfaa3e4300c..79df4555d9431 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c
@@ -29,7 +29,6 @@
 
 #include "ttinterp.h"
 #include "tterrors.h"
-#include "ttsubpix.h"
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
 #include "ttgxvar.h"
 #endif
@@ -52,12 +51,6 @@
           ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
             TT_INTERPRETER_VERSION_35 )
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-#define SUBPIXEL_HINTING_INFINALITY                                          \
-          ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
-            TT_INTERPRETER_VERSION_38 )
-#endif
-
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
 #define SUBPIXEL_HINTING_MINIMAL                                             \
           ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
@@ -275,57 +268,6 @@
   }
 
 
-  /**************************************************************************
-   *
-   * @Function:
-   *   Update_Max
-   *
-   * @Description:
-   *   Checks the size of a buffer and reallocates it if necessary.
-   *
-   * @Input:
-   *   memory ::
-   *     A handle to the parent memory object.
-   *
-   *   multiplier ::
-   *     The size in bytes of each element in the buffer.
-   *
-   *   new_max ::
-   *     The new capacity (size) of the buffer.
-   *
-   * @InOut:
-   *   size ::
-   *     The address of the buffer's current size expressed
-   *     in elements.
-   *
-   *   buff ::
-   *     The address of the buffer base pointer.
-   *
-   * @Return:
-   *   FreeType error code.  0 means success.
-   */
-  FT_LOCAL_DEF( FT_Error )
-  Update_Max( FT_Memory  memory,
-              FT_ULong*  size,
-              FT_ULong   multiplier,
-              void*      _pbuff,
-              FT_ULong   new_max )
-  {
-    FT_Error  error;
-    void**    pbuff = (void**)_pbuff;
-
-
-    if ( *size < new_max )
-    {
-      if ( FT_QREALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
-        return error;
-      *size = new_max;
-    }
-
-    return FT_Err_Ok;
-  }
-
-
   /**************************************************************************
    *
    * @Function:
@@ -359,9 +301,9 @@
                    TT_Size         size )
   {
     FT_Int          i;
-    FT_ULong        tmp;
     TT_MaxProfile*  maxp;
     FT_Error        error;
+    FT_Memory       memory = exec->memory;
 
 
     exec->face = face;
@@ -406,25 +348,15 @@
 
     /* XXX: We reserve a little more elements on the stack to deal safely */
     /*      with broken fonts like arialbs, courbs, timesbs, etc.         */
-    tmp = (FT_ULong)exec->stackSize;
-    error = Update_Max( exec->memory,
-                        &tmp,
-                        sizeof ( FT_F26Dot6 ),
-                        (void*)&exec->stack,
-                        maxp->maxStackElements + 32 );
-    exec->stackSize = (FT_Long)tmp;
-    if ( error )
+    if ( FT_QRENEW_ARRAY( exec->stack,
+                          exec->stackSize,
+                          maxp->maxStackElements + 32 ) )
       return error;
+    exec->stackSize = maxp->maxStackElements + 32;
 
-    tmp = (FT_ULong)exec->glyphSize;
-    error = Update_Max( exec->memory,
-                        &tmp,
-                        sizeof ( FT_Byte ),
-                        (void*)&exec->glyphIns,
-                        maxp->maxSizeOfInstructions );
-    exec->glyphSize = (FT_UInt)tmp;
-    if ( error )
-      return error;
+    /* free previous glyph code range */
+    FT_FREE( exec->glyphIns );
+    exec->glyphSize = 0;
 
     exec->pts.n_points   = 0;
     exec->pts.n_contours = 0;
@@ -1530,14 +1462,16 @@
     if ( exc->iniRange == tt_coderange_glyph &&
          exc->cvt != exc->glyfCvt            )
     {
-      exc->error = Update_Max( exc->memory,
-                               &exc->glyfCvtSize,
-                               sizeof ( FT_Long ),
-                               (void*)&exc->glyfCvt,
-                               exc->cvtSize );
-      if ( exc->error )
+      FT_Memory  memory = exc->memory;
+      FT_Error   error;
+
+
+      FT_MEM_QRENEW_ARRAY( exc->glyfCvt, exc->glyfCvtSize, exc->cvtSize );
+      exc->error = error;
+      if ( error )
         return;
 
+      exc->glyfCvtSize = exc->cvtSize;
       FT_ARRAY_COPY( exc->glyfCvt, exc->cvt, exc->glyfCvtSize );
       exc->cvt = exc->glyfCvt;
     }
@@ -1744,17 +1678,6 @@
 
     if ( v != 0 )
     {
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      if ( SUBPIXEL_HINTING_INFINALITY                            &&
-           ( !exc->ignore_x_mode                                ||
-             ( exc->sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) )
-        zone->cur[point].x = ADD_LONG( zone->cur[point].x,
-                                       FT_MulDiv( distance,
-                                                  v,
-                                                  exc->F_dot_P ) );
-      else
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
       /* Exception to the post-IUP curfew: Allow the x component of */
       /* diagonal moves, but only post-IUP.  DejaVu tries to adjust */
@@ -1860,12 +1783,6 @@
                  FT_UShort       point,
                  FT_F26Dot6      distance )
   {
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    if ( SUBPIXEL_HINTING_INFINALITY && !exc->ignore_x_mode )
-      zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
-    else
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
     if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility )
       zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
@@ -3069,28 +2986,7 @@
         args[0] = 0;
     }
     else
-    {
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      /* subpixel hinting - avoid Typeman Dstroke and */
-      /* IStroke and Vacuform rounds                  */
-      if ( SUBPIXEL_HINTING_INFINALITY                 &&
-           exc->ignore_x_mode                          &&
-           ( ( I == 24                             &&
-               ( exc->face->sph_found_func_flags &
-                 ( SPH_FDEF_SPACING_1 |
-                   SPH_FDEF_SPACING_2 )          ) ) ||
-             ( I == 22                      &&
-               ( exc->sph_in_func_flags   &
-                 SPH_FDEF_TYPEMAN_STROKES ) )        ||
-             ( I == 8                              &&
-               ( exc->face->sph_found_func_flags &
-                 SPH_FDEF_VACUFORM_ROUND_1       ) &&
-               exc->iup_called                     ) ) )
-        args[0] = 0;
-      else
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-        args[0] = exc->storage[I];
-    }
+      args[0] = exc->storage[I];
   }
 
 
@@ -3117,18 +3013,18 @@
       if ( exc->iniRange == tt_coderange_glyph &&
            exc->storage != exc->glyfStorage    )
       {
-        FT_ULong  tmp = (FT_ULong)exc->glyfStoreSize;
+        FT_Memory  memory = exc->memory;
+        FT_Error   error;
 
 
-        exc->error = Update_Max( exc->memory,
-                                 &tmp,
-                                 sizeof ( FT_Long ),
-                                 (void*)&exc->glyfStorage,
-                                 exc->storeSize );
-        exc->glyfStoreSize = (FT_UShort)tmp;
-        if ( exc->error )
+        FT_MEM_QRENEW_ARRAY( exc->glyfStorage,
+                             exc->glyfStoreSize,
+                             exc->storeSize );
+        exc->error  = error;
+        if ( error )
           return;
 
+        exc->glyfStoreSize = exc->storeSize;
         FT_ARRAY_COPY( exc->glyfStorage, exc->storage, exc->glyfStoreSize );
         exc->storage = exc->glyfStorage;
       }
@@ -3604,106 +3500,6 @@
     TT_DefRecord*  rec;
     TT_DefRecord*  limit;
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    /* arguments to opcodes are skipped by `SKIP_Code' */
-    FT_Byte    opcode_pattern[9][12] = {
-                 /* #0 inline delta function 1 */
-                 {
-                   0x4B, /* PPEM    */
-                   0x53, /* GTEQ    */
-                   0x23, /* SWAP    */
-                   0x4B, /* PPEM    */
-                   0x51, /* LTEQ    */
-                   0x5A, /* AND     */
-                   0x58, /* IF      */
-                   0x38, /*   SHPIX */
-                   0x1B, /* ELSE    */
-                   0x21, /*   POP   */
-                   0x21, /*   POP   */
-                   0x59  /* EIF     */
-                 },
-                 /* #1 inline delta function 2 */
-                 {
-                   0x4B, /* PPEM    */
-                   0x54, /* EQ      */
-                   0x58, /* IF      */
-                   0x38, /*   SHPIX */
-                   0x1B, /* ELSE    */
-                   0x21, /*   POP   */
-                   0x21, /*   POP   */
-                   0x59  /* EIF     */
-                 },
-                 /* #2 diagonal stroke function */
-                 {
-                   0x20, /* DUP     */
-                   0x20, /* DUP     */
-                   0xB0, /* PUSHB_1 */
-                         /*   1     */
-                   0x60, /* ADD     */
-                   0x46, /* GC_cur  */
-                   0xB0, /* PUSHB_1 */
-                         /*   64    */
-                   0x23, /* SWAP    */
-                   0x42  /* WS      */
-                 },
-                 /* #3 VacuFormRound function */
-                 {
-                   0x45, /* RCVT    */
-                   0x23, /* SWAP    */
-                   0x46, /* GC_cur  */
-                   0x60, /* ADD     */
-                   0x20, /* DUP     */
-                   0xB0  /* PUSHB_1 */
-                         /*   38    */
-                 },
-                 /* #4 TTFautohint bytecode (old) */
-                 {
-                   0x20, /* DUP     */
-                   0x64, /* ABS     */
-                   0xB0, /* PUSHB_1 */
-                         /*   32    */
-                   0x60, /* ADD     */
-                   0x66, /* FLOOR   */
-                   0x23, /* SWAP    */
-                   0xB0  /* PUSHB_1 */
-                 },
-                 /* #5 spacing function 1 */
-                 {
-                   0x01, /* SVTCA_x */
-                   0xB0, /* PUSHB_1 */
-                         /*   24    */
-                   0x43, /* RS      */
-                   0x58  /* IF      */
-                 },
-                 /* #6 spacing function 2 */
-                 {
-                   0x01, /* SVTCA_x */
-                   0x18, /* RTG     */
-                   0xB0, /* PUSHB_1 */
-                         /*   24    */
-                   0x43, /* RS      */
-                   0x58  /* IF      */
-                 },
-                 /* #7 TypeMan Talk DiagEndCtrl function */
-                 {
-                   0x01, /* SVTCA_x */
-                   0x20, /* DUP     */
-                   0xB0, /* PUSHB_1 */
-                         /*   3     */
-                   0x25, /* CINDEX  */
-                 },
-                 /* #8 TypeMan Talk Align */
-                 {
-                   0x06, /* SPVTL   */
-                   0x7D, /* RDTG    */
-                 },
-               };
-    FT_UShort  opcode_patterns   = 9;
-    FT_UShort  opcode_pointer[9] = {  0, 0, 0, 0, 0, 0, 0, 0, 0 };
-    FT_UShort  opcode_size[9]    = { 12, 8, 8, 6, 7, 4, 5, 4, 2 };
-    FT_UShort  i;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
 
     /* FDEF is only allowed in `prep' or `fpgm' */
     if ( exc->iniRange == tt_coderange_glyph )
@@ -3748,136 +3544,15 @@
     rec->opc            = (FT_UInt16)n;
     rec->start          = exc->IP + 1;
     rec->active         = TRUE;
-    rec->inline_delta   = FALSE;
-    rec->sph_fdef_flags = 0x0000;
 
     if ( n > exc->maxFunc )
       exc->maxFunc = (FT_UInt16)n;
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    /* We don't know for sure these are typeman functions, */
-    /* however they are only active when RS 22 is called   */
-    if ( n >= 64 && n <= 66 )
-      rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_STROKES;
-#endif
-
     /* Now skip the whole function definition. */
     /* We don't allow nested IDEFS & FDEFs.    */
 
     while ( SkipCode( exc ) == SUCCESS )
     {
-
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
-      if ( SUBPIXEL_HINTING_INFINALITY )
-      {
-        for ( i = 0; i < opcode_patterns; i++ )
-        {
-          if ( opcode_pointer[i] < opcode_size[i]                  &&
-               exc->opcode == opcode_pattern[i][opcode_pointer[i]] )
-          {
-            opcode_pointer[i] += 1;
-
-            if ( opcode_pointer[i] == opcode_size[i] )
-            {
-              FT_TRACE6(( "sph: Function %d, opcode ptrn: %ld, %s %s\n",
-                          i, n,
-                          exc->face->root.family_name,
-                          exc->face->root.style_name ));
-
-              switch ( i )
-              {
-              case 0:
-                rec->sph_fdef_flags             |= SPH_FDEF_INLINE_DELTA_1;
-                exc->face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_1;
-                break;
-
-              case 1:
-                rec->sph_fdef_flags             |= SPH_FDEF_INLINE_DELTA_2;
-                exc->face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_2;
-                break;
-
-              case 2:
-                switch ( n )
-                {
-                  /* needs to be implemented still */
-                case 58:
-                  rec->sph_fdef_flags             |= SPH_FDEF_DIAGONAL_STROKE;
-                  exc->face->sph_found_func_flags |= SPH_FDEF_DIAGONAL_STROKE;
-                }
-                break;
-
-              case 3:
-                switch ( n )
-                {
-                case 0:
-                  rec->sph_fdef_flags             |= SPH_FDEF_VACUFORM_ROUND_1;
-                  exc->face->sph_found_func_flags |= SPH_FDEF_VACUFORM_ROUND_1;
-                }
-                break;
-
-              case 4:
-                /* probably not necessary to detect anymore */
-                rec->sph_fdef_flags             |= SPH_FDEF_TTFAUTOHINT_1;
-                exc->face->sph_found_func_flags |= SPH_FDEF_TTFAUTOHINT_1;
-                break;
-
-              case 5:
-                switch ( n )
-                {
-                case 0:
-                case 1:
-                case 2:
-                case 4:
-                case 7:
-                case 8:
-                  rec->sph_fdef_flags             |= SPH_FDEF_SPACING_1;
-                  exc->face->sph_found_func_flags |= SPH_FDEF_SPACING_1;
-                }
-                break;
-
-              case 6:
-                switch ( n )
-                {
-                case 0:
-                case 1:
-                case 2:
-                case 4:
-                case 7:
-                case 8:
-                  rec->sph_fdef_flags             |= SPH_FDEF_SPACING_2;
-                  exc->face->sph_found_func_flags |= SPH_FDEF_SPACING_2;
-                }
-                break;
-
-               case 7:
-                 rec->sph_fdef_flags             |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
-                 exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
-                 break;
-
-               case 8:
-#if 0
-                 rec->sph_fdef_flags             |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
-                 exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
-#endif
-                 break;
-              }
-              opcode_pointer[i] = 0;
-            }
-          }
-
-          else
-            opcode_pointer[i] = 0;
-        }
-
-        /* Set sph_compatibility_mode only when deltas are detected */
-        exc->face->sph_compatibility_mode =
-          ( ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_1 ) |
-            ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) );
-      }
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
       switch ( exc->opcode )
       {
       case 0x89:    /* IDEF */
@@ -3905,10 +3580,6 @@
     TT_CallRec*  pRec;
 
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    exc->sph_in_func_flags = 0x0000;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
     if ( exc->callTop <= 0 )     /* We encountered an ENDF without a call */
     {
       exc->error = FT_THROW( ENDF_In_Exec_Stream );
@@ -3996,17 +3667,6 @@
     if ( !def->active )
       goto Fail;
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    if ( SUBPIXEL_HINTING_INFINALITY                                    &&
-         exc->ignore_x_mode                                             &&
-         ( ( exc->iup_called                                        &&
-             ( exc->sph_tweak_flags & SPH_TWEAK_NO_CALL_AFTER_IUP ) ) ||
-           ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 )        ) )
-      goto Fail;
-    else
-      exc->sph_in_func_flags = def->sph_fdef_flags;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
     /* check the call stack */
     if ( exc->callTop >= exc->callSize )
     {
@@ -4084,15 +3744,6 @@
     if ( !def->active )
       goto Fail;
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    if ( SUBPIXEL_HINTING_INFINALITY                         &&
-         exc->ignore_x_mode                                  &&
-         ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) )
-      goto Fail;
-    else
-      exc->sph_in_func_flags = def->sph_fdef_flags;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
     /* check stack */
     if ( exc->callTop >= exc->callSize )
     {
@@ -4998,14 +4649,6 @@
       }
     }
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */
-    if ( SUBPIXEL_HINTING_INFINALITY         &&
-         exc->ignore_x_mode                  &&
-         ( D < 0 ? NEG_LONG( D ) : D ) == 64 )
-      D += 1;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
     args[0] = D;
   }
 
@@ -5267,13 +4910,6 @@
     /* except to change the subpixel flags temporarily */
     else if ( exc->iniRange == tt_coderange_glyph && K == 3 )
     {
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      /* INSTCTRL modifying flag 3 also has an effect */
-      /* outside of the CVT program                   */
-      if ( SUBPIXEL_HINTING_INFINALITY )
-        exc->ignore_x_mode = !FT_BOOL( L == 4 );
-#endif
-
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
       /* Native ClearType fonts sign a waiver that turns off all backward  */
       /* compatibility hacks and lets them program points to the grid like */
@@ -5605,12 +5241,6 @@
         }
       }
       else
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      /* doesn't follow Cleartype spec but produces better result */
-      if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode )
-        Move_Zp2_Point( exc, point, 0, dy, TRUE );
-      else
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
         Move_Zp2_Point( exc, point, dx, dy, TRUE );
 
       exc->GS.loop--;
@@ -5771,76 +5401,6 @@
         }
       }
       else
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      if ( SUBPIXEL_HINTING_INFINALITY &&
-           exc->ignore_x_mode          )
-      {
-        FT_Int  B1, B2;
-
-
-        /*  If not using ignore_x_mode rendering, allow ZP2 move.        */
-        /*  If inline deltas aren't allowed, skip ZP2 move.              */
-        /*  If using ignore_x_mode rendering, allow ZP2 point move if:   */
-        /*   - freedom vector is y and sph_compatibility_mode is off     */
-        /*   - the glyph is composite and the move is in the Y direction */
-        /*   - the glyph is specifically set to allow SHPIX moves        */
-        /*   - the move is on a previously Y-touched point               */
-
-        /* save point for later comparison */
-        B1 = exc->zp2.cur[point].y;
-
-        if ( exc->face->sph_compatibility_mode )
-        {
-          if ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
-            dy = FT_PIX_ROUND( B1 + dy ) - B1;
-
-          /* skip post-iup deltas */
-          if ( exc->iup_called                                          &&
-               ( ( exc->sph_in_func_flags & SPH_FDEF_INLINE_DELTA_1 ) ||
-                 ( exc->sph_in_func_flags & SPH_FDEF_INLINE_DELTA_2 ) ) )
-            goto Skip;
-
-          if ( !( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) &&
-                ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
-                  ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y )    ||
-                  ( exc->sph_tweak_flags & SPH_TWEAK_DO_SHPIX )      )  )
-            Move_Zp2_Point( exc, point, 0, dy, TRUE );
-
-          /* save new point */
-          if ( exc->GS.freeVector.y != 0 )
-          {
-            B2 = exc->zp2.cur[point].y;
-
-            /* reverse any disallowed moves */
-            if ( ( B1 & 63 ) == 0 &&
-                 ( B2 & 63 ) != 0 &&
-                 B1 != B2         )
-              Move_Zp2_Point( exc, point, 0, NEG_LONG( dy ), TRUE );
-          }
-        }
-        else if ( exc->GS.freeVector.y != 0 )
-        {
-          Move_Zp2_Point( exc, point, dx, dy, TRUE );
-
-          /* save new point */
-          B2 = exc->zp2.cur[point].y;
-
-          /* reverse any disallowed moves */
-          if ( ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
-               ( B1 & 63 ) != 0                                           &&
-               ( B2 & 63 ) != 0                                           &&
-               B1 != B2                                                   )
-            Move_Zp2_Point( exc,
-                            point,
-                            NEG_LONG( dx ),
-                            NEG_LONG( dy ),
-                            TRUE );
-        }
-        else if ( exc->sph_in_func_flags & SPH_FDEF_TYPEMAN_DIAGENDCTRL )
-          Move_Zp2_Point( exc, point, dx, dy, TRUE );
-      }
-      else
-#endif
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
       if ( SUBPIXEL_HINTING_MINIMAL    &&
            exc->backward_compatibility )
@@ -5860,9 +5420,6 @@
 #endif
         Move_Zp2_Point( exc, point, dx, dy, TRUE );
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    Skip:
-#endif
       exc->GS.loop--;
     }
 
@@ -5907,28 +5464,6 @@
 
     distance = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 );
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    /* subpixel hinting - make MSIRP respect CVT cut-in; */
-    if ( SUBPIXEL_HINTING_INFINALITY &&
-         exc->ignore_x_mode          &&
-         exc->GS.freeVector.x != 0   )
-    {
-      FT_F26Dot6  control_value_cutin = exc->GS.control_value_cutin;
-      FT_F26Dot6  delta;
-
-
-      if ( !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
-        control_value_cutin = 0;
-
-      delta = SUB_LONG( distance, args[1] );
-      if ( delta < 0 )
-        delta = NEG_LONG( delta );
-
-      if ( delta >= control_value_cutin )
-        distance = args[1];
-    }
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
     exc->func_move( exc,
                     &exc->zp1,
                     point,
@@ -5969,14 +5504,7 @@
     if ( ( exc->opcode & 1 ) != 0 )
     {
       cur_dist = FAST_PROJECT( &exc->zp0.cur[point] );
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      if ( SUBPIXEL_HINTING_INFINALITY &&
-           exc->ignore_x_mode          &&
-           exc->GS.freeVector.x != 0   )
-        distance = SUB_LONG( Round_None( exc, cur_dist, 3 ), cur_dist );
-      else
-#endif
-        distance = SUB_LONG( exc->func_round( exc, cur_dist, 3 ), cur_dist );
+      distance = SUB_LONG( exc->func_round( exc, cur_dist, 3 ), cur_dist );
     }
     else
       distance = 0;
@@ -6039,27 +5567,12 @@
 
     if ( exc->GS.gep0 == 0 )   /* If in twilight zone */
     {
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      /* Only adjust if not in sph_compatibility_mode or ignore_x_mode. */
-      /* Determined via experimentation and may be incorrect...         */
-      if ( !( SUBPIXEL_HINTING_INFINALITY           &&
-              ( exc->ignore_x_mode                &&
-                exc->face->sph_compatibility_mode ) ) )
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-        exc->zp0.org[point].x = TT_MulFix14( distance,
+      exc->zp0.org[point].x = TT_MulFix14( distance,
                                              exc->GS.freeVector.x );
       exc->zp0.org[point].y = TT_MulFix14( distance,
                                            exc->GS.freeVector.y );
       exc->zp0.cur[point]   = exc->zp0.org[point];
     }
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    if ( SUBPIXEL_HINTING_INFINALITY                    &&
-         exc->ignore_x_mode                             &&
-         ( exc->sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) &&
-         distance > 0                                   &&
-         exc->GS.freeVector.y != 0                      )
-      distance = 0;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
 
     org_dist = FAST_PROJECT( &exc->zp0.cur[point] );
 
@@ -6069,15 +5582,6 @@
       FT_F26Dot6  delta;
 
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      if ( SUBPIXEL_HINTING_INFINALITY                        &&
-           exc->ignore_x_mode                                 &&
-           exc->GS.freeVector.x != 0                          &&
-           exc->GS.freeVector.y == 0                          &&
-           !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
-        control_value_cutin = 0;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
       delta = SUB_LONG( distance, org_dist );
       if ( delta < 0 )
         delta = NEG_LONG( delta );
@@ -6085,14 +5589,7 @@
       if ( delta > control_value_cutin )
         distance = org_dist;
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      if ( SUBPIXEL_HINTING_INFINALITY &&
-           exc->ignore_x_mode          &&
-           exc->GS.freeVector.x != 0   )
-        distance = Round_None( exc, distance, 3 );
-      else
-#endif
-        distance = exc->func_round( exc, distance, 3 );
+      distance = exc->func_round( exc, distance, 3 );
     }
 
     exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) );
@@ -6185,14 +5682,7 @@
 
     if ( ( exc->opcode & 4 ) != 0 )
     {
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      if ( SUBPIXEL_HINTING_INFINALITY &&
-           exc->ignore_x_mode          &&
-           exc->GS.freeVector.x != 0   )
-        distance = Round_None( exc, org_dist, exc->opcode & 3 );
-      else
-#endif
-        distance = exc->func_round( exc, org_dist, exc->opcode & 3 );
+      distance = exc->func_round( exc, org_dist, exc->opcode & 3 );
     }
     else
       distance = Round_None( exc, org_dist, exc->opcode & 3 );
@@ -6204,14 +5694,6 @@
       FT_F26Dot6  minimum_distance = exc->GS.minimum_distance;
 
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      if ( SUBPIXEL_HINTING_INFINALITY                        &&
-           exc->ignore_x_mode                                 &&
-           exc->GS.freeVector.x != 0                          &&
-           !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
-        minimum_distance = 0;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
       if ( org_dist >= 0 )
       {
         if ( distance < minimum_distance )
@@ -6354,41 +5836,7 @@
       distance = exc->func_round( exc, cvt_dist, exc->opcode & 3 );
     }
     else
-    {
-
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      /* do cvt cut-in always in MIRP for sph */
-      if ( SUBPIXEL_HINTING_INFINALITY  &&
-           exc->ignore_x_mode           &&
-           exc->GS.gep0 == exc->GS.gep1 )
-      {
-        FT_F26Dot6  control_value_cutin = exc->GS.control_value_cutin;
-
-
-        if ( exc->GS.freeVector.x != 0                          &&
-             !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
-          control_value_cutin = 0;
-
-        if ( exc->GS.freeVector.y != 0                                 &&
-             ( exc->sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
-        {
-          if ( cur_dist < -64 )
-            cvt_dist -= 16;
-          else if ( cur_dist > 64 && cur_dist < 84 )
-            cvt_dist += 32;
-        }
-
-        delta = SUB_LONG( cvt_dist, org_dist );
-        if ( delta < 0 )
-          delta = NEG_LONG( delta );
-
-        if ( delta > control_value_cutin )
-          cvt_dist = org_dist;
-      }
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
       distance = Round_None( exc, cvt_dist, exc->opcode & 3 );
-    }
 
     /* minimum distance test */
 
@@ -6397,14 +5845,6 @@
       FT_F26Dot6  minimum_distance    = exc->GS.minimum_distance;
 
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-      if ( SUBPIXEL_HINTING_INFINALITY                        &&
-           exc->ignore_x_mode                                 &&
-           exc->GS.freeVector.x != 0                          &&
-           !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
-        minimum_distance = 0;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
       if ( org_dist >= 0 )
       {
         if ( distance < minimum_distance )
@@ -6417,51 +5857,10 @@
       }
     }
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    if ( SUBPIXEL_HINTING_INFINALITY &&
-         exc->ignore_x_mode          &&
-         exc->GS.freeVector.y != 0   )
-    {
-      FT_Int   B1, B2;
-
-
-      B1 = exc->zp1.cur[point].y;
-
-      /* Round moves if necessary */
-      if ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
-        distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist;
-
-      if ( ( exc->opcode & 16 ) == 0                               &&
-           ( exc->opcode & 8 ) == 0                                &&
-           ( exc->sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) )
-        distance += 64;
-
-      exc->func_move( exc,
-                      &exc->zp1,
-                      point,
-                      SUB_LONG( distance, cur_dist ) );
-
-      B2 = exc->zp1.cur[point].y;
-
-      /* Reverse move if necessary */
-      if ( ( exc->face->sph_compatibility_mode &&
-             ( B1 & 63 ) == 0                  &&
-             ( B2 & 63 ) != 0                  )                          ||
-           ( ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
-             ( B1 & 63 ) != 0                                           &&
-             ( B2 & 63 ) != 0                                           ) )
-        exc->func_move( exc,
-                        &exc->zp1,
-                        point,
-                        SUB_LONG( cur_dist, distance ) );
-    }
-    else
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
-      exc->func_move( exc,
-                      &exc->zp1,
-                      point,
-                      SUB_LONG( distance, cur_dist ) );
+    exc->func_move( exc,
+                    &exc->zp1,
+                    point,
+                    SUB_LONG( distance, cur_dist ) );
 
   Fail:
     exc->GS.rp1 = exc->GS.rp0;
@@ -6486,17 +5885,6 @@
     FT_F26Dot6  distance;
 
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    if ( SUBPIXEL_HINTING_INFINALITY                               &&
-         exc->ignore_x_mode                                        &&
-         exc->iup_called                                           &&
-         ( exc->sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) )
-    {
-      exc->error = FT_THROW( Invalid_Reference );
-      goto Fail;
-    }
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
     if ( exc->top < exc->GS.loop                  ||
          BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
     {
@@ -7055,16 +6443,6 @@
     contour = 0;
     point   = 0;
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    if ( SUBPIXEL_HINTING_INFINALITY &&
-         exc->ignore_x_mode          )
-    {
-      exc->iup_called = TRUE;
-      if ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_IUP )
-        return;
-    }
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
     do
     {
       end_point   = exc->pts.contours[contour] - exc->pts.first_point;
@@ -7137,14 +6515,6 @@
     FT_Long    B;
 
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    if ( SUBPIXEL_HINTING_INFINALITY                              &&
-         exc->ignore_x_mode                                       &&
-         exc->iup_called                                          &&
-         ( exc->sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) )
-      goto Fail;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
     P    = (FT_ULong)exc->func_cur_ppem( exc );
     nump = (FT_ULong)args[0];   /* some points theoretically may occur more
                                    than once, thus UShort isn't enough */
@@ -7197,87 +6567,21 @@
             B++;
           B *= 1L << ( 6 - exc->GS.delta_shift );
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
 
-          if ( SUBPIXEL_HINTING_INFINALITY )
+#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
+          /* See `ttinterp.h' for details on backward compatibility */
+          /* mode.                                                  */
+          if ( SUBPIXEL_HINTING_MINIMAL    &&
+               exc->backward_compatibility )
           {
-            /*
-             * Allow delta move if
-             *
-             * - not using ignore_x_mode rendering,
-             * - glyph is specifically set to allow it, or
-             * - glyph is composite and freedom vector is not in subpixel
-             *   direction.
-             */
-            if ( !exc->ignore_x_mode                                   ||
-                 ( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_DO_DELTAP ) ||
-                 ( exc->is_composite && exc->GS.freeVector.y != 0 )    )
+            if ( !( exc->iupx_called && exc->iupy_called )              &&
+                 ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
+                   ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y )        ) )
               exc->func_move( exc, &exc->zp0, A, B );
-
-            /* Otherwise, apply subpixel hinting and compatibility mode */
-            /* rules, always skipping deltas in subpixel direction.     */
-            else if ( exc->ignore_x_mode && exc->GS.freeVector.y != 0 )
-            {
-              FT_UShort  B1, B2;
-
-
-              /* save the y value of the point now; compare after move */
-              B1 = (FT_UShort)exc->zp0.cur[A].y;
-
-              /* Standard subpixel hinting: Allow y move for y-touched */
-              /* points.  This messes up DejaVu ...                    */
-              if ( !exc->face->sph_compatibility_mode          &&
-                   ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
-                exc->func_move( exc, &exc->zp0, A, B );
-
-              /* compatibility mode */
-              else if ( exc->face->sph_compatibility_mode                        &&
-                        !( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) )
-              {
-                if ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
-                  B = FT_PIX_ROUND( B1 + B ) - B1;
-
-                /* Allow delta move if using sph_compatibility_mode,   */
-                /* IUP has not been called, and point is touched on Y. */
-                if ( !exc->iup_called                            &&
-                     ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
-                  exc->func_move( exc, &exc->zp0, A, B );
-              }
-
-              B2 = (FT_UShort)exc->zp0.cur[A].y;
-
-              /* Reverse this move if it results in a disallowed move */
-              if ( exc->GS.freeVector.y != 0                          &&
-                   ( ( exc->face->sph_compatibility_mode          &&
-                       ( B1 & 63 ) == 0                           &&
-                       ( B2 & 63 ) != 0                           ) ||
-                     ( ( exc->sph_tweak_flags                   &
-                         SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP ) &&
-                       ( B1 & 63 ) != 0                           &&
-                       ( B2 & 63 ) != 0                           ) ) )
-                exc->func_move( exc, &exc->zp0, A, NEG_LONG( B ) );
-            }
           }
           else
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
-          {
-
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
-            /* See `ttinterp.h' for details on backward compatibility */
-            /* mode.                                                  */
-            if ( SUBPIXEL_HINTING_MINIMAL    &&
-                 exc->backward_compatibility )
-            {
-              if ( !( exc->iupx_called && exc->iupy_called )              &&
-                   ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
-                     ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y )        ) )
-                exc->func_move( exc, &exc->zp0, A, B );
-            }
-            else
 #endif
-              exc->func_move( exc, &exc->zp0, A, B );
-          }
+            exc->func_move( exc, &exc->zp0, A, B );
         }
       }
       else
@@ -7380,14 +6684,6 @@
    * GETINFO[]:    GET INFOrmation
    * Opcode range: 0x88
    * Stack:        uint32 --> uint32
-   *
-   * XXX: UNDOCUMENTED: Selector bits higher than 9 are currently (May
-   *      2015) not documented in the OpenType specification.
-   *
-   *      Selector bit 11 is incorrectly described as bit 8, while the
-   *      real meaning of bit 8 (vertical LCD subpixels) stays
-   *      undocumented.  The same mistake can be found in Greg Hitchcock's
-   *      whitepaper.
    */
   static void
   Ins_GETINFO( TT_ExecContext  exc,
@@ -7399,31 +6695,8 @@
 
     K = 0;
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    /*********************************
-     * RASTERIZER VERSION
-     * Selector Bit:  0
-     * Return Bit(s): 0-7
-     */
-    if ( SUBPIXEL_HINTING_INFINALITY &&
-         ( args[0] & 1 ) != 0        &&
-         exc->subpixel_hinting       )
-    {
-      if ( exc->ignore_x_mode )
-      {
-        /* if in ClearType backward compatibility mode,         */
-        /* we sometimes change the TrueType version dynamically */
-        K = exc->rasterizer_version;
-        FT_TRACE6(( "Setting rasterizer version %d\n",
-                    exc->rasterizer_version ));
-      }
-      else
-        K = TT_INTERPRETER_VERSION_38;
-    }
-    else
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-      if ( ( args[0] & 1 ) != 0 )
-        K = driver->interpreter_version;
+    if ( ( args[0] & 1 ) != 0 )
+      K = driver->interpreter_version;
 
     /*********************************
      * GLYPH ROTATED
@@ -7446,8 +6719,6 @@
      * VARIATION GLYPH
      * Selector Bit:  3
      * Return Bit(s): 10
-     *
-     * XXX: UNDOCUMENTED!
      */
     if ( (args[0] & 8 ) != 0 && exc->face->blend )
       K |= 1 << 10;
@@ -7522,89 +6793,6 @@
     }
 #endif
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
-    if ( SUBPIXEL_HINTING_INFINALITY                          &&
-         exc->rasterizer_version >= TT_INTERPRETER_VERSION_35 )
-    {
-
-      if ( exc->rasterizer_version >= 37 )
-      {
-        /*********************************
-         * HINTING FOR SUBPIXEL
-         * Selector Bit:  6
-         * Return Bit(s): 13
-         */
-        if ( ( args[0] & 64 ) != 0 && exc->subpixel_hinting )
-          K |= 1 << 13;
-
-        /*********************************
-         * COMPATIBLE WIDTHS ENABLED
-         * Selector Bit:  7
-         * Return Bit(s): 14
-         *
-         * Functionality still needs to be added
-         */
-        if ( ( args[0] & 128 ) != 0 && exc->compatible_widths )
-          K |= 1 << 14;
-
-        /*********************************
-         * VERTICAL LCD SUBPIXELS?
-         * Selector Bit:  8
-         * Return Bit(s): 15
-         *
-         * Functionality still needs to be added
-         */
-        if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd )
-          K |= 1 << 15;
-
-        /*********************************
-         * HINTING FOR BGR?
-         * Selector Bit:  9
-         * Return Bit(s): 16
-         *
-         * Functionality still needs to be added
-         */
-        if ( ( args[0] & 512 ) != 0 && exc->bgr )
-          K |= 1 << 16;
-
-        if ( exc->rasterizer_version >= 38 )
-        {
-          /*********************************
-           * SUBPIXEL POSITIONED?
-           * Selector Bit:  10
-           * Return Bit(s): 17
-           *
-           * Functionality still needs to be added
-           */
-          if ( ( args[0] & 1024 ) != 0 && exc->subpixel_positioned )
-            K |= 1 << 17;
-
-          /*********************************
-           * SYMMETRICAL SMOOTHING
-           * Selector Bit:  11
-           * Return Bit(s): 18
-           *
-           * Functionality still needs to be added
-           */
-          if ( ( args[0] & 2048 ) != 0 && exc->symmetrical_smoothing )
-            K |= 1 << 18;
-
-          /*********************************
-           * GRAY CLEARTYPE
-           * Selector Bit:  12
-           * Return Bit(s): 19
-           *
-           * Functionality still needs to be added
-           */
-          if ( ( args[0] & 4096 ) != 0 && exc->gray_cleartype )
-            K |= 1 << 19;
-        }
-      }
-    }
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
     args[0] = K;
   }
 
@@ -7739,25 +6927,14 @@
   /* documentation is in ttinterp.h */
 
   FT_EXPORT_DEF( FT_Error )
-  TT_RunIns( TT_ExecContext  exc )
+  TT_RunIns( void*  exec )
   {
+    TT_ExecContext  exc = (TT_ExecContext)exec;
+
     FT_ULong   ins_counter = 0;  /* executed instructions counter */
     FT_ULong   num_twilight_points;
     FT_UShort  i;
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    FT_Byte    opcode_pattern[1][2] = {
-                  /* #8 TypeMan Talk Align */
-                  {
-                    0x06, /* SPVTL   */
-                    0x7D, /* RDTG    */
-                  },
-                };
-    FT_UShort  opcode_patterns   = 1;
-    FT_UShort  opcode_pointer[1] = { 0 };
-    FT_UShort  opcode_size[1]    = { 1 };
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
 
     /* We restrict the number of twilight points to a reasonable,     */
     /* heuristic value to avoid slow execution of malformed bytecode. */
@@ -7835,9 +7012,6 @@
     Compute_Round( exc, (FT_Byte)exc->GS.round_state );
 
     /* These flags cancel execution of some opcodes after IUP is called */
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    exc->iup_called  = FALSE;
-#endif
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
     exc->iupx_called = FALSE;
     exc->iupy_called = FALSE;
@@ -7906,7 +7080,7 @@
         /* a variable number of arguments             */
 
         /* it is the job of the application to `activate' GX handling, */
-        /* this is, calling any of the GX API functions on the current */
+        /* that is, calling any of the GX API functions on the current */
         /* font to select a variation instance                         */
         if ( exc->face->blend )
           exc->new_top = exc->args + exc->face->blend->num_axis;
@@ -7927,39 +7101,6 @@
       exc->step_ins = TRUE;
       exc->error    = FT_Err_Ok;
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
-      if ( SUBPIXEL_HINTING_INFINALITY )
-      {
-        for ( i = 0; i < opcode_patterns; i++ )
-        {
-          if ( opcode_pointer[i] < opcode_size[i]                  &&
-               exc->opcode == opcode_pattern[i][opcode_pointer[i]] )
-          {
-            opcode_pointer[i] += 1;
-
-            if ( opcode_pointer[i] == opcode_size[i] )
-            {
-              FT_TRACE6(( "sph: opcode ptrn: %d, %s %s\n",
-                          i,
-                          exc->face->root.family_name,
-                          exc->face->root.style_name ));
-
-              switch ( i )
-              {
-              case 0:
-                break;
-              }
-              opcode_pointer[i] = 0;
-            }
-          }
-          else
-            opcode_pointer[i] = 0;
-        }
-      }
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
       {
         FT_Long*  args   = exc->stack + exc->args;
         FT_Byte   opcode = exc->opcode;
@@ -8466,7 +7607,7 @@
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
         case 0x91:
           /* it is the job of the application to `activate' GX handling, */
-          /* this is, calling any of the GX API functions on the current */
+          /* that is, calling any of the GX API functions on the current */
           /* font to select a variation instance                         */
           if ( exc->face->blend )
             Ins_GETVARIATION( exc, args );
@@ -8604,7 +7745,7 @@
 #else /* !TT_USE_BYTECODE_INTERPRETER */
 
   /* ANSI C doesn't like empty source files */
-  typedef int  _tt_interp_dummy;
+  typedef int  tt_interp_dummy_;
 
 #endif /* !TT_USE_BYTECODE_INTERPRETER */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h
index c54c053b29e03..e98e258fe7edb 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h
@@ -98,48 +98,6 @@ FT_BEGIN_HEADER
   } TT_CallRec, *TT_CallStack;
 
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
-  /**************************************************************************
-   *
-   * These structures define rules used to tweak subpixel hinting for
-   * various fonts.  "", 0, "", NULL value indicates to match any value.
-   */
-
-#define SPH_MAX_NAME_SIZE      32
-#define SPH_MAX_CLASS_MEMBERS  100
-
-  typedef struct  SPH_TweakRule_
-  {
-    const char      family[SPH_MAX_NAME_SIZE];
-    const FT_UInt   ppem;
-    const char      style[SPH_MAX_NAME_SIZE];
-    const FT_ULong  glyph;
-
-  } SPH_TweakRule;
-
-
-  typedef struct  SPH_ScaleRule_
-  {
-    const char      family[SPH_MAX_NAME_SIZE];
-    const FT_UInt   ppem;
-    const char      style[SPH_MAX_NAME_SIZE];
-    const FT_ULong  glyph;
-    const FT_ULong  scale;
-
-  } SPH_ScaleRule;
-
-
-  typedef struct  SPH_Font_Class_
-  {
-    const char  name[SPH_MAX_NAME_SIZE];
-    const char  member[SPH_MAX_CLASS_MEMBERS][SPH_MAX_NAME_SIZE];
-
-  } SPH_Font_Class;
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
-
   /**************************************************************************
    *
    * The main structure for the interpreter which collects all necessary
@@ -399,38 +357,6 @@ FT_BEGIN_HEADER
     FT_Bool            grayscale_cleartype;
 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */
 
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    TT_Round_Func      func_round_sphn;   /* subpixel rounding function */
-
-    FT_Bool            subpixel_hinting;  /* Using subpixel hinting?       */
-    FT_Bool            ignore_x_mode;     /* Standard rendering mode for   */
-                                          /* subpixel hinting.  On if gray */
-                                          /* or subpixel hinting is on.    */
-
-    /* The following 6 aren't fully implemented but here for MS rasterizer */
-    /* compatibility.                                                      */
-    FT_Bool            compatible_widths;     /* compatible widths?        */
-    FT_Bool            symmetrical_smoothing; /* symmetrical_smoothing?    */
-    FT_Bool            bgr;                   /* bgr instead of rgb?       */
-    FT_Bool            vertical_lcd;          /* long side of LCD subpixel */
-                                              /* rectangles is horizontal  */
-    FT_Bool            subpixel_positioned;   /* subpixel positioned       */
-                                              /* (DirectWrite ClearType)?  */
-    FT_Bool            gray_cleartype;        /* ClearType hinting but     */
-                                              /* grayscale rendering       */
-
-    FT_Int             rasterizer_version;    /* MS rasterizer version     */
-
-    FT_Bool            iup_called;            /* IUP called for glyph?     */
-
-    FT_ULong           sph_tweak_flags;       /* flags to control          */
-                                              /* hint tweaks               */
-
-    FT_ULong           sph_in_func_flags;     /* flags to indicate if in   */
-                                              /* special functions         */
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
     /* We maintain two counters (in addition to the instruction counter) */
     /* that act as loop detectors for LOOPCALL and jump opcodes with     */
     /* negative arguments.                                               */
@@ -460,14 +386,6 @@ FT_BEGIN_HEADER
   FT_LOCAL( void )
   TT_Clear_CodeRange( TT_ExecContext  exec,
                       FT_Int          range );
-
-
-  FT_LOCAL( FT_Error )
-  Update_Max( FT_Memory  memory,
-              FT_ULong*  size,
-              FT_ULong   multiplier,
-              void*      _pbuff,
-              FT_ULong   new_max );
 #endif /* TT_USE_BYTECODE_INTERPRETER */
 
 
@@ -536,7 +454,7 @@ FT_BEGIN_HEADER
    *   invoked by the TrueType debugger.
    */
   FT_EXPORT( FT_Error )
-  TT_RunIns( TT_ExecContext  exec );
+  TT_RunIns( void*  exec );
 
 
 FT_END_HEADER
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c
index 4a8873fd8c845..5b56af711df47 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c
@@ -312,7 +312,8 @@
 #define TRICK_SFNT_IDS_NUM_FACES  31
 
     static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES]
-                                       [TRICK_SFNT_IDS_PER_FACE] = {
+                                       [TRICK_SFNT_IDS_PER_FACE] =
+    {
 
 #define TRICK_SFNT_ID_cvt   0
 #define TRICK_SFNT_ID_fpgm  1
@@ -581,7 +582,7 @@
     FT_Bool   result = FALSE;
 
     TT_Face   face = (TT_Face)ttface;
-    FT_UInt   asize;
+    FT_ULong  asize;
     FT_ULong  i;
     FT_ULong  glyph_index = 0;
     FT_UInt   count       = 0;
@@ -589,7 +590,7 @@
 
     for( i = 0; i < face->num_locations; i++ )
     {
-      tt_face_get_location( face, i, &asize );
+      tt_face_get_location( ttface, i, &asize );
       if ( asize > 0 )
       {
         count += 1;
@@ -777,7 +778,6 @@
     }
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-
     {
       FT_UInt  instance_index = (FT_UInt)face_index >> 16;
 
@@ -785,14 +785,11 @@
       if ( FT_HAS_MULTIPLE_MASTERS( ttface ) &&
            instance_index > 0                )
       {
-        error = TT_Set_Named_Instance( face, instance_index );
+        error = FT_Set_Named_Instance( ttface, instance_index );
         if ( error )
           goto Exit;
-
-        tt_apply_mvar( face );
       }
     }
-
 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
 
     /* initialize standard glyph loading routines */
@@ -858,7 +855,7 @@
     face->cvt_program_size  = 0;
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-    tt_done_blend( face );
+    tt_done_blend( ttface );
     face->blend = NULL;
 #endif
   }
@@ -1338,39 +1335,29 @@
   /**************************************************************************
    *
    * @Function:
-   *   tt_size_reset
+   *   tt_size_reset_height
    *
    * @Description:
-   *   Reset a TrueType size when resolutions and character dimensions
-   *   have been changed.
+   *   Recompute a TrueType size's ascender, descender, and height
+   *   when resolutions and character dimensions have been changed.
+   *   Used for variation fonts as an iterator function.
    *
    * @Input:
-   *   size ::
-   *     A handle to the target size object.
-   *
-   *   only_height ::
-   *     Only recompute ascender, descender, and height;
-   *     this flag is used for variation fonts where
-   *     `tt_size_reset' is used as an iterator function.
+   *   ft_size ::
+   *     A handle to the target TT_Size object. This function will be called
+   *     through a `FT_Size_Reset_Func` pointer which takes `FT_Size`. This
+   *     function must take `FT_Size` as a result. The passed `FT_Size` is
+   *     expected to point to a `TT_Size`.
    */
   FT_LOCAL_DEF( FT_Error )
-  tt_size_reset( TT_Size  size,
-                 FT_Bool  only_height )
+  tt_size_reset_height( FT_Size  ft_size )
   {
-    TT_Face           face;
-    FT_Size_Metrics*  size_metrics;
-
-
-    face = (TT_Face)size->root.face;
-
-    /* nothing to do for CFF2 */
-    if ( face->is_cff2 )
-      return FT_Err_Ok;
+    TT_Size           size         = (TT_Size)ft_size;
+    TT_Face           face         = (TT_Face)size->root.face;
+    FT_Size_Metrics*  size_metrics = &size->hinted_metrics;
 
     size->ttmetrics.valid = FALSE;
 
-    size_metrics = &size->hinted_metrics;
-
     /* copy the result from base layer */
     *size_metrics = size->root.metrics;
 
@@ -1397,12 +1384,34 @@
 
     size->ttmetrics.valid = TRUE;
 
-    if ( only_height )
-    {
-      /* we must not recompute the scaling values here since       */
-      /* `tt_size_reset' was already called (with only_height = 0) */
-      return FT_Err_Ok;
-    }
+    return FT_Err_Ok;
+  }
+
+
+  /**************************************************************************
+   *
+   * @Function:
+   *   tt_size_reset
+   *
+   * @Description:
+   *   Reset a TrueType size when resolutions and character dimensions
+   *   have been changed.
+   *
+   * @Input:
+   *   size ::
+   *     A handle to the target size object.
+   */
+  FT_LOCAL_DEF( FT_Error )
+  tt_size_reset( TT_Size  size )
+  {
+    FT_Error          error;
+    TT_Face           face         = (TT_Face)size->root.face;
+    FT_Size_Metrics*  size_metrics = &size->hinted_metrics;
+
+
+    error = tt_size_reset_height( (FT_Size)size );
+    if ( error )
+      return error;
 
     if ( face->header.Flags & 8 )
     {
@@ -1472,9 +1481,6 @@
     TT_Driver  driver = (TT_Driver)ttdriver;
 
     driver->interpreter_version = TT_INTERPRETER_VERSION_35;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-    driver->interpreter_version = TT_INTERPRETER_VERSION_38;
-#endif
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
     driver->interpreter_version = TT_INTERPRETER_VERSION_40;
 #endif
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h
index bc6fbe7f19600..40eb37b4c43ea 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h
@@ -162,8 +162,6 @@ FT_BEGIN_HEADER
     FT_Long   end;            /* where does it end?                     */
     FT_UInt   opc;            /* function #, or instruction code        */
     FT_Bool   active;         /* is it active?                          */
-    FT_Bool   inline_delta;   /* is function that defines inline delta? */
-    FT_ULong  sph_fdef_flags; /* flags to identify special functions    */
 
   } TT_DefRecord, *TT_DefArray;
 
@@ -391,8 +389,10 @@ FT_BEGIN_HEADER
 #endif /* TT_USE_BYTECODE_INTERPRETER */
 
   FT_LOCAL( FT_Error )
-  tt_size_reset( TT_Size  size,
-                 FT_Bool  only_height );
+  tt_size_reset_height( FT_Size  size );
+
+  FT_LOCAL( FT_Error )
+  tt_size_reset( TT_Size  size );
 
 
   /**************************************************************************
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c
index e08bf309e3ca9..54a64c7b462fc 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c
@@ -180,10 +180,11 @@
 
 
   FT_LOCAL_DEF( FT_ULong )
-  tt_face_get_location( TT_Face   face,
-                        FT_UInt   gindex,
-                        FT_UInt  *asize )
+  tt_face_get_location( FT_Face    face,   /* TT_Face */
+                        FT_UInt    gindex,
+                        FT_ULong  *asize )
   {
+    TT_Face   ttface = (TT_Face)face;
     FT_ULong  pos1, pos2;
     FT_Byte*  p;
     FT_Byte*  p_limit;
@@ -191,12 +192,12 @@
 
     pos1 = pos2 = 0;
 
-    if ( gindex < face->num_locations )
+    if ( gindex < ttface->num_locations )
     {
-      if ( face->header.Index_To_Loc_Format != 0 )
+      if ( ttface->header.Index_To_Loc_Format != 0 )
       {
-        p       = face->glyph_locations + gindex * 4;
-        p_limit = face->glyph_locations + face->num_locations * 4;
+        p       = ttface->glyph_locations + gindex * 4;
+        p_limit = ttface->glyph_locations + ttface->num_locations * 4;
 
         pos1 = FT_NEXT_ULONG( p );
         pos2 = pos1;
@@ -206,8 +207,8 @@
       }
       else
       {
-        p       = face->glyph_locations + gindex * 2;
-        p_limit = face->glyph_locations + face->num_locations * 2;
+        p       = ttface->glyph_locations + gindex * 2;
+        p_limit = ttface->glyph_locations + ttface->num_locations * 2;
 
         pos1 = FT_NEXT_USHORT( p );
         pos2 = pos1;
@@ -221,30 +222,30 @@
     }
 
     /* Check broken location data. */
-    if ( pos1 > face->glyf_len )
+    if ( pos1 > ttface->glyf_len )
     {
       FT_TRACE1(( "tt_face_get_location:"
                   " too large offset (0x%08lx) found for glyph index %d,\n",
                   pos1, gindex ));
       FT_TRACE1(( "                     "
                   " exceeding the end of `glyf' table (0x%08lx)\n",
-                  face->glyf_len ));
+                  ttface->glyf_len ));
       *asize = 0;
       return 0;
     }
 
-    if ( pos2 > face->glyf_len )
+    if ( pos2 > ttface->glyf_len )
     {
       /* We try to sanitize the last `loca' entry. */
-      if ( gindex == face->num_locations - 2 )
+      if ( gindex == ttface->num_locations - 2 )
       {
         FT_TRACE1(( "tt_face_get_location:"
                     " too large size (%ld bytes) found for glyph index %d,\n",
                     pos2 - pos1, gindex ));
         FT_TRACE1(( "                     "
                     " truncating at the end of `glyf' table to %ld bytes\n",
-                    face->glyf_len - pos1 ));
-        pos2 = face->glyf_len;
+                    ttface->glyf_len - pos1 ));
+        pos2 = ttface->glyf_len;
       }
       else
       {
@@ -253,7 +254,7 @@
                     pos2, gindex + 1 ));
         FT_TRACE1(( "                     "
                     " exceeding the end of `glyf' table (0x%08lx)\n",
-                    face->glyf_len ));
+                    ttface->glyf_len ));
         *asize = 0;
         return 0;
       }
@@ -268,9 +269,9 @@
     /* We get (intentionally) a wrong, non-zero result in case the  */
     /* `glyf' table is missing.                                     */
     if ( pos2 >= pos1 )
-      *asize = (FT_UInt)( pos2 - pos1 );
+      *asize = (FT_ULong)( pos2 - pos1 );
     else
-      *asize = (FT_UInt)( face->glyf_len - pos1 );
+      *asize = (FT_ULong)( ttface->glyf_len - pos1 );
 
     return pos1;
   }
diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h
index 939e02fe4f158..ed229fa4616df 100644
--- a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h
+++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h
@@ -31,9 +31,9 @@ FT_BEGIN_HEADER
                      FT_Stream  stream );
 
   FT_LOCAL( FT_ULong )
-  tt_face_get_location( TT_Face   face,
-                        FT_UInt   gindex,
-                        FT_UInt  *asize );
+  tt_face_get_location( FT_Face    face,
+                        FT_UInt    gindex,
+                        FT_ULong  *asize );
 
   FT_LOCAL( void )
   tt_face_done_loca( TT_Face  face );
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c b/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c
index 608582c9a5739..d9b9398b013ad 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c
@@ -405,7 +405,7 @@
 #else /* T1_CONFIG_OPTION_NO_AFM */
 
   /* ANSI C doesn't like empty source files */
-  typedef int  _t1_afm_dummy;
+  typedef int  t1_afm_dummy_;
 
 #endif /* T1_CONFIG_OPTION_NO_AFM */
 
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c b/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c
index ded3b264e8517..a4cdf372a9e31 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c
@@ -56,28 +56,32 @@
    *
    */
 
-  static FT_Error
-  t1_get_glyph_name( T1_Face     face,
+  FT_CALLBACK_DEF( FT_Error )
+  t1_get_glyph_name( FT_Face     face,        /* T1_Face */
                      FT_UInt     glyph_index,
                      FT_Pointer  buffer,
                      FT_UInt     buffer_max )
   {
-    FT_STRCPYN( buffer, face->type1.glyph_names[glyph_index], buffer_max );
+    T1_Face  t1face = (T1_Face)face;
+
+
+    FT_STRCPYN( buffer, t1face->type1.glyph_names[glyph_index], buffer_max );
 
     return FT_Err_Ok;
   }
 
 
-  static FT_UInt
-  t1_get_name_index( T1_Face           face,
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_get_name_index( FT_Face           face,        /* T1_Face */
                      const FT_String*  glyph_name )
   {
-    FT_Int  i;
+    T1_Face  t1face = (T1_Face)face;
+    FT_Int   i;
 
 
-    for ( i = 0; i < face->type1.num_glyphs; i++ )
+    for ( i = 0; i < t1face->type1.num_glyphs; i++ )
     {
-      FT_String*  gname = face->type1.glyph_names[i];
+      FT_String*  gname = t1face->type1.glyph_names[i];
 
 
       if ( !ft_strcmp( glyph_name, gname ) )
@@ -90,8 +94,8 @@
 
   static const FT_Service_GlyphDictRec  t1_service_glyph_dict =
   {
-    (FT_GlyphDict_GetNameFunc)  t1_get_glyph_name,    /* get_name   */
-    (FT_GlyphDict_NameIndexFunc)t1_get_name_index     /* name_index */
+    t1_get_glyph_name,  /* FT_GlyphDict_GetNameFunc   get_name   */
+    t1_get_name_index   /* FT_GlyphDict_NameIndexFunc name_index */
   };
 
 
@@ -101,9 +105,12 @@
    */
 
   static const char*
-  t1_get_ps_name( T1_Face  face )
+  t1_get_ps_name( FT_Face  face )    /* T1_Face */
   {
-    return (const char*) face->type1.font_name;
+    T1_Face  t1face = (T1_Face)face;
+
+
+    return (const char*) t1face->type1.font_name;
   }
 
 
@@ -121,30 +128,28 @@
 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
   static const FT_Service_MultiMastersRec  t1_service_multi_masters =
   {
-    (FT_Get_MM_Func)        T1_Get_Multi_Master,    /* get_mm                    */
-    (FT_Set_MM_Design_Func) T1_Set_MM_Design,       /* set_mm_design             */
-    (FT_Set_MM_Blend_Func)  T1_Set_MM_Blend,        /* set_mm_blend              */
-    (FT_Get_MM_Blend_Func)  T1_Get_MM_Blend,        /* get_mm_blend              */
-    (FT_Get_MM_Var_Func)    T1_Get_MM_Var,          /* get_mm_var                */
-    (FT_Set_Var_Design_Func)T1_Set_Var_Design,      /* set_var_design            */
-    (FT_Get_Var_Design_Func)T1_Get_Var_Design,      /* get_var_design            */
-    (FT_Set_Instance_Func)  T1_Reset_MM_Blend,      /* set_instance              */
-    (FT_Set_MM_WeightVector_Func)
-                            T1_Set_MM_WeightVector, /* set_mm_weightvector       */
-    (FT_Get_MM_WeightVector_Func)
-                            T1_Get_MM_WeightVector, /* get_mm_weightvector       */
-    (FT_Var_Load_Delta_Set_Idx_Map_Func)
-                            NULL,                   /* load_delta_set_idx_map    */
-    (FT_Var_Load_Item_Var_Store_Func)
-                            NULL,                   /* load_item_variation_store */
-    (FT_Var_Get_Item_Delta_Func)
-                            NULL,                   /* get_item_delta            */
-    (FT_Var_Done_Item_Var_Store_Func)
-                            NULL,                   /* done_item_variation_store */
-    (FT_Var_Done_Delta_Set_Idx_Map_Func)
-                            NULL,                   /* done_delta_set_index_map  */
-    (FT_Get_Var_Blend_Func) NULL,                   /* get_var_blend             */
-    (FT_Done_Blend_Func)    T1_Done_Blend           /* done_blend                */
+    T1_Get_Multi_Master,    /* FT_Get_MM_Func             get_mm             */
+    T1_Set_MM_Design,       /* FT_Set_MM_Design_Func      set_mm_design      */
+    T1_Set_MM_Blend,        /* FT_Set_MM_Blend_Func       set_mm_blend       */
+    T1_Get_MM_Blend,        /* FT_Get_MM_Blend_Func       get_mm_blend       */
+    T1_Get_MM_Var,          /* FT_Get_MM_Var_Func         get_mm_var         */
+    T1_Set_Var_Design,      /* FT_Set_Var_Design_Func     set_var_design     */
+    T1_Get_Var_Design,      /* FT_Get_Var_Design_Func     get_var_design     */
+    T1_Reset_MM_Blend,      /* FT_Set_Named_Instance_Func set_named_instance */
+    NULL,   /* FT_Get_Default_Named_Instance_Func get_default_named_instance */
+    T1_Set_MM_WeightVector,
+            /* FT_Set_MM_WeightVector_Func        set_mm_weightvector        */
+    T1_Get_MM_WeightVector,
+            /* FT_Get_MM_WeightVector_Func        get_mm_weightvector        */
+
+    NULL,   /* FT_Construct_PS_Name_Func          construct_ps_name          */
+    NULL,   /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map     */
+    NULL,   /* FT_Var_Load_Item_Var_Store_Func    load_item_variation_store  */
+    NULL,   /* FT_Var_Get_Item_Delta_Func         get_item_delta             */
+    NULL,   /* FT_Var_Done_Item_Var_Store_Func    done_item_variation_store  */
+    NULL,   /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map   */
+    NULL,           /* FT_Get_Var_Blend_Func      get_var_blend              */
+    T1_Done_Blend   /* FT_Done_Blend_Func         done_blend                 */
   };
 #endif
 
@@ -632,11 +637,11 @@
 
   static const FT_Service_PsInfoRec  t1_service_ps_info =
   {
-    (PS_GetFontInfoFunc)   t1_ps_get_font_info,    /* ps_get_font_info    */
-    (PS_GetFontExtraFunc)  t1_ps_get_font_extra,   /* ps_get_font_extra   */
-    (PS_HasGlyphNamesFunc) t1_ps_has_glyph_names,  /* ps_has_glyph_names  */
-    (PS_GetFontPrivateFunc)t1_ps_get_font_private, /* ps_get_font_private */
-    (PS_GetFontValueFunc)  t1_ps_get_font_value,   /* ps_get_font_value   */
+    t1_ps_get_font_info,     /* PS_GetFontInfoFunc    ps_get_font_info    */
+    t1_ps_get_font_extra,    /* PS_GetFontExtraFunc   ps_get_font_extra   */
+    t1_ps_has_glyph_names,   /* PS_HasGlyphNamesFunc  ps_has_glyph_names  */
+    t1_ps_get_font_private,  /* PS_GetFontPrivateFunc ps_get_font_private */
+    t1_ps_get_font_value,    /* PS_GetFontValueFunc   ps_get_font_value   */
   };
 
 
@@ -656,9 +661,9 @@
   FT_DEFINE_SERVICE_PROPERTIESREC(
     t1_service_properties,
 
-    (FT_Properties_SetFunc)ps_property_set,      /* set_property */
-    (FT_Properties_GetFunc)ps_property_get )     /* get_property */
-
+    ps_property_set,  /* FT_Properties_SetFunc set_property */
+    ps_property_get   /* FT_Properties_GetFunc get_property */
+  )
 
   /*
    * SERVICE LIST
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1load.c b/src/java.desktop/share/native/libfreetype/src/type1/t1load.c
index 5a1afd8d9f5a5..be7cd0fd5e97e 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1load.c
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1load.c
@@ -73,7 +73,8 @@
 
 
 #ifdef FT_CONFIG_OPTION_INCREMENTAL
-#define IS_INCREMENTAL  FT_BOOL( face->root.internal->incremental_interface )
+#define IS_INCREMENTAL  \
+          FT_BOOL( FT_FACE( face )->internal->incremental_interface )
 #else
 #define IS_INCREMENTAL  0
 #endif
@@ -174,10 +175,11 @@
 
 
   FT_LOCAL_DEF( FT_Error )
-  T1_Get_Multi_Master( T1_Face           face,
+  T1_Get_Multi_Master( FT_Face           face,    /* T1_Face */
                        FT_Multi_Master*  master )
   {
-    PS_Blend  blend = face->blend;
+    T1_Face   t1face = (T1_Face)face;
+    PS_Blend  blend  = t1face->blend;
     FT_UInt   n;
     FT_Error  error;
 
@@ -225,11 +227,12 @@
     for ( j = 1; j < axismap->num_points; j++ )
     {
       if ( ncv <= axismap->blend_points[j] )
-        return INT_TO_FIXED( axismap->design_points[j - 1] ) +
-               ( axismap->design_points[j] - axismap->design_points[j - 1] ) *
-               FT_DivFix( ncv - axismap->blend_points[j - 1],
-                          axismap->blend_points[j] -
-                            axismap->blend_points[j - 1] );
+        return INT_TO_FIXED( axismap->design_points[j - 1] +
+                               FT_MulDiv( ncv - axismap->blend_points[j - 1],
+                                          axismap->design_points[j] -
+                                            axismap->design_points[j - 1],
+                                          axismap->blend_points[j] -
+                                            axismap->blend_points[j - 1] ) );
     }
 
     return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] );
@@ -284,16 +287,17 @@
    * arguments needed by the GX var distortable fonts.
    */
   FT_LOCAL_DEF( FT_Error )
-  T1_Get_MM_Var( T1_Face      face,
+  T1_Get_MM_Var( FT_Face      face,    /* T1_Face */
                  FT_MM_Var*  *master )
   {
-    FT_Memory        memory = face->root.memory;
-    FT_MM_Var       *mmvar = NULL;
+    T1_Face          t1face = (T1_Face)face;
+    FT_Memory        memory = FT_FACE_MEMORY( face );
+    FT_MM_Var       *mmvar  = NULL;
     FT_Multi_Master  mmaster;
     FT_Error         error;
     FT_UInt          i;
     FT_Fixed         axiscoords[T1_MAX_MM_AXIS];
-    PS_Blend         blend = face->blend;
+    PS_Blend         blend  = t1face->blend;
     FT_UShort*       axis_flags;
 
     FT_Offset  mmvar_size;
@@ -319,9 +323,9 @@
                                   sizeof ( FT_UShort ) );
     axis_size       = mmaster.num_axis * sizeof ( FT_Var_Axis );
 
-    if ( FT_ALLOC( mmvar, mmvar_size +
-                          axis_flags_size +
-                          axis_size ) )
+    if ( FT_QALLOC( mmvar, mmvar_size +
+                           axis_flags_size +
+                           axis_size ) )
       goto Exit;
 
     mmvar->num_axis        = mmaster.num_axis;
@@ -332,8 +336,7 @@
     /* to make `FT_Get_Var_Axis_Flags' work: the function expects that the */
     /* values directly follow the data of `FT_MM_Var'                      */
     axis_flags = (FT_UShort*)( (char*)mmvar + mmvar_size );
-    for ( i = 0; i < mmaster.num_axis; i++ )
-      axis_flags[i] = 0;
+    FT_ARRAY_ZERO( axis_flags, mmaster.num_axis );
 
     mmvar->axis       = (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size );
     mmvar->namedstyle = NULL;
@@ -438,32 +441,21 @@
 
 
   FT_LOCAL_DEF( FT_Error )
-  T1_Set_MM_Blend( T1_Face    face,
+  T1_Set_MM_Blend( FT_Face    face,       /* T1_Face */
                    FT_UInt    num_coords,
                    FT_Fixed*  coords )
   {
-    FT_Error  error;
-
-
-    error = t1_set_mm_blend( face, num_coords, coords );
-    if ( error )
-      return error;
-
-    if ( num_coords )
-      face->root.face_flags |= FT_FACE_FLAG_VARIATION;
-    else
-      face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
-
-    return FT_Err_Ok;
+    return t1_set_mm_blend( (T1_Face)face, num_coords, coords );
   }
 
 
   FT_LOCAL_DEF( FT_Error )
-  T1_Get_MM_Blend( T1_Face    face,
+  T1_Get_MM_Blend( FT_Face    face,       /* T1_Face */
                    FT_UInt    num_coords,
                    FT_Fixed*  coords )
   {
-    PS_Blend  blend = face->blend;
+    T1_Face   t1face = (T1_Face)face;
+    PS_Blend  blend  = t1face->blend;
 
     FT_Fixed  axiscoords[4];
     FT_UInt   i, nc;
@@ -494,11 +486,12 @@
 
 
   FT_LOCAL_DEF( FT_Error )
-  T1_Set_MM_WeightVector( T1_Face    face,
+  T1_Set_MM_WeightVector( FT_Face    face,          /* T1_Face */
                           FT_UInt    len,
                           FT_Fixed*  weightvector )
   {
-    PS_Blend  blend = face->blend;
+    T1_Face   t1face = (T1_Face)face;
+    PS_Blend  blend  = t1face->blend;
     FT_UInt   i, n;
 
 
@@ -522,11 +515,6 @@
 
       for ( ; i < blend->num_designs; i++ )
         blend->weight_vector[i] = (FT_Fixed)0;
-
-      if ( len )
-        face->root.face_flags |= FT_FACE_FLAG_VARIATION;
-      else
-        face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
     }
 
     return FT_Err_Ok;
@@ -534,11 +522,12 @@
 
 
   FT_LOCAL_DEF( FT_Error )
-  T1_Get_MM_WeightVector( T1_Face    face,
+  T1_Get_MM_WeightVector( FT_Face    face,          /* T1_Face */
                           FT_UInt*   len,
                           FT_Fixed*  weightvector )
   {
-    PS_Blend  blend = face->blend;
+    T1_Face   t1face = (T1_Face)face;
+    PS_Blend  blend  = t1face->blend;
     FT_UInt   i;
 
 
@@ -563,12 +552,13 @@
 
 
   FT_LOCAL_DEF( FT_Error )
-  T1_Set_MM_Design( T1_Face   face,
+  T1_Set_MM_Design( FT_Face   face,       /* T1_Face */
                     FT_UInt   num_coords,
                     FT_Long*  coords )
   {
+    T1_Face   t1face = (T1_Face)face;
     FT_Error  error;
-    PS_Blend  blend = face->blend;
+    PS_Blend  blend  = t1face->blend;
     FT_UInt   n;
     FT_Fixed  final_blends[T1_MAX_MM_DESIGNS];
 
@@ -634,15 +624,10 @@
       final_blends[n] = the_blend;
     }
 
-    error = t1_set_mm_blend( face, blend->num_axis, final_blends );
+    error = t1_set_mm_blend( t1face, blend->num_axis, final_blends );
     if ( error )
       return error;
 
-    if ( num_coords )
-      face->root.face_flags |= FT_FACE_FLAG_VARIATION;
-    else
-      face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
-
     return FT_Err_Ok;
   }
 
@@ -650,7 +635,7 @@
   /* MM fonts don't have named instances, so only the design is reset */
 
   FT_LOCAL_DEF( FT_Error )
-  T1_Reset_MM_Blend( T1_Face  face,
+  T1_Reset_MM_Blend( FT_Face  face,
                      FT_UInt  instance_index )
   {
     FT_UNUSED( instance_index );
@@ -665,7 +650,7 @@
    * arguments needed by the GX var distortable fonts.
    */
   FT_LOCAL_DEF( FT_Error )
-  T1_Set_Var_Design( T1_Face    face,
+  T1_Set_Var_Design( FT_Face    face,       /* T1_Face */
                      FT_UInt    num_coords,
                      FT_Fixed*  coords )
   {
@@ -684,11 +669,12 @@
 
 
   FT_LOCAL_DEF( FT_Error )
-  T1_Get_Var_Design( T1_Face    face,
+  T1_Get_Var_Design( FT_Face    face,       /* T1_Face */
                      FT_UInt    num_coords,
                      FT_Fixed*  coords )
   {
-    PS_Blend  blend = face->blend;
+    T1_Face   t1face = (T1_Face)face;
+    PS_Blend  blend  = t1face->blend;
 
     FT_Fixed  axiscoords[4];
     FT_UInt   i, nc;
@@ -720,10 +706,11 @@
 
 
   FT_LOCAL_DEF( void )
-  T1_Done_Blend( T1_Face  face )
+  T1_Done_Blend( FT_Face  face )    /* T1_Face */
   {
-    FT_Memory  memory = face->root.memory;
-    PS_Blend   blend  = face->blend;
+    T1_Face    t1face = (T1_Face)face;
+    FT_Memory  memory = FT_FACE_MEMORY( face );
+    PS_Blend   blend  = t1face->blend;
 
 
     if ( blend )
@@ -768,20 +755,22 @@
         dmap->num_points = 0;
       }
 
-      FT_FREE( face->blend );
+      FT_FREE( t1face->blend );
     }
   }
 
 
   static void
-  parse_blend_axis_types( T1_Face    face,
-                          T1_Loader  loader )
+  parse_blend_axis_types( FT_Face  face,     /* T1_Face */
+                          void*    loader_ )
   {
+    T1_Face      t1face = (T1_Face)face;
+    T1_Loader    loader = (T1_Loader)loader_;
     T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
     FT_Int       n, num_axis;
-    FT_Error     error = FT_Err_Ok;
+    FT_Error     error  = FT_Err_Ok;
     PS_Blend     blend;
-    FT_Memory    memory;
+    FT_Memory    memory = FT_FACE_MEMORY( face );
 
 
     /* take an array of objects */
@@ -801,14 +790,13 @@
     }
 
     /* allocate blend if necessary */
-    error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
+    error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis );
     if ( error )
       goto Exit;
 
     FT_TRACE4(( " [" ));
 
-    blend  = face->blend;
-    memory = face->root.memory;
+    blend = t1face->blend;
 
     /* each token is an immediate containing the name of the axis */
     for ( n = 0; n < num_axis; n++ )
@@ -856,14 +844,16 @@
 
 
   static void
-  parse_blend_design_positions( T1_Face    face,
-                                T1_Loader  loader )
+  parse_blend_design_positions( FT_Face  face,     /* T1_Face */
+                                void*    loader_ )
   {
+    T1_Face      t1face   = (T1_Face)face;
+    T1_Loader    loader   = (T1_Loader)loader_;
     T1_TokenRec  design_tokens[T1_MAX_MM_DESIGNS];
     FT_Int       num_designs;
     FT_Int       num_axis = 0; /* make compiler happy */
     T1_Parser    parser   = &loader->parser;
-    FT_Memory    memory   = face->root.memory;
+    FT_Memory    memory   = FT_FACE_MEMORY( face );
     FT_Error     error    = FT_Err_Ok;
     FT_Fixed*    design_pos[T1_MAX_MM_DESIGNS];
 
@@ -921,7 +911,7 @@
           }
 
           num_axis = n_axis;
-          error = t1_allocate_blend( face,
+          error = t1_allocate_blend( t1face,
                                      (FT_UInt)num_designs,
                                      (FT_UInt)num_axis );
           if ( error )
@@ -962,7 +952,7 @@
       loader->parser.root.limit  = old_limit;
 
       /* a valid BlendDesignPosition has been parsed */
-      blend = face->blend;
+      blend = t1face->blend;
       if ( blend->design_pos[0] )
         FT_FREE( blend->design_pos[0] );
 
@@ -980,9 +970,11 @@
 
 
   static void
-  parse_blend_design_map( T1_Face    face,
-                          T1_Loader  loader )
+  parse_blend_design_map( FT_Face  face,     /* T1_Face */
+                          void*    loader_ )
   {
+    T1_Face      t1face = (T1_Face)face;
+    T1_Loader    loader = (T1_Loader)loader_;
     FT_Error     error  = FT_Err_Ok;
     T1_Parser    parser = &loader->parser;
     PS_Blend     blend;
@@ -990,7 +982,7 @@
     FT_Int       n, num_axis;
     FT_Byte*     old_cursor;
     FT_Byte*     old_limit;
-    FT_Memory    memory = face->root.memory;
+    FT_Memory    memory = FT_FACE_MEMORY( face );
 
 
     T1_ToTokenArray( parser, axis_tokens,
@@ -1011,10 +1003,10 @@
     old_cursor = parser->root.cursor;
     old_limit  = parser->root.limit;
 
-    error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
+    error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis );
     if ( error )
       goto Exit;
-    blend = face->blend;
+    blend = t1face->blend;
 
     FT_TRACE4(( " [" ));
 
@@ -1089,15 +1081,17 @@
 
 
   static void
-  parse_weight_vector( T1_Face    face,
-                       T1_Loader  loader )
+  parse_weight_vector( FT_Face  face,     /* T1_Face */
+                       void*    loader_ )
   {
+    T1_Face      t1face = (T1_Face)face;
+    T1_Loader    loader = (T1_Loader)loader_;
     T1_TokenRec  design_tokens[T1_MAX_MM_DESIGNS];
     FT_Int       num_designs;
     FT_Error     error  = FT_Err_Ok;
-    FT_Memory    memory = face->root.memory;
+    FT_Memory    memory = FT_FACE_MEMORY( face );
     T1_Parser    parser = &loader->parser;
-    PS_Blend     blend  = face->blend;
+    PS_Blend     blend  = t1face->blend;
     T1_Token     token;
     FT_Int       n;
     FT_Byte*     old_cursor;
@@ -1122,10 +1116,10 @@
 
     if ( !blend || !blend->num_designs )
     {
-      error = t1_allocate_blend( face, (FT_UInt)num_designs, 0 );
+      error = t1_allocate_blend( t1face, (FT_UInt)num_designs, 0 );
       if ( error )
         goto Exit;
-      blend = face->blend;
+      blend = t1face->blend;
     }
     else if ( blend->num_designs != (FT_UInt)num_designs )
     {
@@ -1173,11 +1167,15 @@
   /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def           */
   /* we're only interested in the number of array elements */
   static void
-  parse_buildchar( T1_Face    face,
-                   T1_Loader  loader )
+  parse_buildchar( FT_Face  face,     /* T1_Face */
+                   void*    loader_ )
   {
-    face->len_buildchar = (FT_UInt)T1_ToFixedArray( &loader->parser,
-                                                    0, NULL, 0 );
+    T1_Face    t1face = (T1_Face)face;
+    T1_Loader  loader = (T1_Loader)loader_;
+
+
+    t1face->len_buildchar = (FT_UInt)T1_ToFixedArray( &loader->parser,
+                                                      0, NULL, 0 );
 
 #ifdef FT_DEBUG_LEVEL_TRACE
     {
@@ -1185,7 +1183,7 @@
 
 
       FT_TRACE4(( " [" ));
-      for ( i = 0; i < face->len_buildchar; i++ )
+      for ( i = 0; i < t1face->len_buildchar; i++ )
         FT_TRACE4(( " 0" ));
 
       FT_TRACE4(( "]\n" ));
@@ -1335,9 +1333,10 @@
 
 
   static void
-  parse_private( T1_Face    face,
-                 T1_Loader  loader )
+  parse_private( FT_Face  face,
+                 void*    loader_ )
   {
+    T1_Loader  loader = (T1_Loader)loader_;
     FT_UNUSED( face );
 
     loader->keywords_encountered |= T1_PRIVATE;
@@ -1401,13 +1400,14 @@
   /* and `/CharStrings' dictionaries.                                */
 
   static void
-  t1_parse_font_matrix( T1_Face    face,
-                        T1_Loader  loader )
+  t1_parse_font_matrix( FT_Face  face,     /* T1_Face */
+                        void*    loader_ )
   {
+    T1_Face     t1face = (T1_Face)face;
+    T1_Loader   loader = (T1_Loader)loader_;
     T1_Parser   parser = &loader->parser;
-    FT_Matrix*  matrix = &face->type1.font_matrix;
-    FT_Vector*  offset = &face->type1.font_offset;
-    FT_Face     root   = (FT_Face)&face->root;
+    FT_Matrix*  matrix = &t1face->type1.font_matrix;
+    FT_Vector*  offset = &t1face->type1.font_offset;
     FT_Fixed    temp[6];
     FT_Fixed    temp_scale;
     FT_Int      result;
@@ -1443,7 +1443,7 @@
     if ( temp_scale != 0x10000L )
     {
       /* set units per EM based on FontMatrix values */
-      root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
+      face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
 
       temp[0] = FT_DivFix( temp[0], temp_scale );
       temp[1] = FT_DivFix( temp[1], temp_scale );
@@ -1471,14 +1471,16 @@
 
 
   static void
-  parse_encoding( T1_Face    face,
-                  T1_Loader  loader )
+  parse_encoding( FT_Face  face,     /* T1_Face */
+                  void*    loader_ )
   {
+    T1_Face    t1face = (T1_Face)face;
+    T1_Loader  loader = (T1_Loader)loader_;
     T1_Parser  parser = &loader->parser;
     FT_Byte*   cur;
     FT_Byte*   limit  = parser->root.limit;
 
-    PSAux_Service  psaux = (PSAux_Service)face->psaux;
+    PSAux_Service  psaux = (PSAux_Service)t1face->psaux;
 
 
     T1_Skip_Spaces( parser );
@@ -1494,7 +1496,7 @@
     /* and we must load it now                               */
     if ( ft_isdigit( *cur ) || *cur == '[' )
     {
-      T1_Encoding  encode          = &face->type1.encoding;
+      T1_Encoding  encode          = &t1face->type1.encoding;
       FT_Int       count, array_size, n;
       PS_Table     char_table      = &loader->encoding_table;
       FT_Memory    memory          = parser->root.memory;
@@ -1676,7 +1678,7 @@
       FT_TRACE4(( "]\n" ));
 #endif
 
-      face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
+      t1face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
       parser->root.cursor       = cur;
     }
 
@@ -1687,21 +1689,21 @@
       if ( cur + 17 < limit                                            &&
            ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
       {
-        face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
+        t1face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
         FT_TRACE4(( " StandardEncoding\n" ));
       }
 
       else if ( cur + 15 < limit                                          &&
                 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
       {
-        face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
+        t1face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
         FT_TRACE4(( " ExpertEncoding\n" ));
       }
 
       else if ( cur + 18 < limit                                             &&
                 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
       {
-        face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
+        t1face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
         FT_TRACE4(( " ISOLatin1Encoding\n" ));
       }
 
@@ -1715,9 +1717,11 @@
 
 
   static void
-  parse_subrs( T1_Face    face,
-               T1_Loader  loader )
+  parse_subrs( FT_Face  face,     /* T1_Face */
+               void*    loader_ )
   {
+    T1_Face    t1face = (T1_Face)face;
+    T1_Loader  loader = (T1_Loader)loader_;
     T1_Parser  parser = &loader->parser;
     PS_Table   table  = &loader->subrs;
     FT_Memory  memory = parser->root.memory;
@@ -1725,7 +1729,7 @@
     FT_Int     num_subrs;
     FT_UInt    count;
 
-    PSAux_Service  psaux = (PSAux_Service)face->psaux;
+    PSAux_Service  psaux = (PSAux_Service)t1face->psaux;
 
 
     T1_Skip_Spaces( parser );
@@ -1769,7 +1773,7 @@
        */
 
       FT_TRACE0(( "parse_subrs: adjusting number of subroutines"
-                  " (from %d to %ld)\n",
+                  " (from %d to %zu)\n",
                   num_subrs,
                   ( parser->root.limit - parser->root.cursor ) >> 3 ));
       num_subrs = ( parser->root.limit - parser->root.cursor ) >> 3;
@@ -1857,7 +1861,7 @@
       /*                                                         */
       /* thanks to Tom Kacvinsky for pointing this out           */
       /*                                                         */
-      if ( face->type1.private_dict.lenIV >= 0 )
+      if ( t1face->type1.private_dict.lenIV >= 0 )
       {
         FT_Byte*  temp = NULL;
 
@@ -1865,7 +1869,7 @@
         /* some fonts define empty subr records -- this is not totally */
         /* compliant to the specification (which says they should at   */
         /* least contain a `return'), but we support them anyway       */
-        if ( size < (FT_ULong)face->type1.private_dict.lenIV )
+        if ( size < (FT_ULong)t1face->type1.private_dict.lenIV )
         {
           error = FT_THROW( Invalid_File_Format );
           goto Fail;
@@ -1876,9 +1880,11 @@
           goto Fail;
         FT_MEM_COPY( temp, base, size );
         psaux->t1_decrypt( temp, size, 4330 );
-        size -= (FT_ULong)face->type1.private_dict.lenIV;
-        error = T1_Add_Table( table, (FT_Int)idx,
-                              temp + face->type1.private_dict.lenIV, size );
+        size -= (FT_ULong)t1face->type1.private_dict.lenIV;
+        error = T1_Add_Table( table,
+                              (FT_Int)idx,
+                              temp + t1face->type1.private_dict.lenIV,
+                              size );
         FT_FREE( temp );
       }
       else
@@ -1910,9 +1916,11 @@
 
 
   static void
-  parse_charstrings( T1_Face    face,
-                     T1_Loader  loader )
+  parse_charstrings( FT_Face  face,     /* T1_Face */
+                     void*    loader_ )
   {
+    T1_Face        t1face       = (T1_Face)face;
+    T1_Loader      loader       = (T1_Loader)loader_;
     T1_Parser      parser       = &loader->parser;
     PS_Table       code_table   = &loader->charstrings;
     PS_Table       name_table   = &loader->glyph_names;
@@ -1920,7 +1928,7 @@
     FT_Memory      memory       = parser->root.memory;
     FT_Error       error;
 
-    PSAux_Service  psaux        = (PSAux_Service)face->psaux;
+    PSAux_Service  psaux        = (PSAux_Service)t1face->psaux;
 
     FT_Byte*       cur          = parser->root.cursor;
     FT_Byte*       limit        = parser->root.limit;
@@ -1940,7 +1948,7 @@
     if ( num_glyphs > ( limit - cur ) >> 3 )
     {
       FT_TRACE0(( "parse_charstrings: adjusting number of glyphs"
-                  " (from %d to %ld)\n",
+                  " (from %d to %zu)\n",
                   num_glyphs, ( limit - cur ) >> 3 ));
       num_glyphs = ( limit - cur ) >> 3;
     }
@@ -2069,13 +2077,13 @@
           notdef_found = 1;
         }
 
-        if ( face->type1.private_dict.lenIV >= 0 &&
+        if ( t1face->type1.private_dict.lenIV >= 0 &&
              n < num_glyphs + TABLE_EXTEND       )
         {
           FT_Byte*  temp = NULL;
 
 
-          if ( size <= (FT_ULong)face->type1.private_dict.lenIV )
+          if ( size <= (FT_ULong)t1face->type1.private_dict.lenIV )
           {
             error = FT_THROW( Invalid_File_Format );
             goto Fail;
@@ -2086,9 +2094,11 @@
             goto Fail;
           FT_MEM_COPY( temp, base, size );
           psaux->t1_decrypt( temp, size, 4330 );
-          size -= (FT_ULong)face->type1.private_dict.lenIV;
-          error = T1_Add_Table( code_table, n,
-                                temp + face->type1.private_dict.lenIV, size );
+          size -= (FT_ULong)t1face->type1.private_dict.lenIV;
+          error = T1_Add_Table( code_table,
+                                n,
+                                temp + t1face->type1.private_dict.lenIV,
+                                size );
           FT_FREE( temp );
         }
         else
@@ -2570,7 +2580,7 @@
     {
       FT_ERROR(( "T1_Open_Face:"
                  " number-of-designs != 2 ^^ number-of-axes\n" ));
-      T1_Done_Blend( face );
+      T1_Done_Blend( FT_FACE( face ) );
     }
 
     if ( face->blend                                                     &&
@@ -2590,15 +2600,15 @@
     /* font as a normal PS font                                     */
     if ( face->blend                                             &&
          ( !face->blend->num_designs || !face->blend->num_axis ) )
-      T1_Done_Blend( face );
+      T1_Done_Blend( FT_FACE( face ) );
 
     /* the font may have no valid WeightVector */
     if ( face->blend && !face->blend->weight_vector )
-      T1_Done_Blend( face );
+      T1_Done_Blend( FT_FACE( face ) );
 
     /* the font may have no valid BlendDesignPositions */
     if ( face->blend && !face->blend->design_pos[0] )
-      T1_Done_Blend( face );
+      T1_Done_Blend( FT_FACE( face ) );
 
     /* the font may have no valid BlendDesignMap */
     if ( face->blend )
@@ -2609,7 +2619,7 @@
       for ( i = 0; i < face->blend->num_axis; i++ )
         if ( !face->blend->design_map[i].num_points )
         {
-          T1_Done_Blend( face );
+          T1_Done_Blend( FT_FACE( face ) );
           break;
         }
     }
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1load.h b/src/java.desktop/share/native/libfreetype/src/type1/t1load.h
index f8511cccf6074..d8c9d2d8abe93 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1load.h
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1load.h
@@ -66,52 +66,52 @@ FT_BEGIN_HEADER
 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
 
   FT_LOCAL( FT_Error )
-  T1_Get_Multi_Master( T1_Face           face,
+  T1_Get_Multi_Master( FT_Face           face,
                        FT_Multi_Master*  master );
 
   FT_LOCAL( FT_Error )
-  T1_Get_MM_Var( T1_Face      face,
+  T1_Get_MM_Var( FT_Face      face,
                  FT_MM_Var*  *master );
 
   FT_LOCAL( FT_Error )
-  T1_Set_MM_Blend( T1_Face    face,
+  T1_Set_MM_Blend( FT_Face    face,
                    FT_UInt    num_coords,
                    FT_Fixed*  coords );
 
   FT_LOCAL( FT_Error )
-  T1_Get_MM_Blend( T1_Face    face,
+  T1_Get_MM_Blend( FT_Face    face,
                    FT_UInt    num_coords,
                    FT_Fixed*  coords );
 
   FT_LOCAL( FT_Error )
-  T1_Set_MM_Design( T1_Face   face,
+  T1_Set_MM_Design( FT_Face   face,
                     FT_UInt   num_coords,
                     FT_Long*  coords );
 
   FT_LOCAL( FT_Error )
-  T1_Reset_MM_Blend( T1_Face  face,
+  T1_Reset_MM_Blend( FT_Face  face,
                      FT_UInt  instance_index );
 
   FT_LOCAL( FT_Error )
-  T1_Get_Var_Design( T1_Face    face,
+  T1_Get_Var_Design( FT_Face    face,
                      FT_UInt    num_coords,
                      FT_Fixed*  coords );
 
   FT_LOCAL( FT_Error )
-  T1_Set_Var_Design( T1_Face    face,
+  T1_Set_Var_Design( FT_Face    face,
                      FT_UInt    num_coords,
                      FT_Fixed*  coords );
 
   FT_LOCAL( void )
-  T1_Done_Blend( T1_Face  face );
+  T1_Done_Blend( FT_Face  face );
 
   FT_LOCAL( FT_Error )
-  T1_Set_MM_WeightVector( T1_Face    face,
+  T1_Set_MM_WeightVector( FT_Face    face,
                           FT_UInt    len,
                           FT_Fixed*  weightvector );
 
   FT_LOCAL( FT_Error )
-  T1_Get_MM_WeightVector( T1_Face    face,
+  T1_Get_MM_WeightVector( FT_Face    face,
                           FT_UInt*   len,
                           FT_Fixed*  weightvector );
 
diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c b/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c
index 1bb2f15f3a8d9..69e4fd5065e5f 100644
--- a/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c
+++ b/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c
@@ -167,8 +167,7 @@
       FT_Module  module;
 
 
-      module = FT_Get_Module( slot->face->driver->root.library,
-                              "pshinter" );
+      module = FT_Get_Module( slot->library, "pshinter" );
       if ( module )
       {
         T1_Hints_Funcs  funcs;
@@ -227,7 +226,7 @@
       face->len_buildchar = 0;
     }
 
-    T1_Done_Blend( face );
+    T1_Done_Blend( t1face );
     face->blend = NULL;
 #endif
 
@@ -290,7 +289,8 @@
    *
    * @Input:
    *   stream ::
-   *     input stream where to load font data.
+   *     Dummy argument for compatibility with the `FT_Face_InitFunc` API.
+   *     Ignored.  The stream should be passed through `face->root.stream`.
    *
    *   face_index ::
    *     The index of the font face in the resource.
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh
index 11aeda5297f4e..d7b2b13e4d38c 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh
@@ -397,7 +397,6 @@ struct IndexSubtableRecord
     TRACE_SERIALIZE (this);
 
     auto *subtable = c->serializer->start_embed ();
-    if (unlikely (!subtable)) return_trace (false);
     if (unlikely (!c->serializer->extend_min (subtable))) return_trace (false);
 
     auto *old_subtable = get_subtable (base);
@@ -545,7 +544,8 @@ struct IndexSubtableArray
                 const IndexSubtableRecord*>> *lookup /* OUT */) const
   {
     bool start_glyph_is_set = false;
-    for (hb_codepoint_t new_gid = 0; new_gid < c->plan->num_output_glyphs (); new_gid++)
+    unsigned num_glyphs = c->plan->num_output_glyphs ();
+    for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
     {
       hb_codepoint_t old_gid;
       if (unlikely (!c->plan->old_gid_for_new_gid (new_gid, &old_gid))) continue;
@@ -576,9 +576,6 @@ struct IndexSubtableArray
   {
     TRACE_SUBSET (this);
 
-    auto *dst = c->serializer->start_embed ();
-    if (unlikely (!dst)) return_trace (false);
-
     hb_vector_t> lookup;
     build_lookup (c, bitmap_size_context, &lookup);
     if (unlikely (!c->serializer->propagate_error (lookup)))
@@ -993,12 +990,10 @@ CBLC::subset (hb_subset_context_t *c) const
 {
   TRACE_SUBSET (this);
 
-  auto *cblc_prime = c->serializer->start_embed ();
-
   // Use a vector as a secondary buffer as the tables need to be built in parallel.
   hb_vector_t cbdt_prime;
 
-  if (unlikely (!cblc_prime)) return_trace (false);
+  auto *cblc_prime = c->serializer->start_embed ();
   if (unlikely (!c->serializer->extend_min (cblc_prime))) return_trace (false);
   cblc_prime->version = version;
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh
index e7c34a83fd6f6..fb2c42a88f080 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh
@@ -53,6 +53,7 @@ struct Paint;
 struct hb_paint_context_t :
        hb_dispatch_context_t
 {
+  const char *get_name () { return "PAINT"; }
   template 
   return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); }
   static return_t default_return_value () { return hb_empty_t (); }
@@ -68,6 +69,8 @@ public:
   unsigned int palette_index;
   hb_color_t foreground;
   VarStoreInstancer &instancer;
+  hb_map_t current_glyphs;
+  hb_map_t current_layers;
   int depth_left = HB_MAX_NESTING_LEVEL;
   int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
 
@@ -261,6 +264,7 @@ struct Variable
 
   void paint_glyph (hb_paint_context_t *c) const
   {
+    TRACE_PAINT (this);
     value.paint_glyph (c, varIdxBase);
   }
 
@@ -281,7 +285,7 @@ struct Variable
   public:
   VarIdx varIdxBase;
   public:
-  DEFINE_SIZE_STATIC (4 + T::static_size);
+  DEFINE_SIZE_MIN (VarIdx::static_size + T::min_size);
 };
 
 template 
@@ -315,6 +319,7 @@ struct NoVariable
 
   void paint_glyph (hb_paint_context_t *c) const
   {
+    TRACE_PAINT (this);
     value.paint_glyph (c, varIdxBase);
   }
 
@@ -332,7 +337,7 @@ struct NoVariable
 
   T      value;
   public:
-  DEFINE_SIZE_STATIC (T::static_size);
+  DEFINE_SIZE_MIN (T::min_size);
 };
 
 // Color structures
@@ -409,7 +414,6 @@ struct ColorLine
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (this);
-    if (unlikely (!out)) return_trace (false);
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
     if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
@@ -559,6 +563,7 @@ struct Affine2x3
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     c->funcs->push_transform (c->data,
                               xx.to_float (c->instancer (varIdxBase, 0)),
                               yx.to_float (c->instancer (varIdxBase, 1)),
@@ -640,6 +645,7 @@ struct PaintSolid
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     hb_bool_t is_foreground;
     hb_color_t color;
 
@@ -694,6 +700,7 @@ struct PaintLinearGradient
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     hb_color_line_t cl = {
       (void *) &(this+colorLine),
       (this+colorLine).static_get_color_stops, c,
@@ -760,6 +767,7 @@ struct PaintRadialGradient
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     hb_color_line_t cl = {
       (void *) &(this+colorLine),
       (this+colorLine).static_get_color_stops, c,
@@ -824,6 +832,7 @@ struct PaintSweepGradient
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     hb_color_line_t cl = {
       (void *) &(this+colorLine),
       (this+colorLine).static_get_color_stops, c,
@@ -875,6 +884,7 @@ struct PaintGlyph
 
   void paint_glyph (hb_paint_context_t *c) const
   {
+    TRACE_PAINT (this);
     c->funcs->push_inverse_root_transform (c->data, c->font);
     c->funcs->push_clip_glyph (c->data, gid, c->font);
     c->funcs->push_root_transform (c->data, c->font);
@@ -947,6 +957,7 @@ struct PaintTransform
 
   void paint_glyph (hb_paint_context_t *c) const
   {
+    TRACE_PAINT (this);
     (this+transform).paint_glyph (c);
     c->recurse (this+src);
     c->funcs->pop_transform (c->data);
@@ -991,6 +1002,7 @@ struct PaintTranslate
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float ddx = dx + c->instancer (varIdxBase, 0);
     float ddy = dy + c->instancer (varIdxBase, 1);
 
@@ -1039,6 +1051,7 @@ struct PaintScale
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
     float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
 
@@ -1089,6 +1102,7 @@ struct PaintScaleAroundCenter
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
     float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
     float tCenterX = centerX + c->instancer (varIdxBase, 2);
@@ -1142,6 +1156,7 @@ struct PaintScaleUniform
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float s = scale.to_float (c->instancer (varIdxBase, 0));
 
     bool p1 = c->funcs->push_scale (c->data, s, s);
@@ -1189,6 +1204,7 @@ struct PaintScaleUniformAroundCenter
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float s = scale.to_float (c->instancer (varIdxBase, 0));
     float tCenterX = centerX + c->instancer (varIdxBase, 1);
     float tCenterY = centerY + c->instancer (varIdxBase, 2);
@@ -1240,6 +1256,7 @@ struct PaintRotate
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float a = angle.to_float (c->instancer (varIdxBase, 0));
 
     bool p1 = c->funcs->push_rotate (c->data, a);
@@ -1287,6 +1304,7 @@ struct PaintRotateAroundCenter
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float a = angle.to_float (c->instancer (varIdxBase, 0));
     float tCenterX = centerX + c->instancer (varIdxBase, 1);
     float tCenterY = centerY + c->instancer (varIdxBase, 2);
@@ -1341,6 +1359,7 @@ struct PaintSkew
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
     float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
 
@@ -1391,6 +1410,7 @@ struct PaintSkewAroundCenter
 
   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
   {
+    TRACE_PAINT (this);
     float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
     float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
     float tCenterX = centerX + c->instancer (varIdxBase, 2);
@@ -1426,20 +1446,24 @@ struct PaintComposite
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    if (!out->src.serialize_subset (c, src, this, instancer)) return_trace (false);
-    return_trace (out->backdrop.serialize_subset (c, backdrop, this, instancer));
+    bool ret = false;
+    ret |= out->src.serialize_subset (c, src, this, instancer);
+    ret |= out->backdrop.serialize_subset (c, backdrop, this, instancer);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
+                  c->check_ops (this->min_size) && // PainComposite can get exponential
                   src.sanitize (c, this) &&
                   backdrop.sanitize (c, this));
   }
 
   void paint_glyph (hb_paint_context_t *c) const
   {
+    TRACE_PAINT (this);
     c->recurse (this+backdrop);
     c->funcs->push_group (c->data);
     c->recurse (this+src);
@@ -1514,10 +1538,10 @@ struct ClipBoxFormat2 : Variable
     value.get_clip_box(clip_box, instancer);
     if (instancer)
     {
-      clip_box.xMin += _hb_roundf (instancer (varIdxBase, 0));
-      clip_box.yMin += _hb_roundf (instancer (varIdxBase, 1));
-      clip_box.xMax += _hb_roundf (instancer (varIdxBase, 2));
-      clip_box.yMax += _hb_roundf (instancer (varIdxBase, 3));
+      clip_box.xMin += roundf (instancer (varIdxBase, 0));
+      clip_box.yMin += roundf (instancer (varIdxBase, 1));
+      clip_box.xMax += roundf (instancer (varIdxBase, 2));
+      clip_box.yMax += roundf (instancer (varIdxBase, 3));
     }
   }
 };
@@ -1898,15 +1922,16 @@ struct LayerList : Array32OfOffset32To
     auto *out = c->serializer->start_embed (this);
     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
 
+    bool ret = false;
     for (const auto& _ : + hb_enumerate (*this)
                          | hb_filter (c->plan->colrv1_layers, hb_first))
 
     {
       auto *o = out->serialize_append (c->serializer);
-      if (unlikely (!o) || !o->serialize_subset (c, _.second, this, instancer))
-        return_trace (false);
+      if (unlikely (!o)) return_trace (false);
+      ret |= o->serialize_subset (c, _.second, this, instancer);
     }
-    return_trace (true);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -2167,7 +2192,7 @@ struct COLR
     if (version == 0 && (!base_it || !layer_it))
       return_trace (false);
 
-    COLR *colr_prime = c->serializer->start_embed ();
+    auto *colr_prime = c->serializer->start_embed ();
     if (unlikely (!c->serializer->extend_min (colr_prime)))  return_trace (false);
 
     if (version == 0)
@@ -2284,6 +2309,7 @@ struct COLR
                                  &(this+varIdxMap),
                                  hb_array (font->coords, font->num_coords));
     hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
+    c.current_glyphs.add (glyph);
 
     if (version == 1)
     {
@@ -2399,18 +2425,42 @@ hb_paint_context_t::recurse (const Paint &paint)
 
 void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
 {
+  TRACE_PAINT (this);
   const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
   for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
   {
+    if (unlikely (c->current_layers.has (i)))
+      continue;
+
+    c->current_layers.add (i);
+
     const Paint &paint = paint_offset_lists.get_paint (i);
     c->funcs->push_group (c->data);
     c->recurse (paint);
     c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
+
+    c->current_layers.del (i);
   }
 }
 
 void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
 {
+  TRACE_PAINT (this);
+
+  if (unlikely (c->current_glyphs.has (gid)))
+    return;
+
+  c->current_glyphs.add (gid);
+
+  c->funcs->push_inverse_root_transform (c->data, c->font);
+  if (c->funcs->color_glyph (c->data, gid, c->font))
+  {
+    c->funcs->pop_transform (c->data);
+    c->current_glyphs.del (gid);
+    return;
+  }
+  c->funcs->pop_transform (c->data);
+
   const COLR *colr_table = c->get_colr_table ();
   const Paint *paint = colr_table->get_base_glyph_paint (gid);
 
@@ -2429,6 +2479,8 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
 
   if (has_clip_box)
     c->funcs->pop_clip (c->data);
+
+  c->current_glyphs.del (gid);
 }
 
 } /* namespace OT */
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh
index 55d770e928360..20b06ab13e378 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh
@@ -48,7 +48,6 @@ struct SBIXGlyph
   {
     TRACE_SERIALIZE (this);
     SBIXGlyph* new_glyph = c->start_embed ();
-    if (unlikely (!new_glyph)) return_trace (nullptr);
     if (unlikely (!c->extend_min (new_glyph))) return_trace (nullptr);
 
     new_glyph->xOffset = xOffset;
@@ -143,7 +142,6 @@ struct SBIXStrike
     unsigned int num_output_glyphs = c->plan->num_output_glyphs ();
 
     auto* out = c->serializer->start_embed ();
-    if (unlikely (!out)) return_trace (false);
     auto snap = c->serializer->snapshot ();
     if (unlikely (!c->serializer->extend (out, num_output_glyphs + 1))) return_trace (false);
     out->ppem = ppem;
@@ -388,7 +386,6 @@ struct sbix
     TRACE_SERIALIZE (this);
 
     auto *out = c->serializer->start_embed> ();
-    if (unlikely (!out)) return_trace (false);
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
     hb_vector_t*> new_strikes;
@@ -423,8 +420,6 @@ struct sbix
   {
     TRACE_SUBSET (this);
 
-    sbix *sbix_prime = c->serializer->start_embed ();
-    if (unlikely (!sbix_prime)) return_trace (false);
     if (unlikely (!c->serializer->embed (this->version))) return_trace (false);
     if (unlikely (!c->serializer->embed (this->flags))) return_trace (false);
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh
index 016a9402e3cd2..257b2a3361ac5 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh
@@ -57,6 +57,9 @@ struct Coverage
   public:
   DEFINE_SIZE_UNION (2, format);
 
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -113,22 +116,33 @@ struct Coverage
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (this))) return_trace (false);
 
-    unsigned count = 0;
+    unsigned count = hb_len (glyphs);
     unsigned num_ranges = 0;
     hb_codepoint_t last = (hb_codepoint_t) -2;
+    hb_codepoint_t max = 0;
+    bool unsorted = false;
     for (auto g: glyphs)
     {
+      if (last != (hb_codepoint_t) -2 && g < last)
+        unsorted = true;
       if (last + 1 != g)
         num_ranges++;
       last = g;
-      count++;
+      if (g > max) max = g;
     }
-    u.format = count <= num_ranges * 3 ? 1 : 2;
+    u.format = !unsorted && count <= num_ranges * 3 ? 1 : 2;
 
 #ifndef HB_NO_BEYOND_64K
-    if (count && last > 0xFFFFu)
+    if (max > 0xFFFFu)
       u.format += 2;
+    if (unlikely (max > 0xFFFFFFu))
+#else
+    if (unlikely (max > 0xFFFFu))
 #endif
+    {
+      c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW);
+      return_trace (false);
+    }
 
     switch (u.format)
     {
@@ -148,8 +162,8 @@ struct Coverage
     auto it =
     + iter ()
     | hb_take (c->plan->source->get_num_glyphs ())
-    | hb_filter (c->plan->glyph_map_gsub)
     | hb_map_retains_sorting (c->plan->glyph_map_gsub)
+    | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; })
     ;
 
     // Cache the iterator result as it will be iterated multiple times
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh
index 1fa92df3620a8..995f1ebdbda4b 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh
@@ -79,7 +79,7 @@ struct CoverageFormat1_3
   {
     if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2)
     {
-      for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+      for (auto g : *glyphs)
         if (get_coverage (g) != NOT_COVERED)
           return true;
       return false;
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh
index 2650d198f4c97..d47c7eea99252 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh
@@ -95,19 +95,26 @@ struct CoverageFormat2_4
     unsigned count = 0;
     unsigned range = (unsigned) -1;
     last = (hb_codepoint_t) -2;
+    unsigned unsorted = false;
     for (auto g: glyphs)
     {
       if (last + 1 != g)
       {
+        if (unlikely (last != (hb_codepoint_t) -2 && last + 1 > g))
+          unsorted = true;
+
         range++;
-        rangeRecord[range].first = g;
-        rangeRecord[range].value = count;
+        rangeRecord.arrayZ[range].first = g;
+        rangeRecord.arrayZ[range].value = count;
       }
-      rangeRecord[range].last = g;
+      rangeRecord.arrayZ[range].last = g;
       last = g;
       count++;
     }
 
+    if (unlikely (unsorted))
+      rangeRecord.as_array ().qsort (RangeRecord::cmp_range);
+
     return_trace (true);
   }
 
@@ -115,7 +122,7 @@ struct CoverageFormat2_4
   {
     if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
     {
-      for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+      for (auto g : *glyphs)
         if (get_coverage (g) != NOT_COVERED)
           return true;
       return false;
@@ -185,8 +192,8 @@ struct CoverageFormat2_4
         if (__more__ ())
         {
           unsigned int old = coverage;
-          j = c->rangeRecord[i].first;
-          coverage = c->rangeRecord[i].value;
+          j = c->rangeRecord.arrayZ[i].first;
+          coverage = c->rangeRecord.arrayZ[i].value;
           if (unlikely (coverage != old + 1))
           {
             /* Broken table. Skip. Important to avoid DoS.
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/RangeRecord.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/RangeRecord.hh
index a62629fad3439..85aacace9a764 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/RangeRecord.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/RangeRecord.hh
@@ -51,6 +51,18 @@ struct RangeRecord
   int cmp (hb_codepoint_t g) const
   { return g < first ? -1 : g <= last ? 0 : +1; }
 
+  HB_INTERNAL static int cmp_range (const void *pa, const void *pb) {
+    const RangeRecord *a = (const RangeRecord *) pa;
+    const RangeRecord *b = (const RangeRecord *) pb;
+    if (a->first < b->first) return -1;
+    if (a->first > b->first) return +1;
+    if (a->last < b->last) return -1;
+    if (a->last > b->last) return +1;
+    if (a->value < b->value) return -1;
+    if (a->value > b->value) return +1;
+    return 0;
+  }
+
   unsigned get_population () const
   {
     if (unlikely (last < first)) return 0;
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh
index 0cf5753b0e5fd..98543f56c3bcc 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh
@@ -29,9 +29,10 @@
 #ifndef OT_LAYOUT_GDEF_GDEF_HH
 #define OT_LAYOUT_GDEF_GDEF_HH
 
-#include "../../../hb-ot-layout-common.hh"
+#include "../../../hb-ot-var-common.hh"
 
 #include "../../../hb-font.hh"
+#include "../../../hb-cache.hh"
 
 
 namespace OT {
@@ -48,8 +49,6 @@ struct AttachPoint : Array16Of
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out)) return_trace (false);
-
     return_trace (out->serialize (c->serializer, + iter ()));
   }
 };
@@ -201,22 +200,23 @@ struct CaretValueFormat3
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out)) return_trace (false);
     if (!c->serializer->embed (caretValueFormat)) return_trace (false);
     if (!c->serializer->embed (coordinate)) return_trace (false);
 
     unsigned varidx = (this+deviceTable).get_variation_index ();
-    if (c->plan->layout_variation_idx_delta_map.has (varidx))
+    hb_pair_t *new_varidx_delta;
+    if (!c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta))
+      return_trace (false);
+
+    uint32_t new_varidx = hb_first (*new_varidx_delta);
+    int delta = hb_second (*new_varidx_delta);
+    if (delta != 0)
     {
-      int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (varidx));
-      if (delta != 0)
-      {
-        if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
-          return_trace (false);
-      }
+      if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+        return_trace (false);
     }
 
-    if (c->plan->all_axes_pinned)
+    if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
       return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
 
     if (!c->serializer->embed (deviceTable))
@@ -441,6 +441,16 @@ struct MarkGlyphSetsFormat1
   bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
   { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
 
+  template 
+  void collect_coverage (hb_vector_t &sets) const
+  {
+     for (const auto &offset : coverage)
+     {
+       const auto &cov = this+offset;
+       cov.collect_coverage (sets.push ());
+     }
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
@@ -494,6 +504,15 @@ struct MarkGlyphSets
     }
   }
 
+  template 
+  void collect_coverage (hb_vector_t &sets) const
+  {
+    switch (u.format) {
+    case 1: u.format1.collect_coverage (sets); return;
+    default:return;
+    }
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
@@ -585,6 +604,26 @@ struct GDEFVersion1_2
                   (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
   }
 
+  static void remap_varidx_after_instantiation (const hb_map_t& varidx_map,
+                                                hb_hashmap_t>& layout_variation_idx_delta_map /* IN/OUT */)
+  {
+    /* varidx_map is empty which means varstore is empty after instantiation,
+     * no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX.
+     * varidx_map doesn't have original varidx, indicating delta row is all
+     * zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
+    for (auto _ : layout_variation_idx_delta_map.iter_ref ())
+    {
+      /* old_varidx->(varidx, delta) mapping generated for subsetting, then this
+       * varidx is used as key of varidx_map during instantiation */
+      uint32_t varidx = _.second.first;
+      uint32_t *new_varidx;
+      if (varidx_map.has (varidx, &new_varidx))
+        _.second.first = *new_varidx;
+      else
+        _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+    }
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
@@ -607,6 +646,22 @@ struct GDEFVersion1_2
     {
       if (c->plan->all_axes_pinned)
         out->varStore = 0;
+      else if (c->plan->normalized_coords)
+      {
+        if (varStore)
+        {
+          item_variations_t item_vars;
+          if (item_vars.instantiate (this+varStore, c->plan, true, true,
+                                     c->plan->gdef_varstore_inner_maps.as_array ()))
+            subset_varstore = out->varStore.serialize_serialize (c->serializer,
+                                                                 item_vars.has_long_word (),
+                                                                 c->plan->axis_tags,
+                                                                 item_vars.get_region_list (),
+                                                                 item_vars.get_vardata_encodings ());
+          remap_varidx_after_instantiation (item_vars.get_varidx_map (),
+                                            c->plan->layout_variation_idx_delta_map);
+        }
+      }
       else
         subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
     }
@@ -858,27 +913,79 @@ struct GDEF
         hb_blob_destroy (table.get_blob ());
         table = hb_blob_get_empty ();
       }
+
+#ifndef HB_NO_GDEF_CACHE
+      table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests);
+#endif
     }
     ~accelerator_t () { table.destroy (); }
 
+    unsigned int get_glyph_props (hb_codepoint_t glyph) const
+    {
+      unsigned v;
+
+#ifndef HB_NO_GDEF_CACHE
+      if (glyph_props_cache.get (glyph, &v))
+        return v;
+#endif
+
+      v = table->get_glyph_props (glyph);
+
+#ifndef HB_NO_GDEF_CACHE
+      if (likely (table.get_blob ())) // Don't try setting if we are the null instance!
+        glyph_props_cache.set (glyph, v);
+#endif
+
+      return v;
+
+    }
+
+    bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+    {
+      return
+#ifndef HB_NO_GDEF_CACHE
+             mark_glyph_set_digests[set_index].may_have (glyph_id) &&
+#endif
+             table->mark_set_covers (set_index, glyph_id);
+    }
+
     hb_blob_ptr_t table;
+#ifndef HB_NO_GDEF_CACHE
+    hb_vector_t mark_glyph_set_digests;
+    mutable hb_cache_t<21, 3, 8> glyph_props_cache;
+#endif
   };
 
   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
   { get_lig_caret_list ().collect_variation_indices (c); }
 
   void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
+                                       const hb_vector_t& normalized_coords,
+                                       bool calculate_delta, /* not pinned at default */
+                                       bool no_variations, /* all axes pinned */
                                        hb_hashmap_t> *layout_variation_idx_delta_map /* OUT */) const
   {
     if (!has_var_store ()) return;
-    if (layout_variation_indices->is_empty ()) return;
+    const VariationStore &var_store = get_var_store ();
+    float *store_cache = var_store.create_cache ();
 
     unsigned new_major = 0, new_minor = 0;
     unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
     for (unsigned idx : layout_variation_indices->iter ())
     {
+      int delta = 0;
+      if (calculate_delta)
+        delta = roundf (var_store.get_delta (idx, normalized_coords.arrayZ,
+                                             normalized_coords.length, store_cache));
+
+      if (no_variations)
+      {
+        layout_variation_idx_delta_map->set (idx, hb_pair_t (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
+        continue;
+      }
+
       uint16_t major = idx >> 16;
-      if (major >= get_var_store ().get_sub_table_count ()) break;
+      if (major >= var_store.get_sub_table_count ()) break;
       if (major != last_major)
       {
         new_minor = 0;
@@ -886,14 +993,11 @@ struct GDEF
       }
 
       unsigned new_idx = (new_major << 16) + new_minor;
-      if (!layout_variation_idx_delta_map->has (idx))
-        continue;
-      int delta = hb_second (layout_variation_idx_delta_map->get (idx));
-
       layout_variation_idx_delta_map->set (idx, hb_pair_t (new_idx, delta));
       ++new_minor;
       last_major = major;
     }
+    var_store.destroy_cache (store_cache);
   }
 
   protected:
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh
index e7e3c5c6d1ea4..23821a49c77ad 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh
@@ -25,7 +25,9 @@ struct AnchorFormat3
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
+    if (unlikely (!c->check_struct (this))) return_trace (false);
+
+    return_trace (xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
   }
 
   void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
@@ -35,9 +37,9 @@ struct AnchorFormat3
     *x = font->em_fscale_x (xCoordinate);
     *y = font->em_fscale_y (yCoordinate);
 
-    if (font->x_ppem || font->num_coords)
+    if ((font->x_ppem || font->num_coords) && xDeviceTable.sanitize (&c->sanitizer, this))
       *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache);
-    if (font->y_ppem || font->num_coords)
+    if ((font->y_ppem || font->num_coords) && yDeviceTable.sanitize (&c->sanitizer, this))
       *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache);
   }
 
@@ -45,15 +47,19 @@ struct AnchorFormat3
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out)) return_trace (false);
     if (unlikely (!c->serializer->embed (format))) return_trace (false);
     if (unlikely (!c->serializer->embed (xCoordinate))) return_trace (false);
     if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false);
 
     unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
-    if (c->plan->layout_variation_idx_delta_map.has (x_varidx))
+    if (x_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
     {
-      int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (x_varidx));
+      hb_pair_t *new_varidx_delta;
+      if (!c->plan->layout_variation_idx_delta_map.has (x_varidx, &new_varidx_delta))
+        return_trace (false);
+
+      x_varidx = hb_first (*new_varidx_delta);
+      int delta = hb_second (*new_varidx_delta);
       if (delta != 0)
       {
         if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta,
@@ -63,9 +69,14 @@ struct AnchorFormat3
     }
 
     unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
-    if (c->plan->layout_variation_idx_delta_map.has (y_varidx))
+    if (y_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
     {
-      int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (y_varidx));
+      hb_pair_t *new_varidx_delta;
+      if (!c->plan->layout_variation_idx_delta_map.has (y_varidx, &new_varidx_delta))
+        return_trace (false);
+
+      y_varidx = hb_first (*new_varidx_delta);
+      int delta = hb_second (*new_varidx_delta);
       if (delta != 0)
       {
         if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta,
@@ -74,7 +85,10 @@ struct AnchorFormat3
       }
     }
 
-    if (c->plan->all_axes_pinned)
+    /* in case that all axes are pinned or no variations after instantiation,
+     * both var_idxes will be mapped to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
+    if (x_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX &&
+        y_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
       return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
 
     if (!c->serializer->embed (xDeviceTable)) return_trace (false);
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh
index c442efa1eaa89..b61f1413ea5a9 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorMatrix.hh
@@ -21,18 +21,25 @@ struct AnchorMatrix
     if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
     unsigned int count = rows * cols;
     if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
+
+    if (c->lazy_some_gpos)
+      return_trace (true);
+
     for (unsigned int i = 0; i < count; i++)
       if (!matrixZ[i].sanitize (c, this)) return_trace (false);
     return_trace (true);
   }
 
-  const Anchor& get_anchor (unsigned int row, unsigned int col,
+  const Anchor& get_anchor (hb_ot_apply_context_t *c,
+                            unsigned int row, unsigned int col,
                             unsigned int cols, bool *found) const
   {
     *found = false;
     if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
-    *found = !matrixZ[row * cols + col].is_null ();
-    return this+matrixZ[row * cols + col];
+    auto &offset = matrixZ[row * cols + col];
+    if (unlikely (!offset.sanitize (&c->sanitizer, this))) return Null (Anchor);
+    *found = !offset.is_null ();
+    return this+offset;
   }
 
   template serializer->extend_min (out)))  return_trace (false);
 
     out->rows = num_rows;
+    bool ret = false;
     for (const unsigned i : index_iter)
     {
       auto *offset = c->serializer->embed (matrixZ[i]);
       if (!offset) return_trace (false);
-      offset->serialize_subset (c, matrixZ[i], this);
+      ret |= offset->serialize_subset (c, matrixZ[i], this);
     }
 
-    return_trace (true);
+    return_trace (ret);
   }
 };
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh
index 13a435d00bfae..3a2957af1a543 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh
@@ -24,16 +24,17 @@ struct EntryExitRecord
     (src_base+exitAnchor).collect_variation_indices (c);
   }
 
-  EntryExitRecord* subset (hb_subset_context_t *c,
-                           const void *src_base) const
+  bool subset (hb_subset_context_t *c,
+               const void *src_base) const
   {
     TRACE_SERIALIZE (this);
     auto *out = c->serializer->embed (this);
-    if (unlikely (!out)) return_trace (nullptr);
+    if (unlikely (!out)) return_trace (false);
 
-    out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
-    out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
-    return_trace (out);
+    bool ret = false;
+    ret |= out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
+    ret |= out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
+    return_trace (ret);
   }
 
   protected:
@@ -91,7 +92,13 @@ struct CursivePosFormat1
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
+    if (unlikely (!coverage.sanitize (c, this)))
+      return_trace (false);
+
+    if (c->lazy_some_gpos)
+      return_trace (entryExitRecord.sanitize_shallow (c));
+    else
+      return_trace (entryExitRecord.sanitize (c, this));
   }
 
   bool intersects (const hb_set_t *glyphs) const
@@ -119,19 +126,21 @@ struct CursivePosFormat1
     hb_buffer_t *buffer = c->buffer;
 
     const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
-    if (!this_record.entryAnchor) return_trace (false);
+    if (!this_record.entryAnchor ||
+        unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false);
 
     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
+    skippy_iter.reset_fast (buffer->idx);
     unsigned unsafe_from;
-    if (!skippy_iter.prev (&unsafe_from))
+    if (unlikely (!skippy_iter.prev (&unsafe_from)))
     {
       buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
       return_trace (false);
     }
 
     const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
-    if (!prev_record.exitAnchor)
+    if (!prev_record.exitAnchor ||
+        unlikely (!prev_record.exitAnchor.sanitize (&c->sanitizer, this)))
     {
       buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
       return_trace (false);
@@ -200,8 +209,8 @@ struct CursivePosFormat1
      * Arabic. */
     unsigned int child  = i;
     unsigned int parent = j;
-    hb_position_t x_offset = entry_x - exit_x;
-    hb_position_t y_offset = entry_y - exit_y;
+    hb_position_t x_offset = roundf (entry_x - exit_x);
+    hb_position_t y_offset = roundf (entry_y - exit_y);
     if  (!(c->lookup_props & LookupFlag::RightToLeft))
     {
       unsigned int k = child;
@@ -278,7 +287,6 @@ struct CursivePosFormat1
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
     auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out)) return_trace (false);
 
     auto it =
     + hb_zip (this+coverage, entryExitRecord)
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh
index 9493ec987e864..f4af98b25fd73 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh
@@ -156,7 +156,7 @@ GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
   {
     for (unsigned i = 0; i < len; i++)
       if (unlikely (pos[i].y_offset))
-        pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset);
+        pos[i].x_offset += roundf (font->slant_xy * pos[i].y_offset);
   }
 }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh
index a2d807cc3206c..eecdb95a95fc2 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh
@@ -27,6 +27,7 @@ struct LigatureArray : List16OfOffset16To
     auto *out = c->serializer->start_embed (this);
     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
 
+    bool ret = false;
     for (const auto _ : + hb_zip (coverage, *this)
                   | hb_filter (glyphset, hb_first))
     {
@@ -38,13 +39,13 @@ struct LigatureArray : List16OfOffset16To
           + hb_range (src.rows * class_count)
           | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
           ;
-      matrix->serialize_subset (c,
-                                _.second,
-                                this,
-                                src.rows,
-                                indexes);
+      ret |= matrix->serialize_subset (c,
+                                       _.second,
+                                       this,
+                                       src.rows,
+                                       indexes);
     }
-    return_trace (this->len);
+    return_trace (ret);
   }
 };
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh
index e80c05cd2708a..abae8f1c607ca 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh
@@ -28,7 +28,7 @@ struct MarkArray : Array16Of        /* Array of MarkRecords--in Cove
 
     const Anchor& mark_anchor = this + record.markAnchor;
     bool found;
-    const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
+    const Anchor& glyph_anchor = anchors.get_anchor (c, glyph_index, mark_class, class_count, &found);
     /* If this subtable doesn't have an anchor for this base and this class,
      * return false such that the subsequent subtables have a chance at it. */
     if (unlikely (!found)) return_trace (false);
@@ -82,10 +82,10 @@ struct MarkArray : Array16Of        /* Array of MarkRecords--in Cove
     | hb_map (hb_second)
     ;
 
+    bool ret = false;
     unsigned new_length = 0;
     for (const auto& mark_record : mark_iter) {
-      if (unlikely (!mark_record.subset (c, this, klass_mapping)))
-        return_trace (false);
+      ret |= mark_record.subset (c, this, klass_mapping);
       new_length++;
     }
 
@@ -93,7 +93,7 @@ struct MarkArray : Array16Of        /* Array of MarkRecords--in Cove
                                                 HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)))
       return_trace (false);
 
-    return_trace (true);
+    return_trace (ret);
   }
 };
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh
index bf129a4a0e976..e633f7a1be108 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh
@@ -197,9 +197,10 @@ struct MarkBasePosFormat1_2
     if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
       return_trace (false);
 
-    out->markArray.serialize_subset (c, markArray, this,
-                                     (this+markCoverage).iter (),
-                                     &klass_mapping);
+    if (unlikely (!out->markArray.serialize_subset (c, markArray, this,
+                                                    (this+markCoverage).iter (),
+                                                    &klass_mapping)))
+      return_trace (false);
 
     unsigned basecount = (this+baseArray).rows;
     auto base_iter =
@@ -228,11 +229,9 @@ struct MarkBasePosFormat1_2
       ;
     }
 
-    out->baseArray.serialize_subset (c, baseArray, this,
-                                     base_iter.len (),
-                                     base_indexes.iter ());
-
-    return_trace (true);
+    return_trace (out->baseArray.serialize_subset (c, baseArray, this,
+                                                   base_iter.len (),
+                                                   base_indexes.iter ()));
   }
 };
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh
index 30bba4b0d8c33..cf4cbae9a3f70 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh
@@ -169,7 +169,7 @@ struct MarkLigPosFormat1_2
   {
     TRACE_SUBSET (this);
     const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
+    const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
 
     auto *out = c->serializer->start_embed (*this);
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
@@ -195,23 +195,24 @@ struct MarkLigPosFormat1_2
     if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
       return_trace (false);
 
-    out->markArray.serialize_subset (c, markArray, this,
-                                     (this+markCoverage).iter (),
-                                     &klass_mapping);
+    if (unlikely (!out->markArray.serialize_subset (c, markArray, this,
+                                                    (this+markCoverage).iter (),
+                                                    &klass_mapping)))
+      return_trace (false);
 
     auto new_ligature_coverage =
     + hb_iter (this + ligatureCoverage)
-    | hb_filter (glyphset)
+    | hb_take ((this + ligatureArray).len)
     | hb_map_retains_sorting (glyph_map)
+    | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; })
     ;
 
     if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
       return_trace (false);
 
-    out->ligatureArray.serialize_subset (c, ligatureArray, this,
-                                         hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
-
-    return_trace (true);
+    return_trace (out->ligatureArray.serialize_subset (c, ligatureArray, this,
+                                                       hb_iter (this+ligatureCoverage),
+                                                       classCount, &klass_mapping));
   }
 
 };
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh
index fbcebb8044169..ea196581aff85 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh
@@ -100,16 +100,16 @@ struct MarkMarkPosFormat1_2
 
     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
+    skippy_iter.reset_fast (buffer->idx);
     skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags);
     unsigned unsafe_from;
-    if (!skippy_iter.prev (&unsafe_from))
+    if (unlikely (!skippy_iter.prev (&unsafe_from)))
     {
       buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
       return_trace (false);
     }
 
-    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]))
+    if (likely (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])))
     {
       buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
       return_trace (false);
@@ -183,9 +183,10 @@ struct MarkMarkPosFormat1_2
     if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
       return_trace (false);
 
-    out->mark1Array.serialize_subset (c, mark1Array, this,
-                                      (this+mark1Coverage).iter (),
-                                      &klass_mapping);
+    if (unlikely (!out->mark1Array.serialize_subset (c, mark1Array, this,
+                                                     (this+mark1Coverage).iter (),
+                                                     &klass_mapping)))
+      return_trace (false);
 
     unsigned mark2count = (this+mark2Array).rows;
     auto mark2_iter =
@@ -214,9 +215,10 @@ struct MarkMarkPosFormat1_2
       ;
     }
 
-    out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ());
+    return_trace (out->mark2Array.serialize_subset (c, mark2Array, this,
+                                                    mark2_iter.len (),
+                                                    mark2_indexes.iter ()));
 
-    return_trace (true);
   }
 };
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkRecord.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkRecord.hh
index a7d489d2a51f0..1230025267511 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkRecord.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkRecord.hh
@@ -24,17 +24,16 @@ struct MarkRecord
     return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
   }
 
-  MarkRecord *subset (hb_subset_context_t    *c,
-                      const void             *src_base,
-                      const hb_map_t         *klass_mapping) const
+  bool subset (hb_subset_context_t    *c,
+               const void             *src_base,
+               const hb_map_t         *klass_mapping) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
-    if (unlikely (!out)) return_trace (nullptr);
+    if (unlikely (!out)) return_trace (false);
 
     out->klass = klass_mapping->get (klass);
-    out->markAnchor.serialize_subset (c, markAnchor, src_base);
-    return_trace (out);
+    return_trace (out->markAnchor.serialize_subset (c, markAnchor, src_base));
   }
 
   void collect_variation_indices (hb_collect_variation_indices_context_t *c,
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh
index 468eccfd50169..478c72df750bf 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh
@@ -110,9 +110,9 @@ struct PairPosFormat1_3
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
+    skippy_iter.reset_fast (buffer->idx);
     unsigned unsafe_to;
-    if (!skippy_iter.next (&unsafe_to))
+    if (unlikely (!skippy_iter.next (&unsafe_to)))
     {
       buffer->unsafe_to_concat (buffer->idx, unsafe_to);
       return_trace (false);
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh
index 17486dddaf7de..ce6eec4f20697 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh
@@ -50,13 +50,13 @@ struct PairPosFormat2_4
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
     unsigned int stride = HBUINT16::static_size * (len1 + len2);
-    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
     unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
     return_trace (c->check_range ((const void *) values,
                                   count,
-                                  record_size) &&
-                  valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
-                  valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
+                                  stride) &&
+                  (c->lazy_some_gpos ||
+                   (valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
+                    valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride))));
   }
 
   bool intersects (const hb_set_t *glyphs) const
@@ -131,40 +131,46 @@ struct PairPosFormat2_4
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
+    skippy_iter.reset_fast (buffer->idx);
     unsigned unsafe_to;
-    if (!skippy_iter.next (&unsafe_to))
+    if (unlikely (!skippy_iter.next (&unsafe_to)))
     {
       buffer->unsafe_to_concat (buffer->idx, unsafe_to);
       return_trace (false);
     }
 
-    unsigned int len1 = valueFormat1.get_len ();
-    unsigned int len2 = valueFormat2.get_len ();
-    unsigned int record_len = len1 + len2;
+    unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
+    if (!klass2)
+    {
+      buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
+      return_trace (false);
+    }
 
     unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
-    unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
     if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
     {
       buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
       return_trace (false);
     }
 
+    unsigned int len1 = valueFormat1.get_len ();
+    unsigned int len2 = valueFormat2.get_len ();
+    unsigned int record_len = len1 + len2;
+
     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
 
     bool applied_first = false, applied_second = false;
 
 
     /* Isolate simple kerning and apply it half to each side.
-     * Results in better cursor positinoing / underline drawing.
+     * Results in better cursor positioning / underline drawing.
      *
      * Disabled, because causes issues... :-(
      * https://github.com/harfbuzz/harfbuzz/issues/3408
      * https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978
      */
 #ifndef HB_SPLIT_KERN
-    if (0)
+    if (false)
 #endif
     {
       if (!len2)
@@ -224,8 +230,8 @@ struct PairPosFormat2_4
                           c->buffer->idx, skippy_iter.idx);
     }
 
-    applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos());
-    applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
+    applied_first = len1 && valueFormat1.apply_value (c, this, v, buffer->cur_pos());
+    applied_second = len2 && valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
 
     if (applied_first || applied_second)
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
@@ -293,11 +299,13 @@ struct PairPosFormat2_4
       out->valueFormat2 = out->valueFormat2.drop_device_table_flags ();
     }
 
+    unsigned total_len = len1 + len2;
+    hb_vector_t class2_idxs (+ hb_range ((unsigned) class2Count) | hb_filter (klass2_map));
     for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
     {
-      for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
+      for (unsigned class2_idx : class2_idxs)
       {
-        unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+        unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * total_len;
         valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], &c->plan->layout_variation_idx_delta_map);
         valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], &c->plan->layout_variation_idx_delta_map);
       }
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh
index adeb08e910b82..7ccec1df841d0 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh
@@ -52,8 +52,9 @@ struct PairSet
 
     unsigned int count = len;
     const PairValueRecord *record = &firstPairValueRecord;
-    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
-                  closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
+    return_trace (c->lazy_some_gpos ||
+                  (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
+                   closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)));
   }
 
   bool intersects (const hb_set_t *glyphs,
@@ -120,8 +121,8 @@ struct PairSet
                             c->buffer->idx, pos);
       }
 
-      bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
-      bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
+      bool applied_first = len1 && valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
+      bool applied_second = len2 && valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
 
       if (applied_first || applied_second)
         if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairValueRecord.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairValueRecord.hh
index d4f549a480dcf..b32abe46d21b6 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairValueRecord.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairValueRecord.hh
@@ -22,7 +22,7 @@ struct PairValueRecord
   ValueRecord   values;                 /* Positioning data for the first glyph
                                          * followed by for second glyph */
   public:
-  DEFINE_SIZE_ARRAY (Types::size, values);
+  DEFINE_SIZE_ARRAY (Types::HBGlyphID::static_size, values);
 
   int cmp (hb_codepoint_t k) const
   { return secondGlyph.cmp (k); }
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh
index 47391c77028d5..8e21c5f8e713b 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh
@@ -90,6 +90,7 @@ struct SinglePosFormat1
 
   bool
   position_single (hb_font_t           *font,
+                   hb_blob_t           *table_blob,
                    hb_direction_t       direction,
                    hb_codepoint_t       gid,
                    hb_glyph_position_t &pos) const
@@ -100,7 +101,7 @@ struct SinglePosFormat1
     /* This is ugly... */
     hb_buffer_t buffer;
     buffer.props.direction = direction;
-    OT::hb_ot_apply_context_t c (1, font, &buffer);
+    OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob);
 
     valueFormat.apply_value (&c, this, values, pos);
     return true;
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh
index 6546eb167037c..ddc4c18ec1c49 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh
@@ -94,6 +94,7 @@ struct SinglePosFormat2
 
   bool
   position_single (hb_font_t           *font,
+                   hb_blob_t           *table_blob,
                    hb_direction_t       direction,
                    hb_codepoint_t       gid,
                    hb_glyph_position_t &pos) const
@@ -105,7 +106,7 @@ struct SinglePosFormat2
     /* This is ugly... */
     hb_buffer_t buffer;
     buffer.props.direction = direction;
-    OT::hb_ot_apply_context_t c (1, font, &buffer);
+    OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob);
 
     valueFormat.apply_value (&c, this,
                              &values[index * valueFormat.get_len ()],
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh
index 1aa451abcc83b..8618cddad1c73 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh
@@ -118,21 +118,25 @@ struct ValueFormat : HBUINT16
     auto *cache = c->var_store_cache;
 
     /* pixel -> fractional pixel */
-    if (format & xPlaDevice) {
-      if (use_x_device) glyph_pos.x_offset  += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
+    if (format & xPlaDevice)
+    {
+      if (use_x_device) glyph_pos.x_offset  += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache);
       values++;
     }
-    if (format & yPlaDevice) {
-      if (use_y_device) glyph_pos.y_offset  += (base + get_device (values, &ret)).get_y_delta (font, store, cache);
+    if (format & yPlaDevice)
+    {
+      if (use_y_device) glyph_pos.y_offset  += get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache);
       values++;
     }
-    if (format & xAdvDevice) {
-      if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
+    if (format & xAdvDevice)
+    {
+      if (horizontal && use_x_device) glyph_pos.x_advance += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache);
       values++;
     }
-    if (format & yAdvDevice) {
+    if (format & yAdvDevice)
+    {
       /* y_advance values grow downward but font-space grows upward, hence negation */
-      if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache);
+      if (!horizontal && use_y_device) glyph_pos.y_advance -= get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache);
       values++;
     }
     return ret;
@@ -174,6 +178,9 @@ struct ValueFormat : HBUINT16
     if (format & xAdvance)   x_adv = copy_value (c, new_format, xAdvance, *values++);
     if (format & yAdvance)   y_adv = copy_value (c, new_format, yAdvance, *values++);
 
+    if (!has_device ())
+      return;
+
     if (format & xPlaDevice)
     {
       add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map);
@@ -233,14 +240,12 @@ struct ValueFormat : HBUINT16
 
     if (format & ValueFormat::xAdvDevice)
     {
-
       (base + get_device (&(values[i]))).collect_variation_indices (c);
       i++;
     }
 
     if (format & ValueFormat::yAdvDevice)
     {
-
       (base + get_device (&(values[i]))).collect_variation_indices (c);
       i++;
     }
@@ -277,11 +282,23 @@ struct ValueFormat : HBUINT16
   {
     return *static_cast *> (value);
   }
-  static inline const Offset16To& get_device (const Value* value, bool *worked=nullptr)
+  static inline const Offset16To& get_device (const Value* value)
   {
-    if (worked) *worked |= bool (*value);
     return *static_cast *> (value);
   }
+  static inline const Device& get_device (const Value* value,
+                                          bool *worked,
+                                          const void *base,
+                                          hb_sanitize_context_t &c)
+  {
+    if (worked) *worked |= bool (*value);
+    auto &offset = *static_cast *> (value);
+
+    if (unlikely (!offset.sanitize (&c, base)))
+      return Null(Device);
+
+    return base + offset;
+  }
 
   void add_delta_to_value (HBINT16 *value,
                            const void *base,
@@ -340,25 +357,26 @@ struct ValueFormat : HBUINT16
   bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
+
+    if (unlikely (!c->check_range (values, get_size ()))) return_trace (false);
+
+    if (c->lazy_some_gpos)
+      return_trace (true);
+
+    return_trace (!has_device () || sanitize_value_devices (c, base, values));
   }
 
   bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
   {
     TRACE_SANITIZE (this);
-    unsigned int len = get_len ();
+    unsigned size = get_size ();
 
-    if (!c->check_range (values, count, get_size ())) return_trace (false);
+    if (!c->check_range (values, count, size)) return_trace (false);
 
-    if (!has_device ()) return_trace (true);
+    if (c->lazy_some_gpos)
+      return_trace (true);
 
-    for (unsigned int i = 0; i < count; i++) {
-      if (!sanitize_value_devices (c, base, values))
-        return_trace (false);
-      values += len;
-    }
-
-    return_trace (true);
+    return_trace (sanitize_values_stride_unsafe (c, base, values, count, size));
   }
 
   /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Common.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Common.hh
index 968bba0481adf..b849494d88aa1 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Common.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Common.hh
@@ -8,8 +8,6 @@ namespace OT {
 namespace Layout {
 namespace GSUB_impl {
 
-typedef hb_pair_t hb_codepoint_pair_t;
-
 template
 static void SingleSubst_serialize (hb_serialize_context_t *c,
                                    Iterator it);
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh
index 308da587d1e72..de4a111b46cfb 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh
@@ -10,10 +10,10 @@ namespace GSUB_impl {
 template 
 struct Ligature
 {
-  protected:
+  public:
   typename Types::HBGlyphID
                 ligGlyph;               /* GlyphID of ligature to substitute */
-  HeadlessArrayOf
+  HeadlessArray16Of
                 component;              /* Array of component GlyphIDs--start
                                          * with the second  component--ordered
                                          * in writing direction */
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh
index 2b23262280205..ff0ffce94d777 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh
@@ -75,12 +75,69 @@ struct LigatureSet
   bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
+
     unsigned int num_ligs = ligature.len;
+
+#ifndef HB_NO_OT_RULESETS_FAST_PATH
+    if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 4)
+#endif
+    {
+    slow:
+      for (unsigned int i = 0; i < num_ligs; i++)
+      {
+        const auto &lig = this+ligature.arrayZ[i];
+        if (lig.apply (c)) return_trace (true);
+      }
+      return_trace (false);
+    }
+
+    /* This version is optimized for speed by matching the first component
+     * of the ligature here, instead of calling into the ligation code.
+     *
+     * This is replicated in ChainRuleSet and RuleSet. */
+
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (c->buffer->idx);
+    skippy_iter.set_match_func (match_always, nullptr);
+    skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
+    unsigned unsafe_to;
+    hb_codepoint_t first = (unsigned) -1;
+    bool matched = skippy_iter.next (&unsafe_to);
+    if (likely (matched))
+    {
+      first = c->buffer->info[skippy_iter.idx].codepoint;
+      unsafe_to = skippy_iter.idx + 1;
+
+      if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
+      {
+        /* Can't use the fast path if eg. the next char is a default-ignorable
+         * or other skippable. */
+        goto slow;
+      }
+    }
+    else
+      goto slow;
+
+    bool unsafe_to_concat = false;
+
     for (unsigned int i = 0; i < num_ligs; i++)
     {
-      const auto &lig = this+ligature[i];
-      if (lig.apply (c)) return_trace (true);
+      const auto &lig = this+ligature.arrayZ[i];
+      if (unlikely (lig.component.lenP1 <= 1) ||
+          lig.component.arrayZ[0] == first)
+      {
+        if (lig.apply (c))
+        {
+          if (unsafe_to_concat)
+            c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
+          return_trace (true);
+        }
+      }
+      else if (likely (lig.component.lenP1 > 1))
+        unsafe_to_concat = true;
     }
+    if (likely (unsafe_to_concat))
+      c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
 
     return_trace (false);
   }
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
index 73f222746e5d7..ec6dfa476476c 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
@@ -191,7 +191,6 @@ struct ReverseChainSingleSubstFormat1
     TRACE_SERIALIZE (this);
 
     auto *out = c->serializer->start_embed (this);
-    if (unlikely (!c->serializer->check_success (out))) return_trace (false);
     if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
     if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false);
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh
index 62d68160c7bd2..a5e93a98bef99 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh
@@ -53,7 +53,7 @@ struct Sequence
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       {
         c->buffer->message (c->font,
-                            "replaced glyph at %u (multiple subtitution)",
+                            "replaced glyph at %u (multiple substitution)",
                             c->buffer->idx - 1u);
       }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh
index 304d1928e2370..b84259e7f00e0 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh
@@ -57,7 +57,7 @@ struct SingleSubst
 
 #ifndef HB_NO_BEYOND_64K
        if (+ glyphs
-           | hb_map_retains_sorting (hb_first)
+           | hb_map_retains_sorting (hb_second)
            | hb_filter ([] (hb_codepoint_t gid) { return gid > 0xFFFFu; }))
        {
          format += 2;
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh
index 94cb61abc07f1..151c1ac48cb7c 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh
@@ -87,19 +87,54 @@ struct CompositeGlyphRecord
     }
   }
 
-  void transform_points (contour_point_vector_t &points,
+  static void transform (const float (&matrix)[4],
+                         hb_array_t points)
+  {
+    if (matrix[0] != 1.f || matrix[1] != 0.f ||
+        matrix[2] != 0.f || matrix[3] != 1.f)
+      for (auto &point : points)
+        point.transform (matrix);
+  }
+
+  static void translate (const contour_point_t &trans,
+                         hb_array_t points)
+  {
+    if (HB_OPTIMIZE_SIZE_VAL)
+    {
+      if (trans.x != 0.f || trans.y != 0.f)
+        for (auto &point : points)
+          point.translate (trans);
+    }
+    else
+    {
+      if (trans.x != 0.f && trans.y != 0.f)
+        for (auto &point : points)
+          point.translate (trans);
+      else
+      {
+        if (trans.x != 0.f)
+          for (auto &point : points)
+            point.x += trans.x;
+        else if (trans.y != 0.f)
+          for (auto &point : points)
+            point.y += trans.y;
+      }
+    }
+  }
+
+  void transform_points (hb_array_t points,
                          const float (&matrix)[4],
                          const contour_point_t &trans) const
   {
     if (scaled_offsets ())
     {
-      points.translate (trans);
-      points.transform (matrix);
+      translate (trans, points);
+      transform (matrix, points);
     }
     else
     {
-      points.transform (matrix);
-      points.translate (trans);
+      transform (matrix, points);
+      translate (trans, points);
     }
   }
 
@@ -108,8 +143,8 @@ struct CompositeGlyphRecord
     float matrix[4];
     contour_point_t trans;
     get_transformation (matrix, trans);
-    if (unlikely (!points.resize (points.length + 1))) return false;
-    points[points.length - 1] = trans;
+    if (unlikely (!points.alloc (points.length + 4))) return false; // For phantom points
+    points.push (trans);
     return true;
   }
 
@@ -358,7 +393,7 @@ struct CompositeGlyph
     {
       /* last 4 points in points_with_deltas are phantom points and should not be included */
       if (i >= points_with_deltas.length - 4) {
-        free (o);
+        hb_free (o);
         return false;
       }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh
index 1ebaaa3f831e1..b295e41510fd8 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh
@@ -103,6 +103,63 @@ struct Glyph
     }
   }
 
+  bool get_all_points_without_var (const hb_face_t *face,
+                                   contour_point_vector_t &points /* OUT */) const
+  {
+    switch (type) {
+    case SIMPLE:
+      if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points)))
+        return false;
+      break;
+    case COMPOSITE:
+    {
+      for (auto &item : get_composite_iterator ())
+        if (unlikely (!item.get_points (points))) return false;
+      break;
+    }
+#ifndef HB_NO_VAR_COMPOSITES
+    case VAR_COMPOSITE:
+    {
+      for (auto &item : get_var_composite_iterator ())
+        if (unlikely (!item.get_points (points))) return false;
+      break;
+    }
+#endif
+    case EMPTY:
+      break;
+    }
+
+    /* Init phantom points */
+    if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
+    hb_array_t phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
+    {
+      int lsb = 0;
+      int h_delta = face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
+                    (int) header->xMin - lsb : 0;
+      HB_UNUSED int tsb = 0;
+      int v_orig  = (int) header->yMax +
+#ifndef HB_NO_VERTICAL
+                    ((void) face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
+#else
+                    0
+#endif
+                    ;
+      unsigned h_adv = face->table.hmtx->get_advance_without_var_unscaled (gid);
+      unsigned v_adv =
+#ifndef HB_NO_VERTICAL
+                       face->table.vmtx->get_advance_without_var_unscaled (gid)
+#else
+                       - face->get_upem ()
+#endif
+                       ;
+      phantoms[PHANTOM_LEFT].x = h_delta;
+      phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
+      phantoms[PHANTOM_TOP].y = v_orig;
+      phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
+    }
+    return true;
+  }
+
   void update_mtx (const hb_subset_plan_t *plan,
                    int xMin, int xMax,
                    int yMin, int yMax,
@@ -114,8 +171,8 @@ struct Glyph
 
     if (type != EMPTY)
     {
-      plan->bounds_width_map.set (new_gid, xMax - xMin);
-      plan->bounds_height_map.set (new_gid, yMax - yMin);
+      plan->bounds_width_vec[new_gid] = xMax - xMin;
+      plan->bounds_height_vec[new_gid] = yMax - yMin;
     }
 
     unsigned len = all_points.length;
@@ -124,10 +181,12 @@ struct Glyph
     float topSideY = all_points[len - 2].y;
     float bottomSideY = all_points[len - 1].y;
 
+    uint32_t hash = hb_hash (new_gid);
+
     signed hori_aw = roundf (rightSideX - leftSideX);
     if (hori_aw < 0) hori_aw = 0;
     int lsb = roundf (xMin - leftSideX);
-    plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb));
+    plan->hmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) hori_aw, lsb));
     //flag value should be computed using non-empty glyphs
     if (type != EMPTY && lsb != xMin)
       plan->head_maxp_info.allXMinIsLsb = false;
@@ -135,7 +194,7 @@ struct Glyph
     signed vert_aw = roundf (topSideY - bottomSideY);
     if (vert_aw < 0) vert_aw = 0;
     int tsb = roundf (topSideY - yMax);
-    plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb));
+    plan->vmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) vert_aw, tsb));
   }
 
   bool compile_header_bytes (const hb_subset_plan_t *plan,
@@ -155,24 +214,28 @@ struct Glyph
     {
       xMin = xMax = all_points[0].x;
       yMin = yMax = all_points[0].y;
-    }
 
-    for (unsigned i = 1; i < all_points.length - 4; i++)
-    {
-      float x = all_points[i].x;
-      float y = all_points[i].y;
-      xMin = hb_min (xMin, x);
-      xMax = hb_max (xMax, x);
-      yMin = hb_min (yMin, y);
-      yMax = hb_max (yMax, y);
+      unsigned count = all_points.length - 4;
+      for (unsigned i = 1; i < count; i++)
+      {
+        float x = all_points[i].x;
+        float y = all_points[i].y;
+        xMin = hb_min (xMin, x);
+        xMax = hb_max (xMax, x);
+        yMin = hb_min (yMin, y);
+        yMax = hb_max (yMax, y);
+      }
     }
 
-    update_mtx (plan, roundf (xMin), roundf (xMax), roundf (yMin), roundf (yMax), all_points);
 
-    int rounded_xMin = roundf (xMin);
-    int rounded_xMax = roundf (xMax);
-    int rounded_yMin = roundf (yMin);
-    int rounded_yMax = roundf (yMax);
+    // These are destined for storage in a 16 bit field to clamp the values to
+    // fit into a 16 bit signed integer.
+    int rounded_xMin = hb_clamp (roundf (xMin), -32768.0f, 32767.0f);
+    int rounded_xMax = hb_clamp (roundf (xMax), -32768.0f, 32767.0f);
+    int rounded_yMin = hb_clamp (roundf (yMin), -32768.0f, 32767.0f);
+    int rounded_yMax = hb_clamp (roundf (yMax), -32768.0f, 32767.0f);
+
+    update_mtx (plan, rounded_xMin, rounded_xMax, rounded_yMin, rounded_yMax, all_points);
 
     if (type != EMPTY)
     {
@@ -287,6 +350,7 @@ struct Glyph
                    bool use_my_metrics = true,
                    bool phantom_only = false,
                    hb_array_t coords = hb_array_t (),
+                   hb_map_t *current_glyphs = nullptr,
                    unsigned int depth = 0,
                    unsigned *edge_count = nullptr) const
   {
@@ -296,6 +360,10 @@ struct Glyph
     if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false;
     (*edge_count)++;
 
+    hb_map_t current_glyphs_stack;
+    if (current_glyphs == nullptr)
+      current_glyphs = ¤t_glyphs_stack;
+
     if (head_maxp_info)
     {
       head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
@@ -305,9 +373,8 @@ struct Glyph
       coords = hb_array (font->coords, font->num_coords);
 
     contour_point_vector_t stack_points;
-    bool inplace = type == SIMPLE && all_points.length == 0;
-    /* Load into all_points if it's empty, as an optimization. */
-    contour_point_vector_t &points = inplace ? all_points : stack_points;
+    contour_point_vector_t &points = type == SIMPLE ? all_points : stack_points;
+    unsigned old_length = points.length;
 
     switch (type) {
     case SIMPLE:
@@ -315,7 +382,7 @@ struct Glyph
         head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours);
       if (depth > 0 && composite_contours)
         *composite_contours += (unsigned) header->numberOfContours;
-      if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
+      if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (all_points, phantom_only)))
         return false;
       break;
     case COMPOSITE:
@@ -329,6 +396,7 @@ struct Glyph
     {
       for (auto &item : get_var_composite_iterator ())
         if (unlikely (!item.get_points (points))) return false;
+      break;
     }
 #endif
     case EMPTY:
@@ -365,9 +433,11 @@ struct Glyph
     }
 
 #ifndef HB_NO_VAR
-    glyf_accelerator.gvar->apply_deltas_to_points (gid,
-                                                   coords,
-                                                   points.as_array ());
+    if (coords)
+      glyf_accelerator.gvar->apply_deltas_to_points (gid,
+                                                     coords,
+                                                     points.as_array ().sub_array (old_length),
+                                                     phantom_only && type == SIMPLE);
 #endif
 
     // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
@@ -375,27 +445,33 @@ struct Glyph
     if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
     {
       if (unlikely (!points_with_deltas->resize (points.length))) return false;
-      points_with_deltas->copy_vector (points);
+      *points_with_deltas = points;
     }
 
     switch (type) {
     case SIMPLE:
       if (depth == 0 && head_maxp_info)
-        head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, points.length - 4);
-      if (!inplace)
-        all_points.extend (points.as_array ());
+        head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4);
       break;
     case COMPOSITE:
     {
-      contour_point_vector_t comp_points;
       unsigned int comp_index = 0;
       for (auto &item : get_composite_iterator ())
       {
-        comp_points.reset ();
-        if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
+        hb_codepoint_t item_gid = item.get_gid ();
+
+        if (unlikely (current_glyphs->has (item_gid)))
+          continue;
+
+        current_glyphs->add (item_gid);
+
+        unsigned old_count = all_points.length;
+
+        if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
+                      !glyf_accelerator.glyph_for_gid (item_gid)
                                        .get_points (font,
                                                     glyf_accelerator,
-                                                    comp_points,
+                                                    all_points,
                                                     points_with_deltas,
                                                     head_maxp_info,
                                                     composite_contours,
@@ -403,23 +479,32 @@ struct Glyph
                                                     use_my_metrics,
                                                     phantom_only,
                                                     coords,
+                                                    current_glyphs,
                                                     depth + 1,
                                                     edge_count)))
+        {
+          current_glyphs->del (item_gid);
           return false;
+        }
+
+        auto comp_points = all_points.as_array ().sub_array (old_count);
 
         /* Copy phantom points from component if USE_MY_METRICS flag set */
         if (use_my_metrics && item.is_use_my_metrics ())
           for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
             phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
 
-        float matrix[4];
-        contour_point_t default_trans;
-        item.get_transformation (matrix, default_trans);
+        if (comp_points) // Empty in case of phantom_only
+        {
+          float matrix[4];
+          contour_point_t default_trans;
+          item.get_transformation (matrix, default_trans);
 
-        /* Apply component transformation & translation (with deltas applied) */
-        item.transform_points (comp_points, matrix, points[comp_index]);
+          /* Apply component transformation & translation (with deltas applied) */
+          item.transform_points (comp_points, matrix, points[comp_index]);
+        }
 
-        if (item.is_anchored ())
+        if (item.is_anchored () && !phantom_only)
         {
           unsigned int p1, p2;
           item.get_anchor_points (p1, p2);
@@ -429,16 +514,20 @@ struct Glyph
             delta.init (all_points[p1].x - comp_points[p2].x,
                         all_points[p1].y - comp_points[p2].y);
 
-            comp_points.translate (delta);
+            item.translate (delta, comp_points);
           }
         }
 
-        all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT));
+        all_points.resize (all_points.length - PHANTOM_COUNT);
 
         if (all_points.length > HB_GLYF_MAX_POINTS)
+        {
+          current_glyphs->del (item_gid);
           return false;
+        }
 
         comp_index++;
+        current_glyphs->del (item_gid);
       }
 
       if (head_maxp_info && depth == 0)
@@ -453,26 +542,37 @@ struct Glyph
 #ifndef HB_NO_VAR_COMPOSITES
     case VAR_COMPOSITE:
     {
-      contour_point_vector_t comp_points;
       hb_array_t points_left = points.as_array ();
       for (auto &item : get_var_composite_iterator ())
       {
+        hb_codepoint_t item_gid = item.get_gid ();
+
+        if (unlikely (current_glyphs->has (item_gid)))
+          continue;
+
+        current_glyphs->add (item_gid);
+
         unsigned item_num_points = item.get_num_points ();
         hb_array_t record_points = points_left.sub_array (0, item_num_points);
-
-        comp_points.reset ();
+        assert (record_points.length == item_num_points);
 
         auto component_coords = coords;
-        if (item.is_reset_unspecified_axes ())
+        /* Copying coords is expensive; so we have put an arbitrary
+         * limit on the max number of coords for now. */
+        if (item.is_reset_unspecified_axes () ||
+            coords.length > HB_GLYF_VAR_COMPOSITE_MAX_AXES)
           component_coords = hb_array ();
 
         coord_setter_t coord_setter (component_coords);
         item.set_variations (coord_setter, record_points);
 
-        if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
+        unsigned old_count = all_points.length;
+
+        if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
+                      !glyf_accelerator.glyph_for_gid (item_gid)
                                        .get_points (font,
                                                     glyf_accelerator,
-                                                    comp_points,
+                                                    all_points,
                                                     points_with_deltas,
                                                     head_maxp_info,
                                                     nullptr,
@@ -480,24 +580,36 @@ struct Glyph
                                                     use_my_metrics,
                                                     phantom_only,
                                                     coord_setter.get_coords (),
+                                                    current_glyphs,
                                                     depth + 1,
                                                     edge_count)))
+        {
+          current_glyphs->del (item_gid);
           return false;
+        }
+
+        auto comp_points = all_points.as_array ().sub_array (old_count);
 
         /* Apply component transformation */
-        item.transform_points (record_points, comp_points);
+        if (comp_points) // Empty in case of phantom_only
+          item.transform_points (record_points, comp_points);
 
         /* Copy phantom points from component if USE_MY_METRICS flag set */
         if (use_my_metrics && item.is_use_my_metrics ())
           for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
             phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
 
-        all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT));
+        all_points.resize (all_points.length - PHANTOM_COUNT);
 
         if (all_points.length > HB_GLYF_MAX_POINTS)
+        {
+          current_glyphs->del (item_gid);
           return false;
+        }
 
         points_left += item_num_points;
+
+        current_glyphs->del (item_gid);
       }
       all_points.extend (phantoms);
     } break;
@@ -512,9 +624,10 @@ struct Glyph
       /* Undocumented rasterizer behavior:
        * Shift points horizontally by the updated left side bearing
        */
-      contour_point_t delta;
-      delta.init (-phantoms[PHANTOM_LEFT].x, 0.f);
-      if (delta.x) all_points.translate (delta);
+      int v = -phantoms[PHANTOM_LEFT].x;
+      if (v)
+        for (auto &point : all_points)
+          point.x += v;
     }
 
     return !all_points.in_error ();
@@ -545,10 +658,11 @@ struct Glyph
     int num_contours = header->numberOfContours;
     if (unlikely (num_contours == 0)) type = EMPTY;
     else if (num_contours > 0) type = SIMPLE;
+    else if (num_contours == -1) type = COMPOSITE;
 #ifndef HB_NO_VAR_COMPOSITES
     else if (num_contours == -2) type = VAR_COMPOSITE;
 #endif
-    else type = COMPOSITE; /* negative numbers */
+    else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild.
   }
 
   protected:
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh
index bed9fc81d817a..5088397266d24 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh
@@ -124,7 +124,7 @@ struct SimpleGlyph
   }
 
   static bool read_flags (const HBUINT8 *&p /* IN/OUT */,
-                          contour_point_vector_t &points_ /* IN/OUT */,
+                          hb_array_t points_ /* IN/OUT */,
                           const HBUINT8 *end)
   {
     unsigned count = points_.length;
@@ -146,7 +146,7 @@ struct SimpleGlyph
   }
 
   static bool read_points (const HBUINT8 *&p /* IN/OUT */,
-                           contour_point_vector_t &points_ /* IN/OUT */,
+                           hb_array_t points_ /* IN/OUT */,
                            const HBUINT8 *end,
                            float contour_point_t::*m,
                            const simple_glyph_flag_t short_flag,
@@ -154,10 +154,9 @@ struct SimpleGlyph
   {
     int v = 0;
 
-    unsigned count = points_.length;
-    for (unsigned i = 0; i < count; i++)
+    for (auto &point : points_)
     {
-      unsigned flag = points_[i].flag;
+      unsigned flag = point.flag;
       if (flag & short_flag)
       {
         if (unlikely (p + 1 > end)) return false;
@@ -175,23 +174,27 @@ struct SimpleGlyph
           p += HBINT16::static_size;
         }
       }
-      points_.arrayZ[i].*m = v;
+      point.*m = v;
     }
     return true;
   }
 
-  bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
+  bool get_contour_points (contour_point_vector_t &points /* OUT */,
                            bool phantom_only = false) const
   {
     const HBUINT16 *endPtsOfContours = &StructAfter (header);
     int num_contours = header.numberOfContours;
-    assert (num_contours);
+    assert (num_contours > 0);
     /* One extra item at the end, for the instruction-count below. */
     if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false;
     unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
 
-    points_.alloc (num_points + 4, true); // Allocate for phantom points, to avoid a possible copy
-    if (!points_.resize (num_points)) return false;
+    unsigned old_length = points.length;
+    points.alloc (points.length + num_points + 4, true); // Allocate for phantom points, to avoid a possible copy
+    if (unlikely (!points.resize (points.length + num_points, false))) return false;
+    auto points_ = points.as_array ().sub_array (old_length);
+    if (!phantom_only)
+      hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points);
     if (phantom_only) return true;
 
     for (int i = 0; i < num_contours; i++)
@@ -214,7 +217,7 @@ struct SimpleGlyph
   }
 
   static void encode_coord (int value,
-                            uint8_t &flag,
+                            unsigned &flag,
                             const simple_glyph_flag_t short_flag,
                             const simple_glyph_flag_t same_flag,
                             hb_vector_t &coords /* OUT */)
@@ -239,9 +242,9 @@ struct SimpleGlyph
     }
   }
 
-  static void encode_flag (uint8_t &flag,
-                           uint8_t &repeat,
-                           uint8_t lastflag,
+  static void encode_flag (unsigned flag,
+                           unsigned &repeat,
+                           unsigned lastflag,
                            hb_vector_t &flags /* OUT */)
   {
     if (flag == lastflag && repeat != 255)
@@ -262,7 +265,7 @@ struct SimpleGlyph
     else
     {
       repeat = 0;
-      flags.push (flag);
+      flags.arrayZ[flags.length++] = flag;
     }
   }
 
@@ -282,13 +285,13 @@ struct SimpleGlyph
     if (unlikely (!x_coords.alloc (2*num_points, true))) return false;
     if (unlikely (!y_coords.alloc (2*num_points, true))) return false;
 
-    uint8_t lastflag = 255, repeat = 0;
+    unsigned lastflag = 255, repeat = 0;
     int prev_x = 0, prev_y = 0;
 
     for (unsigned i = 0; i < num_points; i++)
     {
-      uint8_t flag = all_points.arrayZ[i].flag;
-      flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE;
+      unsigned flag = all_points.arrayZ[i].flag;
+      flag &= FLAG_ON_CURVE | FLAG_OVERLAP_SIMPLE | FLAG_CUBIC;
 
       int cur_x = roundf (all_points.arrayZ[i].x);
       int cur_y = roundf (all_points.arrayZ[i].y);
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SubsetGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SubsetGlyph.hh
index d6ce5be07bbc4..9c04d890d1abc 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SubsetGlyph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SubsetGlyph.hh
@@ -22,7 +22,7 @@ struct SubsetGlyph
 
   bool serialize (hb_serialize_context_t *c,
                   bool use_short_loca,
-                  const hb_subset_plan_t *plan)
+                  const hb_subset_plan_t *plan) const
   {
     TRACE_SERIALIZE (this);
 
@@ -40,7 +40,7 @@ struct SubsetGlyph
     pad = 0;
     while (pad_length > 0)
     {
-      c->embed (pad);
+      (void) c->embed (pad);
       pad_length--;
     }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/VarCompositeGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/VarCompositeGlyph.hh
index f2dcb065e263d..4f29f0aab37c5 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/VarCompositeGlyph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/VarCompositeGlyph.hh
@@ -36,24 +36,21 @@ struct VarCompositeGlyphRecord
 
   unsigned int get_size () const
   {
+    unsigned fl = flags;
     unsigned int size = min_size;
 
-    unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 4 : 3;
+    unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 4 : 3;
     size += numAxes * axis_width;
 
-    // gid
-    size += 2;
-    if (flags & GID_IS_24BIT)           size += 1;
+    if (fl & GID_IS_24BIT)      size += 1;
 
-    if (flags & HAVE_TRANSLATE_X)       size += 2;
-    if (flags & HAVE_TRANSLATE_Y)       size += 2;
-    if (flags & HAVE_ROTATION)          size += 2;
-    if (flags & HAVE_SCALE_X)           size += 2;
-    if (flags & HAVE_SCALE_Y)           size += 2;
-    if (flags & HAVE_SKEW_X)            size += 2;
-    if (flags & HAVE_SKEW_Y)            size += 2;
-    if (flags & HAVE_TCENTER_X)         size += 2;
-    if (flags & HAVE_TCENTER_Y)         size += 2;
+    // 2 bytes each for the following flags
+    fl = fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y |
+               HAVE_ROTATION |
+               HAVE_SCALE_X | HAVE_SCALE_Y |
+               HAVE_SKEW_X | HAVE_SKEW_Y |
+               HAVE_TCENTER_X | HAVE_TCENTER_Y);
+    size += hb_popcount (fl) * 2;
 
     return size;
   }
@@ -66,17 +63,17 @@ struct VarCompositeGlyphRecord
   hb_codepoint_t get_gid () const
   {
     if (flags & GID_IS_24BIT)
-      return StructAfter (numAxes);
+      return * (const HBGlyphID24 *) &pad;
     else
-      return StructAfter (numAxes);
+      return * (const HBGlyphID16 *) &pad;
   }
 
   void set_gid (hb_codepoint_t gid)
   {
     if (flags & GID_IS_24BIT)
-      StructAfter (numAxes) = gid;
+      * (HBGlyphID24 *) &pad = gid;
     else
-      StructAfter (numAxes) = gid;
+      * (HBGlyphID16 *) &pad = gid;
   }
 
   unsigned get_numAxes () const
@@ -86,26 +83,44 @@ struct VarCompositeGlyphRecord
 
   unsigned get_num_points () const
   {
+    unsigned fl = flags;
     unsigned num = 0;
-    if (flags & AXES_HAVE_VARIATION)                    num += numAxes;
-    if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))  num++;
-    if (flags & HAVE_ROTATION)                          num++;
-    if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))          num++;
-    if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))            num++;
-    if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))      num++;
+    if (fl & AXES_HAVE_VARIATION)                       num += numAxes;
+
+    /* Hopefully faster code, relying on the value of the flags. */
+    fl = (((fl & (HAVE_TRANSLATE_Y | HAVE_SCALE_Y | HAVE_SKEW_Y | HAVE_TCENTER_Y)) >> 1) | fl) &
+         (HAVE_TRANSLATE_X | HAVE_ROTATION | HAVE_SCALE_X | HAVE_SKEW_X | HAVE_TCENTER_X);
+    num += hb_popcount (fl);
+    return num;
+
+    /* Slower but more readable code. */
+    if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))     num++;
+    if (fl & HAVE_ROTATION)                             num++;
+    if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y))             num++;
+    if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y))               num++;
+    if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y))         num++;
     return num;
   }
 
-  void transform_points (hb_array_t record_points,
-                         contour_point_vector_t &points) const
+  void transform_points (hb_array_t record_points,
+                         hb_array_t points) const
   {
     float matrix[4];
     contour_point_t trans;
 
-    get_transformation_from_points (record_points, matrix, trans);
+    get_transformation_from_points (record_points.arrayZ, matrix, trans);
+
+    auto arrayZ = points.arrayZ;
+    unsigned count = points.length;
 
-    points.transform (matrix);
-    points.translate (trans);
+    if (matrix[0] != 1.f || matrix[1] != 0.f ||
+        matrix[2] != 0.f || matrix[3] != 1.f)
+      for (unsigned i = 0; i < count; i++)
+        arrayZ[i].transform (matrix);
+
+    if (trans.x != 0.f || trans.y != 0.f)
+      for (unsigned i = 0; i < count; i++)
+        arrayZ[i].translate (trans);
   }
 
   static inline void transform (float (&matrix)[4], contour_point_t &trans,
@@ -136,26 +151,41 @@ struct VarCompositeGlyphRecord
   static void translate (float (&matrix)[4], contour_point_t &trans,
                          float translateX, float translateY)
   {
-    // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L213
-    float other[6] = {1.f, 0.f, 0.f, 1.f, translateX, translateY};
-    transform (matrix, trans, other);
+    if (!translateX && !translateY)
+      return;
+
+    trans.x += matrix[0] * translateX + matrix[2] * translateY;
+    trans.y += matrix[1] * translateX + matrix[3] * translateY;
   }
 
   static void scale (float (&matrix)[4], contour_point_t &trans,
                      float scaleX, float scaleY)
   {
-    // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L224
-    float other[6] = {scaleX, 0.f, 0.f, scaleY, 0.f, 0.f};
-    transform (matrix, trans, other);
+    if (scaleX == 1.f && scaleY == 1.f)
+      return;
+
+    matrix[0] *= scaleX;
+    matrix[1] *= scaleX;
+    matrix[2] *= scaleY;
+    matrix[3] *= scaleY;
   }
 
   static void rotate (float (&matrix)[4], contour_point_t &trans,
                       float rotation)
   {
+    if (!rotation)
+      return;
+
     // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
     rotation = rotation * HB_PI;
-    float c = cosf (rotation);
-    float s = sinf (rotation);
+    float c;
+    float s;
+#ifdef HAVE_SINCOSF
+    sincosf (rotation, &s, &c);
+#else
+    c = cosf (rotation);
+    s = sinf (rotation);
+#endif
     float other[6] = {c, s, -s, c, 0.f, 0.f};
     transform (matrix, trans, other);
   }
@@ -163,101 +193,100 @@ struct VarCompositeGlyphRecord
   static void skew (float (&matrix)[4], contour_point_t &trans,
                     float skewX, float skewY)
   {
+    if (!skewX && !skewY)
+      return;
+
     // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255
     skewX = skewX * HB_PI;
     skewY = skewY * HB_PI;
-    float other[6] = {1.f, tanf (skewY), tanf (skewX), 1.f, 0.f, 0.f};
+    float other[6] = {1.f,
+                      skewY ? tanf (skewY) : 0.f,
+                      skewX ? tanf (skewX) : 0.f,
+                      1.f,
+                      0.f, 0.f};
     transform (matrix, trans, other);
   }
 
   bool get_points (contour_point_vector_t &points) const
   {
-    float translateX = 0.f;
-    float translateY = 0.f;
-    float rotation = 0.f;
-    float scaleX = 1.f * (1 << 10);
-    float scaleY = 1.f * (1 << 10);
-    float skewX = 0.f;
-    float skewY = 0.f;
-    float tCenterX = 0.f;
-    float tCenterY = 0.f;
-
     unsigned num_points = get_num_points ();
 
-    if (unlikely (!points.resize (points.length + num_points))) return false;
+    points.alloc (points.length + num_points + 4); // For phantom points
+    if (unlikely (!points.resize (points.length + num_points, false))) return false;
+    contour_point_t *rec_points = points.arrayZ + (points.length - num_points);
+    hb_memset (rec_points, 0, num_points * sizeof (rec_points[0]));
 
-    unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
-    unsigned axes_size = numAxes * axis_width;
+    unsigned fl = flags;
 
-    const F2DOT14 *q = (const F2DOT14 *) (axes_size +
-                                          (flags & GID_IS_24BIT ? 3 : 2) +
-                                          &StructAfter (numAxes));
+    unsigned num_axes = numAxes;
+    unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
+    unsigned axes_size = num_axes * axis_width;
 
-    hb_array_t rec_points = points.as_array ().sub_array (points.length - num_points);
+    const F2DOT14 *q = (const F2DOT14 *) (axes_size +
+                                          (fl & GID_IS_24BIT ? 3 : 2) +
+                                          (const HBUINT8 *) &pad);
 
-    unsigned count = numAxes;
-    if (flags & AXES_HAVE_VARIATION)
+    unsigned count = num_axes;
+    if (fl & AXES_HAVE_VARIATION)
     {
       for (unsigned i = 0; i < count; i++)
-        rec_points[i].x = q++->to_int ();
-      rec_points += count;
+        rec_points++->x = q++->to_int ();
     }
     else
       q += count;
 
     const HBUINT16 *p = (const HBUINT16 *) q;
 
-    if (flags & HAVE_TRANSLATE_X)       translateX = * (const FWORD *) p++;
-    if (flags & HAVE_TRANSLATE_Y)       translateY = * (const FWORD *) p++;
-    if (flags & HAVE_ROTATION)          rotation = ((const F4DOT12 *) p++)->to_int ();
-    if (flags & HAVE_SCALE_X)           scaleX = ((const F6DOT10 *) p++)->to_int ();
-    if (flags & HAVE_SCALE_Y)           scaleY = ((const F6DOT10 *) p++)->to_int ();
-    if (flags & HAVE_SKEW_X)            skewX = ((const F4DOT12 *) p++)->to_int ();
-    if (flags & HAVE_SKEW_Y)            skewY = ((const F4DOT12 *) p++)->to_int ();
-    if (flags & HAVE_TCENTER_X)         tCenterX = * (const FWORD *) p++;
-    if (flags & HAVE_TCENTER_Y)         tCenterY = * (const FWORD *) p++;
-
-    if ((flags & UNIFORM_SCALE) && !(flags & HAVE_SCALE_Y))
-      scaleY = scaleX;
-
-    if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
+    if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
     {
-      rec_points[0].x = translateX;
-      rec_points[0].y = translateY;
+      int translateX = (fl & HAVE_TRANSLATE_X) ? * (const FWORD *) p++ : 0;
+      int translateY = (fl & HAVE_TRANSLATE_Y) ? * (const FWORD *) p++ : 0;
+      rec_points->x = translateX;
+      rec_points->y = translateY;
       rec_points++;
     }
-    if (flags & HAVE_ROTATION)
+    if (fl & HAVE_ROTATION)
     {
-      rec_points[0].x = rotation;
+      int rotation = (fl & HAVE_ROTATION) ? ((const F4DOT12 *) p++)->to_int () : 0;
+      rec_points->x = rotation;
       rec_points++;
     }
-    if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
+    if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y))
     {
-      rec_points[0].x = scaleX;
-      rec_points[0].y = scaleY;
+      int scaleX = (fl & HAVE_SCALE_X) ? ((const F6DOT10 *) p++)->to_int () : 1 << 10;
+      int scaleY = (fl & HAVE_SCALE_Y) ? ((const F6DOT10 *) p++)->to_int () : 1 << 10;
+      if ((fl & UNIFORM_SCALE) && !(fl & HAVE_SCALE_Y))
+        scaleY = scaleX;
+      rec_points->x = scaleX;
+      rec_points->y = scaleY;
       rec_points++;
     }
-    if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
+    if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y))
     {
-      rec_points[0].x = skewX;
-      rec_points[0].y = skewY;
+      int skewX = (fl & HAVE_SKEW_X) ? ((const F4DOT12 *) p++)->to_int () : 0;
+      int skewY = (fl & HAVE_SKEW_Y) ? ((const F4DOT12 *) p++)->to_int () : 0;
+      rec_points->x = skewX;
+      rec_points->y = skewY;
       rec_points++;
     }
-    if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
+    if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
     {
-      rec_points[0].x = tCenterX;
-      rec_points[0].y = tCenterY;
+      int tCenterX = (fl & HAVE_TCENTER_X) ? * (const FWORD *) p++ : 0;
+      int tCenterY = (fl & HAVE_TCENTER_Y) ? * (const FWORD *) p++ : 0;
+      rec_points->x = tCenterX;
+      rec_points->y = tCenterY;
       rec_points++;
     }
-    assert (!rec_points);
 
     return true;
   }
 
-  void get_transformation_from_points (hb_array_t rec_points,
+  void get_transformation_from_points (const contour_point_t *rec_points,
                                        float (&matrix)[4], contour_point_t &trans) const
   {
-    if (flags & AXES_HAVE_VARIATION)
+    unsigned fl = flags;
+
+    if (fl & AXES_HAVE_VARIATION)
       rec_points += numAxes;
 
     matrix[0] = matrix[3] = 1.f;
@@ -274,36 +303,35 @@ struct VarCompositeGlyphRecord
     float tCenterX = 0.f;
     float tCenterY = 0.f;
 
-    if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
+    if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
     {
-      translateX = rec_points[0].x;
-      translateY = rec_points[0].y;
+      translateX = rec_points->x;
+      translateY = rec_points->y;
       rec_points++;
     }
-    if (flags & HAVE_ROTATION)
+    if (fl & HAVE_ROTATION)
     {
-      rotation = rec_points[0].x / (1 << 12);
+      rotation = rec_points->x / (1 << 12);
       rec_points++;
     }
-    if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
+    if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y))
     {
-      scaleX = rec_points[0].x / (1 << 10);
-      scaleY = rec_points[0].y / (1 << 10);
+      scaleX = rec_points->x / (1 << 10);
+      scaleY = rec_points->y / (1 << 10);
       rec_points++;
     }
-    if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
+    if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y))
     {
-      skewX = rec_points[0].x / (1 << 12);
-      skewY = rec_points[0].y / (1 << 12);
+      skewX = rec_points->x / (1 << 12);
+      skewY = rec_points->y / (1 << 12);
       rec_points++;
     }
-    if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
+    if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
     {
-      tCenterX = rec_points[0].x;
-      tCenterY = rec_points[0].y;
+      tCenterX = rec_points->x;
+      tCenterY = rec_points->y;
       rec_points++;
     }
-    assert (!rec_points);
 
     translate (matrix, trans, translateX + tCenterX, translateY + tCenterY);
     rotate (matrix, trans, rotation);
@@ -317,18 +345,19 @@ struct VarCompositeGlyphRecord
   {
     bool have_variations = flags & AXES_HAVE_VARIATION;
     unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
+    unsigned num_axes = numAxes;
 
     const HBUINT8  *p = (const HBUINT8 *)  (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2));
     const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2));
 
-    const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + numAxes) : (HBUINT8 *) (q + numAxes)));
+    const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + num_axes) : (HBUINT8 *) (q + num_axes)));
 
-    unsigned count = numAxes;
+    unsigned count = num_axes;
     for (unsigned i = 0; i < count; i++)
     {
       unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++;
 
-      signed v = have_variations ? rec_points[i].x : a++->to_int ();
+      signed v = have_variations ? rec_points.arrayZ[i].x : a++->to_int ();
 
       v = hb_clamp (v, -(1<<14), (1<<14));
       setter[axis_index] = v;
@@ -338,8 +367,9 @@ struct VarCompositeGlyphRecord
   protected:
   HBUINT16      flags;
   HBUINT8       numAxes;
+  HBUINT16      pad;
   public:
-  DEFINE_SIZE_MIN (3);
+  DEFINE_SIZE_MIN (5);
 };
 
 using var_composite_iter_t = composite_iter_tmpl;
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/coord-setter.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/coord-setter.hh
index df64ed5af7d2e..cf05929362f59 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/coord-setter.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/coord-setter.hh
@@ -16,6 +16,8 @@ struct coord_setter_t
 
   int& operator [] (unsigned idx)
   {
+    if (unlikely (idx >= HB_GLYF_VAR_COMPOSITE_MAX_AXES))
+      return Crap(int);
     if (coords.length < idx + 1)
       coords.resize (idx + 1);
     return coords[idx];
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf-helpers.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf-helpers.hh
index 18e2d92d0f418..3462e4d1ea5fd 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf-helpers.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf-helpers.hh
@@ -12,24 +12,44 @@ namespace OT {
 namespace glyf_impl {
 
 
-template
+template
 static void
-_write_loca (IteratorIn&& it, bool short_offsets, IteratorOut&& dest)
+_write_loca (IteratorIn&& it,
+             const hb_sorted_vector_t new_to_old_gid_list,
+             bool short_offsets,
+             TypeOut *dest,
+             unsigned num_offsets)
 {
   unsigned right_shift = short_offsets ? 1 : 0;
-  unsigned int offset = 0;
-  dest << 0;
-  + it
-  | hb_map ([=, &offset] (unsigned int padded_size)
-            {
-              offset += padded_size;
-              DEBUG_MSG (SUBSET, nullptr, "loca entry offset %u", offset);
-              return offset >> right_shift;
-            })
-  | hb_sink (dest)
-  ;
+  unsigned offset = 0;
+  TypeOut value;
+  value = 0;
+  *dest++ = value;
+  hb_codepoint_t last = 0;
+  for (auto _ : new_to_old_gid_list)
+  {
+    hb_codepoint_t gid = _.first;
+    for (; last < gid; last++)
+    {
+      DEBUG_MSG (SUBSET, nullptr, "loca entry empty offset %u", offset);
+      *dest++ = value;
+    }
+
+    unsigned padded_size = *it++;
+    offset += padded_size;
+    DEBUG_MSG (SUBSET, nullptr, "loca entry gid %u offset %u padded-size %u", gid, offset, padded_size);
+    value = offset >> right_shift;
+    *dest++ = value;
+
+    last++; // Skip over gid
+  }
+  unsigned num_glyphs = num_offsets - 1;
+  for (; last < num_glyphs; last++)
+  {
+    DEBUG_MSG (SUBSET, nullptr, "loca entry empty offset %u", offset);
+    *dest++ = value;
+  }
 }
 
 static bool
@@ -67,11 +87,14 @@ _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
 template
 static bool
-_add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_short_loca)
+_add_loca_and_head (hb_subset_context_t *c,
+                    Iterator padded_offsets,
+                    bool use_short_loca)
 {
-  unsigned num_offsets = padded_offsets.len () + 1;
+  unsigned num_offsets = c->plan->num_output_glyphs () + 1;
   unsigned entry_size = use_short_loca ? 2 : 4;
-  char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets);
+
+  char *loca_prime_data = (char *) hb_malloc (entry_size * num_offsets);
 
   if (unlikely (!loca_prime_data)) return false;
 
@@ -79,9 +102,9 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s
              entry_size, num_offsets, entry_size * num_offsets);
 
   if (use_short_loca)
-    _write_loca (padded_offsets, true, hb_array ((HBUINT16 *) loca_prime_data, num_offsets));
+    _write_loca (padded_offsets, c->plan->new_to_old_gid_list, true, (HBUINT16 *) loca_prime_data, num_offsets);
   else
-    _write_loca (padded_offsets, false, hb_array ((HBUINT32 *) loca_prime_data, num_offsets));
+    _write_loca (padded_offsets, c->plan->new_to_old_gid_list, false, (HBUINT32 *) loca_prime_data, num_offsets);
 
   hb_blob_t *loca_blob = hb_blob_create (loca_prime_data,
                                          entry_size * num_offsets,
@@ -89,8 +112,8 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s
                                          loca_prime_data,
                                          hb_free);
 
-  bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
-             && _add_head_and_set_loca_version (plan, use_short_loca);
+  bool result = c->plan->add_table (HB_OT_TAG_loca, loca_blob)
+             && _add_head_and_set_loca_version (c->plan, use_short_loca);
 
   hb_blob_destroy (loca_blob);
   return result;
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh
index d2a93a56d8502..175e1de308c51 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh
@@ -85,75 +85,72 @@ struct glyf
       return_trace (false);
     }
 
-    glyf *glyf_prime = c->serializer->start_embed  ();
-    if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
-
     hb_font_t *font = nullptr;
     if (c->plan->normalized_coords)
     {
       font = _create_font_for_instancing (c->plan);
-      if (unlikely (!font)) return false;
+      if (unlikely (!font))
+        return_trace (false);
     }
 
     hb_vector_t padded_offsets;
-    unsigned num_glyphs = c->plan->num_output_glyphs ();
-    if (unlikely (!padded_offsets.resize (num_glyphs)))
-    {
-      hb_font_destroy (font);
-      return false;
-    }
+    if (unlikely (!padded_offsets.alloc (c->plan->new_to_old_gid_list.length, true)))
+      return_trace (false);
 
     hb_vector_t glyphs;
     if (!_populate_subset_glyphs (c->plan, font, glyphs))
     {
       hb_font_destroy (font);
-      return false;
+      return_trace (false);
     }
 
     if (font)
       hb_font_destroy (font);
 
     unsigned max_offset = 0;
-    for (unsigned i = 0; i < num_glyphs; i++)
+    for (auto &g : glyphs)
     {
-      padded_offsets[i] = glyphs[i].padded_size ();
-      max_offset += padded_offsets[i];
+      unsigned size = g.padded_size ();
+      padded_offsets.push (size);
+      max_offset += size;
     }
 
     bool use_short_loca = false;
     if (likely (!c->plan->force_long_loca))
       use_short_loca = max_offset < 0x1FFFF;
 
-    if (!use_short_loca) {
-      for (unsigned i = 0; i < num_glyphs; i++)
-        padded_offsets[i] = glyphs[i].length ();
+    if (!use_short_loca)
+    {
+      padded_offsets.resize (0);
+      for (auto &g : glyphs)
+        padded_offsets.push (g.length ());
     }
 
-    bool result = glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan);
+    auto *glyf_prime = c->serializer->start_embed  ();
+    bool result = glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan);
     if (c->plan->normalized_coords && !c->plan->pinned_at_default)
       _free_compiled_subset_glyphs (glyphs);
 
-    if (!result) return false;
-
-    if (unlikely (c->serializer->in_error ())) return_trace (false);
+    if (unlikely (!c->serializer->check_success (glyf_impl::_add_loca_and_head (c,
+                                                 padded_offsets.iter (),
+                                                 use_short_loca))))
+      return_trace (false);
 
-    return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan,
-                                                                               padded_offsets.iter (),
-                                                                               use_short_loca)));
+    return result;
   }
 
   bool
   _populate_subset_glyphs (const hb_subset_plan_t   *plan,
                            hb_font_t                *font,
-                           hb_vector_t &glyphs /* OUT */) const;
+                           hb_vector_t& glyphs /* OUT */) const;
 
   hb_font_t *
   _create_font_for_instancing (const hb_subset_plan_t *plan) const;
 
   void _free_compiled_subset_glyphs (hb_vector_t &glyphs) const
   {
-    for (unsigned i = 0; i < glyphs.length; i++)
-      glyphs[i].free_compiled_bytes ();
+    for (auto &g : glyphs)
+      g.free_compiled_bytes ();
   }
 
   protected:
@@ -222,13 +219,14 @@ struct glyf_accelerator_t
     if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only)))
       return false;
 
+    unsigned count = all_points.length;
+    assert (count >= glyf_impl::PHANTOM_COUNT);
+    count -= glyf_impl::PHANTOM_COUNT;
+
     if (consumer.is_consuming_contour_points ())
     {
-      unsigned count = all_points.length;
-      assert (count >= glyf_impl::PHANTOM_COUNT);
-      count -= glyf_impl::PHANTOM_COUNT;
-      for (unsigned point_index = 0; point_index < count; point_index++)
-        consumer.consume_point (all_points[point_index]);
+      for (auto &point : all_points.as_array ().sub_array (0, count))
+        consumer.consume_point (point);
       consumer.points_end ();
     }
 
@@ -236,7 +234,7 @@ struct glyf_accelerator_t
     contour_point_t *phantoms = consumer.get_phantoms_sink ();
     if (phantoms)
       for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i)
-        phantoms[i] = all_points[all_points.length - glyf_impl::PHANTOM_COUNT + i];
+        phantoms[i] = all_points.arrayZ[count + i];
 
     return true;
   }
@@ -299,6 +297,7 @@ struct glyf_accelerator_t
       if (extents) bounds = contour_bounds_t ();
     }
 
+    HB_ALWAYS_INLINE
     void consume_point (const contour_point_t &point) { bounds.add (point); }
     void points_end () { bounds.get_extents (font, extents, scaled); }
 
@@ -431,16 +430,17 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t   *plan,
                                hb_vector_t& glyphs /* OUT */) const
 {
   OT::glyf_accelerator_t glyf (plan->source);
-  unsigned num_glyphs = plan->num_output_glyphs ();
-  if (!glyphs.resize (num_glyphs)) return false;
+  if (!glyphs.alloc (plan->new_to_old_gid_list.length, true)) return false;
 
-  for (auto p : plan->glyph_map->iter ())
+  for (const auto &pair : plan->new_to_old_gid_list)
   {
-    unsigned new_gid = p.second;
-    glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid];
-    subset_glyph.old_gid = p.first;
+    hb_codepoint_t new_gid = pair.first;
+    hb_codepoint_t old_gid = pair.second;
+    glyf_impl::SubsetGlyph *p = glyphs.push ();
+    glyf_impl::SubsetGlyph& subset_glyph = *p;
+    subset_glyph.old_gid = old_gid;
 
-    if (unlikely (new_gid == 0 &&
+    if (unlikely (old_gid == 0 && new_gid == 0 &&
                   !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
                   !plan->normalized_coords)
       subset_glyph.source_glyph = glyf_impl::Glyph ();
@@ -487,7 +487,7 @@ glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const
   {
     hb_variation_t var;
     var.tag = _.first;
-    var.value = _.second;
+    var.value = _.second.middle;
     vars.push (var);
   }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/path-builder.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/path-builder.hh
index 6a476204f1040..d56ea3e45ff4b 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/path-builder.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/path-builder.hh
@@ -21,19 +21,15 @@ struct path_builder_t
     operator bool () const { return has_data; }
 
     bool has_data = false;
-    float x = 0.;
-    float y = 0.;
+    float x;
+    float y;
 
-    optional_point_t lerp (optional_point_t p, float t)
-    { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
+    optional_point_t mid (optional_point_t p)
+    { return optional_point_t ((x + p.x) * 0.5f, (y + p.y) * 0.5f); }
   } first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2;
 
-  path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
-  {
-    font = font_;
-    draw_session = &draw_session_;
-    first_oncurve = first_offcurve = first_offcurve2 = last_offcurve = last_offcurve2 = optional_point_t ();
-  }
+  path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) :
+    font (font_), draw_session (&draw_session_) {}
 
   /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
      See also:
@@ -41,6 +37,7 @@ struct path_builder_t
      * https://stackoverflow.com/a/20772557
      *
      * Cubic support added. */
+  HB_ALWAYS_INLINE
   void consume_point (const contour_point_t &point)
   {
     bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
@@ -50,7 +47,7 @@ struct path_builder_t
     bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC);
 #endif
     optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y));
-    if (!first_oncurve)
+    if (unlikely (!first_oncurve))
     {
       if (is_on_curve)
       {
@@ -66,7 +63,7 @@ struct path_builder_t
         }
         else if (first_offcurve)
         {
-          optional_point_t mid = first_offcurve.lerp (p, .5f);
+          optional_point_t mid = first_offcurve.mid (p);
           first_oncurve = mid;
           last_offcurve = p;
           draw_session->move_to (mid.x, mid.y);
@@ -102,7 +99,7 @@ struct path_builder_t
           }
           else
           {
-            optional_point_t mid = last_offcurve.lerp (p, .5f);
+            optional_point_t mid = last_offcurve.mid (p);
 
             if (is_cubic)
             {
@@ -127,13 +124,13 @@ struct path_builder_t
       }
     }
 
-    if (point.is_end_point)
+    if (unlikely (point.is_end_point))
     {
       if (first_offcurve && last_offcurve)
       {
-        optional_point_t mid = last_offcurve.lerp (first_offcurve2 ?
-                                                   first_offcurve2 :
-                                                   first_offcurve, .5f);
+        optional_point_t mid = last_offcurve.mid (first_offcurve2 ?
+                                                  first_offcurve2 :
+                                                  first_offcurve);
         if (last_offcurve2)
           draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
                                   last_offcurve.x, last_offcurve.y,
diff --git a/src/java.desktop/share/native/libharfbuzz/OT/name/name.hh b/src/java.desktop/share/native/libharfbuzz/OT/name/name.hh
index 15ff7a8bdb75c..f14c2da2de68f 100644
--- a/src/java.desktop/share/native/libharfbuzz/OT/name/name.hh
+++ b/src/java.desktop/share/native/libharfbuzz/OT/name/name.hh
@@ -359,7 +359,7 @@ struct name
       record.nameID = ids.name_id;
       record.length = 0; // handled in NameRecord copy()
       record.offset = 0;
-      memcpy (name_records, &record, NameRecord::static_size);
+      hb_memcpy (name_records, &record, NameRecord::static_size);
       name_records++;
     }
 #endif
@@ -384,10 +384,7 @@ struct name
 
   bool subset (hb_subset_context_t *c) const
   {
-    TRACE_SUBSET (this);
-
-    name *name_prime = c->serializer->start_embed ();
-    if (unlikely (!name_prime)) return_trace (false);
+    auto *name_prime = c->serializer->start_embed ();
 
 #ifdef HB_EXPERIMENTAL_API
     const hb_hashmap_t *name_table_overrides =
@@ -436,7 +433,7 @@ struct name
     if (!name_table_overrides->is_empty ())
     {
       if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population (), true)))
-        return_trace (false);
+        return false;
       for (const auto& record_ids : name_table_overrides->keys ())
       {
         if (name_table_overrides->get (record_ids).length == 0)
@@ -448,13 +445,13 @@ struct name
     }
 #endif
 
-    return (name_prime->serialize (c->serializer, it,
-                                   std::addressof (this + stringOffset)
+    return name_prime->serialize (c->serializer, it,
+                                  std::addressof (this + stringOffset)
 #ifdef HB_EXPERIMENTAL_API
-                                   , insert_name_records
-                                   , name_table_overrides
+                                  , insert_name_records
+                                  , name_table_overrides
 #endif
-                                   ));
+                                  );
   }
 
   bool sanitize_records (hb_sanitize_context_t *c) const
diff --git a/src/java.desktop/share/native/libharfbuzz/UPDATING.txt b/src/java.desktop/share/native/libharfbuzz/UPDATING.txt
index 6b4e7ccc4fef2..3f72983a45576 100644
--- a/src/java.desktop/share/native/libharfbuzz/UPDATING.txt
+++ b/src/java.desktop/share/native/libharfbuzz/UPDATING.txt
@@ -106,7 +106,7 @@ STEP 6: TESTING
   Look for manual related layout jtreg tests (test/jdk/java/awt/font/TextLayout)
   and run on Windows,Linux and Mac.
   Use Font2DTest set to TextLayout and check the above languages. Probably
-  not going to see layout problems a code point at a time but it needs to
+  not going to see layout problems in code at this point of time but it needs to
   be checked.
 
   Different unicode combinations can be checked using Font2DTest.
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh
index c2e24a7067874..c1432883ffaae 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh
@@ -72,7 +72,7 @@ struct ClassDef : public OT::ClassDef
     class_def_link->width = SmallTypes::size;
     class_def_link->objidx = class_def_prime_id;
     class_def_link->position = link_position;
-    class_def_prime_vertex.parents.push (parent_id);
+    class_def_prime_vertex.add_parent (parent_id);
 
     return true;
   }
@@ -94,7 +94,13 @@ struct ClassDef : public OT::ClassDef
     }
 
     hb_bytes_t class_def_copy = serializer.copy_bytes ();
-    c.add_buffer ((char *) class_def_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer.
+    if (!class_def_copy.arrayZ) return false;
+    // Give ownership to the context, it will cleanup the buffer.
+    if (!c.add_buffer ((char *) class_def_copy.arrayZ))
+    {
+      hb_free ((char *) class_def_copy.arrayZ);
+      return false;
+    }
 
     auto& obj = c.graph.vertices_[dest_obj].obj;
     obj.head = (char *) class_def_copy.arrayZ;
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh
index 49d09363156a9..4f44e076d1f3e 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh
@@ -96,7 +96,7 @@ struct Coverage : public OT::Layout::Common::Coverage
     coverage_link->width = SmallTypes::size;
     coverage_link->objidx = coverage_prime_id;
     coverage_link->position = link_position;
-    coverage_prime_vertex.parents.push (parent_id);
+    coverage_prime_vertex.add_parent (parent_id);
 
     return (Coverage*) coverage_prime_vertex.obj.head;
   }
@@ -118,7 +118,13 @@ struct Coverage : public OT::Layout::Common::Coverage
     }
 
     hb_bytes_t coverage_copy = serializer.copy_bytes ();
-    c.add_buffer ((char *) coverage_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer.
+    if (!coverage_copy.arrayZ) return false;
+    // Give ownership to the context, it will cleanup the buffer.
+    if (!c.add_buffer ((char *) coverage_copy.arrayZ))
+    {
+      hb_free ((char *) coverage_copy.arrayZ);
+      return false;
+    }
 
     auto& obj = c.graph.vertices_[dest_obj].obj;
     obj.head = (char *) coverage_copy.arrayZ;
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/graph.hh
index 38ca5db096186..4a1f7ebf5a5c1 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/graph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/graph.hh
@@ -43,12 +43,28 @@ struct graph_t
   {
     hb_serialize_context_t::object_t obj;
     int64_t distance = 0 ;
-    int64_t space = 0 ;
-    hb_vector_t parents;
+    unsigned space = 0 ;
     unsigned start = 0;
     unsigned end = 0;
     unsigned priority = 0;
-
+    private:
+    unsigned incoming_edges_ = 0;
+    unsigned single_parent = (unsigned) -1;
+    hb_hashmap_t parents;
+    public:
+
+    auto parents_iter () const HB_AUTO_RETURN
+    (
+      hb_concat (
+        hb_iter (&single_parent, single_parent != (unsigned) -1),
+        parents.keys_ref ()
+      )
+    )
+
+    bool in_error () const
+    {
+      return parents.in_error ();
+    }
 
     bool link_positions_valid (unsigned num_objects, bool removed_nil)
     {
@@ -143,7 +159,9 @@ struct graph_t
       hb_swap (a.obj, b.obj);
       hb_swap (a.distance, b.distance);
       hb_swap (a.space, b.space);
+      hb_swap (a.single_parent, b.single_parent);
       hb_swap (a.parents, b.parents);
+      hb_swap (a.incoming_edges_, b.incoming_edges_);
       hb_swap (a.start, b.start);
       hb_swap (a.end, b.end);
       hb_swap (a.priority, b.priority);
@@ -154,6 +172,7 @@ struct graph_t
     {
       hb_hashmap_t result;
 
+      result.alloc (obj.real_links.length);
       for (const auto& l : obj.real_links) {
         result.set (l.position, l.objidx);
       }
@@ -163,27 +182,83 @@ struct graph_t
 
     bool is_shared () const
     {
-      return parents.length > 1;
+      return parents.get_population () > 1;
     }
 
     unsigned incoming_edges () const
     {
-      return parents.length;
+      if (HB_DEBUG_SUBSET_REPACK)
+       {
+        assert (incoming_edges_ == (single_parent != (unsigned) -1) +
+                (parents.values_ref () | hb_reduce (hb_add, 0)));
+       }
+      return incoming_edges_;
+    }
+
+    void reset_parents ()
+    {
+      incoming_edges_ = 0;
+      single_parent = (unsigned) -1;
+      parents.reset ();
+    }
+
+    void add_parent (unsigned parent_index)
+    {
+      assert (parent_index != (unsigned) -1);
+      if (incoming_edges_ == 0)
+      {
+        single_parent = parent_index;
+        incoming_edges_ = 1;
+        return;
+      }
+      else if (single_parent != (unsigned) -1)
+      {
+        assert (incoming_edges_ == 1);
+        if (!parents.set (single_parent, 1))
+          return;
+        single_parent = (unsigned) -1;
+      }
+
+      unsigned *v;
+      if (parents.has (parent_index, &v))
+      {
+        (*v)++;
+        incoming_edges_++;
+      }
+      else if (parents.set (parent_index, 1))
+        incoming_edges_++;
     }
 
     void remove_parent (unsigned parent_index)
     {
-      for (unsigned i = 0; i < parents.length; i++)
+      if (parent_index == single_parent)
       {
-        if (parents[i] != parent_index) continue;
-        parents.remove_unordered (i);
-        break;
+        single_parent = (unsigned) -1;
+        incoming_edges_--;
+        return;
+      }
+
+      unsigned *v;
+      if (parents.has (parent_index, &v))
+      {
+        incoming_edges_--;
+        if (*v > 1)
+          (*v)--;
+        else
+          parents.del (parent_index);
+
+        if (incoming_edges_ == 1)
+        {
+          single_parent = *parents.keys ();
+          parents.reset ();
+        }
       }
     }
 
     void remove_real_link (unsigned child_index, const void* offset)
     {
-      for (unsigned i = 0; i < obj.real_links.length; i++)
+      unsigned count = obj.real_links.length;
+      for (unsigned i = 0; i < count; i++)
       {
         auto& link = obj.real_links.arrayZ[i];
         if (link.objidx != child_index)
@@ -197,18 +272,53 @@ struct graph_t
       }
     }
 
-    void remap_parents (const hb_vector_t& id_map)
+    bool remap_parents (const hb_vector_t& id_map)
     {
-      for (unsigned i = 0; i < parents.length; i++)
-        parents[i] = id_map[parents[i]];
+      if (single_parent != (unsigned) -1)
+      {
+        assert (single_parent < id_map.length);
+        single_parent = id_map[single_parent];
+        return true;
+      }
+
+      hb_hashmap_t new_parents;
+      new_parents.alloc (parents.get_population ());
+      for (auto _ : parents)
+      {
+        assert (_.first < id_map.length);
+        assert (!new_parents.has (id_map[_.first]));
+        new_parents.set (id_map[_.first], _.second);
+      }
+
+      if (parents.in_error() || new_parents.in_error ())
+        return false;
+
+      parents = std::move (new_parents);
+      return true;
     }
 
     void remap_parent (unsigned old_index, unsigned new_index)
     {
-      for (unsigned i = 0; i < parents.length; i++)
+      if (single_parent != (unsigned) -1)
       {
-        if (parents[i] == old_index)
-          parents[i] = new_index;
+        if (single_parent == old_index)
+          single_parent = new_index;
+        return;
+      }
+
+      const unsigned *pv;
+      if (parents.has (old_index, &pv))
+      {
+        unsigned v = *pv;
+        if (!parents.set (new_index, v))
+          incoming_edges_ -= v;
+        parents.del (old_index);
+
+        if (incoming_edges_ == 1)
+        {
+          single_parent = *parents.keys ();
+          parents.reset ();
+        }
       }
     }
 
@@ -328,11 +438,12 @@ struct graph_t
     bool removed_nil = false;
     vertices_.alloc (objects.length);
     vertices_scratch_.alloc (objects.length);
-    for (unsigned i = 0; i < objects.length; i++)
+    unsigned count = objects.length;
+    for (unsigned i = 0; i < count; i++)
     {
       // If this graph came from a serialization buffer object 0 is the
       // nil object. We don't need it for our purposes here so drop it.
-      if (i == 0 && !objects[i])
+      if (i == 0 && !objects.arrayZ[i])
       {
         removed_nil = true;
         continue;
@@ -340,9 +451,9 @@ struct graph_t
 
       vertex_t* v = vertices_.push ();
       if (check_success (!vertices_.in_error ()))
-        v->obj = *objects[i];
+        v->obj = *objects.arrayZ[i];
 
-      check_success (v->link_positions_valid (objects.length, removed_nil));
+      check_success (v->link_positions_valid (count, removed_nil));
 
       if (!removed_nil) continue;
       // Fix indices to account for removed nil object.
@@ -354,7 +465,6 @@ struct graph_t
 
   ~graph_t ()
   {
-    vertices_.fini ();
     for (char* b : buffers)
       hb_free (b);
   }
@@ -364,6 +474,18 @@ struct graph_t
     return root ().equals (other.root (), *this, other, 0);
   }
 
+  void print () const {
+    for (int i = vertices_.length - 1; i >= 0; i--)
+    {
+      const auto& v = vertices_[i];
+      printf("%d: %u [", i, (unsigned int)v.table_size());
+      for (const auto &l : v.obj.real_links) {
+        printf("%u, ", l.objidx);
+      }
+      printf("]\n");
+    }
+  }
+
   // Sorts links of all objects in a consistent manner and zeroes all offsets.
   void normalize ()
   {
@@ -396,9 +518,10 @@ struct graph_t
     return vertices_[i].obj;
   }
 
-  void add_buffer (char* buffer)
+  bool add_buffer (char* buffer)
   {
     buffers.push (buffer);
+    return !buffers.in_error ();
   }
 
   /*
@@ -414,7 +537,7 @@ struct graph_t
     link->width = 2;
     link->objidx = child_id;
     link->position = (char*) offset - (char*) v.obj.head;
-    vertices_[child_id].parents.push (parent_id);
+    vertices_[child_id].add_parent (parent_id);
   }
 
   /*
@@ -443,7 +566,7 @@ struct graph_t
 
     update_distances ();
 
-    hb_priority_queue_t queue;
+    hb_priority_queue_t queue;
     hb_vector_t &sorted_graph = vertices_scratch_;
     if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
     hb_vector_t id_map;
@@ -460,7 +583,7 @@ struct graph_t
     {
       unsigned next_id = queue.pop_minimum().second;
 
-      hb_swap (sorted_graph[new_id], vertices_[next_id]);
+      sorted_graph[new_id] = std::move (vertices_[next_id]);
       const vertex_t& next = sorted_graph[new_id];
 
       if (unlikely (!check_success(new_id >= 0))) {
@@ -488,8 +611,8 @@ struct graph_t
     check_success (!queue.in_error ());
     check_success (!sorted_graph.in_error ());
 
-    remap_all_obj_indices (id_map, &sorted_graph);
-    hb_swap (vertices_, sorted_graph);
+    check_success (remap_all_obj_indices (id_map, &sorted_graph));
+    vertices_ = std::move (sorted_graph);
 
     if (!check_success (new_id == -1))
       print_orphaned_nodes ();
@@ -579,8 +702,8 @@ struct graph_t
     const auto& node = object (node_idx);
     if (offset < node.head || offset >= node.tail) return -1;
 
-    unsigned length = node.real_links.length;
-    for (unsigned i = 0; i < length; i++)
+    unsigned count = node.real_links.length;
+    for (unsigned i = 0; i < count; i++)
     {
       // Use direct access for increased performance, this is a hot method.
       const auto& link = node.real_links.arrayZ[i];
@@ -600,7 +723,7 @@ struct graph_t
   {
     unsigned child_idx = index_for_offset (node_idx, offset);
     auto& child = vertices_[child_idx];
-    for (unsigned p : child.parents)
+    for (unsigned p : child.parents_iter ())
     {
       if (p != node_idx) {
         return duplicate (node_idx, child_idx);
@@ -683,12 +806,15 @@ struct graph_t
       subgraph.set (root_idx, wide_parents (root_idx, parents));
       find_subgraph (root_idx, subgraph);
     }
+    if (subgraph.in_error ())
+      return false;
 
     unsigned original_root_idx = root_idx ();
     hb_map_t index_map;
     bool made_changes = false;
     for (auto entry : subgraph.iter ())
     {
+      assert (entry.first < vertices_.length);
       const auto& node = vertices_[entry.first];
       unsigned subgraph_incoming_edges = entry.second;
 
@@ -727,8 +853,7 @@ struct graph_t
     remap_obj_indices (index_map, parents.iter (), true);
 
     // Update roots set with new indices as needed.
-    uint32_t next = HB_SET_VALUE_INVALID;
-    while (roots.next (&next))
+    for (auto next : roots)
     {
       const uint32_t *v;
       if (index_map.has (next, &v))
@@ -745,10 +870,10 @@ struct graph_t
   {
     for (const auto& link : vertices_[node_idx].obj.all_links ())
     {
-      const uint32_t *v;
+      hb_codepoint_t *v;
       if (subgraph.has (link.objidx, &v))
       {
-        subgraph.set (link.objidx, *v + 1);
+        (*v)++;
         continue;
       }
       subgraph.set (link.objidx, 1);
@@ -820,7 +945,7 @@ struct graph_t
     new_link->position = (const char*) new_offset - (const char*) new_v.obj.head;
 
     auto& child = vertices_[child_id];
-    child.parents.push (new_parent_idx);
+    child.add_parent (new_parent_idx);
 
     old_v.remove_real_link (child_id, old_offset);
     child.remove_parent (old_parent_idx);
@@ -864,18 +989,18 @@ struct graph_t
     clone->obj.tail = child.obj.tail;
     clone->distance = child.distance;
     clone->space = child.space;
-    clone->parents.reset ();
+    clone->reset_parents ();
 
     unsigned clone_idx = vertices_.length - 2;
     for (const auto& l : child.obj.real_links)
     {
       clone->obj.real_links.push (l);
-      vertices_[l.objidx].parents.push (clone_idx);
+      vertices_[l.objidx].add_parent (clone_idx);
     }
     for (const auto& l : child.obj.virtual_links)
     {
       clone->obj.virtual_links.push (l);
-      vertices_[l.objidx].parents.push (clone_idx);
+      vertices_[l.objidx].add_parent (clone_idx);
     }
 
     check_success (!clone->obj.real_links.in_error ());
@@ -1004,13 +1129,13 @@ struct graph_t
   {
     update_parents();
 
-    if (root().parents)
+    if (root().incoming_edges ())
       // Root cannot have parents.
       return false;
 
     for (unsigned i = 0; i < root_idx (); i++)
     {
-      if (!vertices_[i].parents)
+      if (!vertices_[i].incoming_edges ())
         return false;
     }
     return true;
@@ -1074,14 +1199,14 @@ struct graph_t
     parents_invalid = true;
     update_parents();
 
-    if (root().parents) {
+    if (root().incoming_edges ()) {
       DEBUG_MSG (SUBSET_REPACK, nullptr, "Root node has incoming edges.");
     }
 
     for (unsigned i = 0; i < root_idx (); i++)
     {
       const auto& v = vertices_[i];
-      if (!v.parents)
+      if (!v.incoming_edges ())
         DEBUG_MSG (SUBSET_REPACK, nullptr, "Node %u is orphaned.", i);
     }
   }
@@ -1113,6 +1238,8 @@ struct graph_t
 
   unsigned space_for (unsigned index, unsigned* root = nullptr) const
   {
+  loop:
+    assert (index < vertices_.length);
     const auto& node = vertices_[index];
     if (node.space)
     {
@@ -1121,22 +1248,24 @@ struct graph_t
       return node.space;
     }
 
-    if (!node.parents)
+    if (!node.incoming_edges ())
     {
       if (root)
         *root = index;
       return 0;
     }
 
-    return space_for (node.parents[0], root);
+    index = *node.parents_iter ();
+    goto loop;
   }
 
   void err_other_error () { this->successful = false; }
 
   size_t total_size_in_bytes () const {
     size_t total_size = 0;
-    for (unsigned i = 0; i < vertices_.length; i++) {
-      size_t size = vertices_[i].obj.tail - vertices_[i].obj.head;
+    unsigned count = vertices_.length;
+    for (unsigned i = 0; i < count; i++) {
+      size_t size = vertices_.arrayZ[i].obj.tail - vertices_.arrayZ[i].obj.head;
       total_size += size;
     }
     return total_size;
@@ -1151,12 +1280,8 @@ struct graph_t
   unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const
   {
     unsigned count = 0;
-    hb_set_t visited;
-    for (unsigned p : vertices_[node_idx].parents)
+    for (unsigned p : vertices_[node_idx].parents_iter ())
     {
-      if (visited.has (p)) continue;
-      visited.add (p);
-
       // Only real links can be wide
       for (const auto& l : vertices_[p].obj.real_links)
       {
@@ -1183,21 +1308,21 @@ struct graph_t
   {
     if (!parents_invalid) return;
 
-    for (unsigned i = 0; i < vertices_.length; i++)
-      vertices_[i].parents.reset ();
+    unsigned count = vertices_.length;
 
-    for (unsigned p = 0; p < vertices_.length; p++)
+    for (unsigned i = 0; i < count; i++)
+      vertices_.arrayZ[i].reset_parents ();
+
+    for (unsigned p = 0; p < count; p++)
     {
-      for (auto& l : vertices_[p].obj.all_links ())
-      {
-        vertices_[l.objidx].parents.push (p);
-      }
+      for (auto& l : vertices_.arrayZ[p].obj.all_links ())
+        vertices_[l.objidx].add_parent (p);
     }
 
-    for (unsigned i = 0; i < vertices_.length; i++)
+    for (unsigned i = 0; i < count; i++)
       // parents arrays must be accurate or downstream operations like cycle detection
       // and sorting won't work correctly.
-      check_success (!vertices_[i].parents.in_error ());
+      check_success (!vertices_.arrayZ[i].in_error ());
 
     parents_invalid = false;
   }
@@ -1239,15 +1364,12 @@ struct graph_t
     // According to https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf
     // for practical performance this is faster then using a more advanced queue
     // (such as a fibonacci queue) with a fast decrease priority.
-    for (unsigned i = 0; i < vertices_.length; i++)
-    {
-      if (i == vertices_.length - 1)
-        vertices_[i].distance = 0;
-      else
-        vertices_[i].distance = hb_int_max (int64_t);
-    }
+    unsigned count = vertices_.length;
+    for (unsigned i = 0; i < count; i++)
+      vertices_.arrayZ[i].distance = hb_int_max (int64_t);
+    vertices_.tail ().distance = 0;
 
-    hb_priority_queue_t queue;
+    hb_priority_queue_t queue;
     queue.insert (0, vertices_.length - 1);
 
     hb_vector_t visited;
@@ -1265,15 +1387,15 @@ struct graph_t
       {
         if (visited[link.objidx]) continue;
 
-        const auto& child = vertices_[link.objidx].obj;
+        const auto& child = vertices_.arrayZ[link.objidx].obj;
         unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide
         int64_t child_weight = (child.tail - child.head) +
-                               ((int64_t) 1 << (link_width * 8)) * (vertices_[link.objidx].space + 1);
+                               ((int64_t) 1 << (link_width * 8)) * (vertices_.arrayZ[link.objidx].space + 1);
         int64_t child_distance = next_distance + child_weight;
 
-        if (child_distance < vertices_[link.objidx].distance)
+        if (child_distance < vertices_.arrayZ[link.objidx].distance)
         {
-          vertices_[link.objidx].distance = child_distance;
+          vertices_.arrayZ[link.objidx].distance = child_distance;
           queue.insert (child_distance, link.objidx);
         }
       }
@@ -1301,7 +1423,7 @@ struct graph_t
     unsigned old_idx = link.objidx;
     link.objidx = new_idx;
     vertices_[old_idx].remove_parent (parent_idx);
-    vertices_[new_idx].parents.push (parent_idx);
+    vertices_[new_idx].add_parent (parent_idx);
   }
 
   /*
@@ -1329,17 +1451,20 @@ struct graph_t
   /*
    * Updates all objidx's in all links using the provided mapping.
    */
-  void remap_all_obj_indices (const hb_vector_t& id_map,
+  bool remap_all_obj_indices (const hb_vector_t& id_map,
                               hb_vector_t* sorted_graph) const
   {
-    for (unsigned i = 0; i < sorted_graph->length; i++)
+    unsigned count = sorted_graph->length;
+    for (unsigned i = 0; i < count; i++)
     {
-      (*sorted_graph)[i].remap_parents (id_map);
-      for (auto& link : (*sorted_graph)[i].obj.all_links_writer ())
+      if (!(*sorted_graph)[i].remap_parents (id_map))
+        return false;
+      for (auto& link : sorted_graph->arrayZ[i].obj.all_links_writer ())
       {
         link.objidx = id_map[link.objidx];
       }
     }
+    return true;
   }
 
   /*
@@ -1370,7 +1495,7 @@ struct graph_t
     for (const auto& l : v.obj.all_links ())
       find_connected_nodes (l.objidx, targets, visited, connected);
 
-    for (unsigned p : v.parents)
+    for (unsigned p : v.parents_iter ())
       find_connected_nodes (p, targets, visited, connected);
   }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.cc b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.cc
index b2044426d46d2..d66eb49cfd2e2 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.cc
+++ b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.cc
@@ -52,7 +52,11 @@ unsigned gsubgpos_graph_context_t::create_node (unsigned size)
   if (!buffer)
     return -1;
 
-  add_buffer (buffer);
+  if (!add_buffer (buffer)) {
+    // Allocation did not get stored for freeing later.
+    hb_free (buffer);
+    return -1;
+  }
 
   return graph.new_node (buffer, buffer + size);
 }
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh
index 9fe9662e64508..b25d538fe3dde 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh
@@ -40,16 +40,16 @@ struct gsubgpos_graph_context_t
   graph_t& graph;
   unsigned lookup_list_index;
   hb_hashmap_t lookups;
-
+  hb_hashmap_t subtable_to_extension;
 
   HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_,
                                         graph_t& graph_);
 
   HB_INTERNAL unsigned create_node (unsigned size);
 
-  void add_buffer (char* buffer)
+  bool add_buffer (char* buffer)
   {
-    graph.add_buffer (buffer);
+    return graph.add_buffer (buffer);
   }
 
  private:
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh
index c170638409f82..a5f9223e6059e 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh
@@ -166,7 +166,7 @@ struct Lookup : public OT::Lookup
     }
 
     if (all_new_subtables) {
-      add_sub_tables (c, this_index, type, all_new_subtables);
+      return add_sub_tables (c, this_index, type, all_new_subtables);
     }
 
     return true;
@@ -184,7 +184,7 @@ struct Lookup : public OT::Lookup
     return sub_table->split_subtables (c, parent_idx, objidx);
   }
 
-  void add_sub_tables (gsubgpos_graph_context_t& c,
+  bool add_sub_tables (gsubgpos_graph_context_t& c,
                        unsigned this_index,
                        unsigned type,
                        hb_vector_t>>& subtable_ids)
@@ -200,7 +200,12 @@ struct Lookup : public OT::Lookup
     size_t new_size = v.table_size ()
                       + new_subtable_count * OT::Offset16::static_size;
     char* buffer = (char*) hb_calloc (1, new_size);
-    c.add_buffer (buffer);
+    if (!buffer) return false;
+    if (!c.add_buffer (buffer))
+    {
+      hb_free (buffer);
+     return false;
+    }
     hb_memcpy (buffer, v.obj.head, v.table_size());
 
     v.obj.head = buffer;
@@ -220,7 +225,7 @@ struct Lookup : public OT::Lookup
         if (is_ext)
         {
           unsigned ext_id = create_extension_subtable (c, subtable_id, type);
-          c.graph.vertices_[subtable_id].parents.push (ext_id);
+          c.graph.vertices_[subtable_id].add_parent (ext_id);
           subtable_id = ext_id;
         }
 
@@ -229,7 +234,7 @@ struct Lookup : public OT::Lookup
         link->objidx = subtable_id;
         link->position = (char*) &new_lookup->subTable[offset_index++] -
                          (char*) new_lookup;
-        c.graph.vertices_[subtable_id].parents.push (this_index);
+        c.graph.vertices_[subtable_id].add_parent (this_index);
       }
     }
 
@@ -239,6 +244,7 @@ struct Lookup : public OT::Lookup
     // The head location of the lookup has changed, invalidating the lookups map entry
     // in the context. Update the map.
     c.lookups.set (this_index, new_lookup);
+    return true;
   }
 
   void fix_existing_subtable_links (gsubgpos_graph_context_t& c,
@@ -293,24 +299,35 @@ struct Lookup : public OT::Lookup
                                 unsigned subtable_index)
   {
     unsigned type = lookupType;
+    unsigned ext_index = -1;
+    unsigned* existing_ext_index = nullptr;
+    if (c.subtable_to_extension.has(subtable_index, &existing_ext_index)) {
+      ext_index = *existing_ext_index;
+    } else {
+      ext_index = create_extension_subtable(c, subtable_index, type);
+      c.subtable_to_extension.set(subtable_index, ext_index);
+    }
 
-    unsigned ext_index = create_extension_subtable(c, subtable_index, type);
     if (ext_index == (unsigned) -1)
       return false;
 
+    auto& subtable_vertex = c.graph.vertices_[subtable_index];
     auto& lookup_vertex = c.graph.vertices_[lookup_index];
     for (auto& l : lookup_vertex.obj.real_links.writer ())
     {
-      if (l.objidx == subtable_index)
+      if (l.objidx == subtable_index) {
         // Change lookup to point at the extension.
         l.objidx = ext_index;
+        if (existing_ext_index)
+          subtable_vertex.remove_parent(lookup_index);
+      }
     }
 
     // Make extension point at the subtable.
     auto& ext_vertex = c.graph.vertices_[ext_index];
-    auto& subtable_vertex = c.graph.vertices_[subtable_index];
-    ext_vertex.parents.push (lookup_index);
-    subtable_vertex.remap_parent (lookup_index, ext_index);
+    ext_vertex.add_parent (lookup_index);
+    if (!existing_ext_index)
+      subtable_vertex.remap_parent (lookup_index, ext_index);
 
     return true;
   }
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh
index 84ef5f71b93cf..ae5ebd0d16756 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh
@@ -217,7 +217,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2::min_size +
+        OT::Layout::GPOS_impl::MarkBasePosFormat1_2::min_size +
         MarkArray::min_size +
         AnchorMatrix::min_size +
         c.graph.vertices_[base_coverage_id].table_size ();
@@ -318,8 +318,11 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2 class_to_info;
 
-    unsigned class_count= classCount;
-    class_to_info.resize (class_count);
+    unsigned class_count = classCount;
+    if (!class_count) return class_to_info;
+
+    if (!class_to_info.resize (class_count))
+      return hb_vector_t();
 
     auto mark_array = c.graph.as_table (this_index, &markArray);
     if (!mark_array) return hb_vector_t ();
@@ -327,6 +330,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2= class_count) continue;
       class_to_info[klass].marks.add (mark);
     }
 
@@ -335,6 +339,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2= class_count) continue;
       class_to_info[klass].child_indices.push (link.objidx);
     }
 
@@ -479,7 +484,7 @@ struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
       return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
 #ifndef HB_NO_BEYOND_64K
     case 2: HB_FALLTHROUGH;
-      // Don't split 24bit PairPos's.
+      // Don't split 24bit MarkBasePos's.
 #endif
     default:
       return hb_vector_t ();
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh
index 1c13eb24f9458..ad158cc9e8fae 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh
@@ -215,7 +215,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4iter ()
         | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
-          return hb_pair_t (gid, class_def_1->get_class (gid));
+          return hb_codepoint_pair_t (gid, class_def_1->get_class (gid));
         })
         ;
     class_def_size_estimator_t estimator (gid_and_class);
@@ -386,14 +386,14 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4iter ()
     | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
-      return hb_pair_t (gid, class_def_1_table->get_class (gid));
+      return hb_codepoint_pair_t (gid, class_def_1_table->get_class (gid));
     })
     | hb_filter ([&] (hb_codepoint_t klass) {
       return klass >= start && klass < end;
     }, hb_second)
-    | hb_map_retains_sorting ([&] (hb_pair_t gid_and_class) {
+    | hb_map_retains_sorting ([&] (hb_codepoint_pair_t gid_and_class) {
       // Classes must be from 0...N so subtract start
-      return hb_pair_t (gid_and_class.first, gid_and_class.second - start);
+      return hb_codepoint_pair_t (gid_and_class.first, gid_and_class.second - start);
     })
     ;
 
@@ -419,7 +419,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4width = SmallTypes::size;
     class_def_link->objidx = class_def_2_id;
     class_def_link->position = 10;
-    graph.vertices_[class_def_2_id].parents.push (pair_pos_prime_id);
+    graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id);
     graph.duplicate (pair_pos_prime_id, class_def_2_id);
 
     return pair_pos_prime_id;
@@ -519,7 +519,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4iter ()
     | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
-      return hb_pair_t (gid, class_def_1.table->get_class (gid));
+      return hb_codepoint_pair_t (gid, class_def_1.table->get_class (gid));
     })
     | hb_filter ([&] (hb_codepoint_t klass) {
       return klass < count;
diff --git a/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh b/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh
index 040fd1de5fd5b..06e4bf44d8e72 100644
--- a/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh
+++ b/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh
@@ -116,10 +116,10 @@ will_overflow (graph_t& graph,
   for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--)
   {
     // Don't need to check virtual links for overflow
-    for (const auto& link : vertices[parent_idx].obj.real_links)
+    for (const auto& link : vertices.arrayZ[parent_idx].obj.real_links)
     {
       int64_t offset = compute_offset (graph, parent_idx, link);
-      if (is_valid_offset (offset, link))
+      if (likely (is_valid_offset (offset, link)))
         continue;
 
       if (!overflows) return true;
@@ -226,6 +226,9 @@ inline hb_blob_t* serialize (const graph_t& graph)
 {
   hb_vector_t buffer;
   size_t size = graph.total_size_in_bytes ();
+
+  if (!size) return hb_blob_get_empty ();
+
   if (!buffer.alloc (size)) {
     DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer.");
     return nullptr;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh
index 8230cba7c94b1..b2d1b7b67e0cf 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh
@@ -851,43 +851,41 @@ struct StateTableDriver
        *
        *   https://github.com/harfbuzz/harfbuzz/issues/2860
        */
-      const EntryT *wouldbe_entry;
-      bool safe_to_break =
-        /* 1. */
-        !c->is_actionable (this, entry)
-      &&
-        /* 2. */
-        (
-          /* 2a. */
-          state == StateTableT::STATE_START_OF_TEXT
-        ||
-          /* 2b. */
-          (
-            (entry.flags & context_t::DontAdvance) &&
-            next_state == StateTableT::STATE_START_OF_TEXT
-          )
-        ||
+
+      const auto is_safe_to_break_extra = [&]()
+      {
           /* 2c. */
-          (
-            wouldbe_entry = &machine.get_entry (StateTableT::STATE_START_OF_TEXT, klass)
-          ,
-            /* 2c'. */
-            !c->is_actionable (this, *wouldbe_entry)
-          &&
-            /* 2c". */
-            (
-              next_state == machine.new_state (wouldbe_entry->newState)
-            &&
-              (entry.flags & context_t::DontAdvance) == (wouldbe_entry->flags & context_t::DontAdvance)
-            )
-          )
-        )
-      &&
-        /* 3. */
-        !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT))
-      ;
-
-      if (!safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len)
+          const auto wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
+
+          /* 2c'. */
+          if (c->is_actionable (this, wouldbe_entry))
+              return false;
+
+          /* 2c". */
+          return next_state == machine.new_state(wouldbe_entry.newState)
+              && (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance);
+      };
+
+      const auto is_safe_to_break = [&]()
+      {
+          /* 1. */
+          if (c->is_actionable (this, entry))
+              return false;
+
+          /* 2. */
+          // This one is meh, I know...
+          const auto ok =
+                 state == StateTableT::STATE_START_OF_TEXT
+              || ((entry.flags & context_t::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT)
+              || is_safe_to_break_extra();
+          if (!ok)
+              return false;
+
+          /* 3. */
+          return !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT));
+      };
+
+      if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len)
         buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
 
       c->transition (this, entry);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh
index cb53128349888..5c49d1f0562c0 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh
@@ -111,13 +111,13 @@ struct TrackData
         break;
       }
     }
-    if (!trackTableEntry) return 0.;
+    if (!trackTableEntry) return 0;
 
     /*
      * Choose size.
      */
     unsigned int sizes = nSizes;
-    if (!sizes) return 0.;
+    if (!sizes) return 0;
     if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
 
     hb_array_t size_table ((base+sizeTable).arrayZ, sizes);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc
index b0afbdfbb0453..fc5834c7ca1b1 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc
@@ -55,7 +55,13 @@ AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *p
                                                        buffer (buffer_),
                                                        sanitizer (),
                                                        ankr_table (&Null (AAT::ankr)),
-                                                       gdef_table (face->table.GDEF->table),
+                                                       gdef_table (
+#ifndef HB_NO_OT_LAYOUT
+                                                         face->table.GDEF->table
+#else
+                                                         &Null (GDEF)
+#endif
+                                                       ),
                                                        lookup_index (0)
 {
   sanitizer.init (blob);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-algs.hh b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh
index e2b970f968f14..b2b7c2567392f 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-algs.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh
@@ -87,6 +87,19 @@ static inline constexpr uint16_t hb_uint16_swap (uint16_t v)
 static inline constexpr uint32_t hb_uint32_swap (uint32_t v)
 { return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
 
+#ifndef HB_FAST_INT_ACCESS
+#if defined(__OPTIMIZE__) && \
+    defined(__BYTE_ORDER) && \
+    (__BYTE_ORDER == __BIG_ENDIAN || \
+     (__BYTE_ORDER == __LITTLE_ENDIAN && \
+      hb_has_builtin(__builtin_bswap16) && \
+      hb_has_builtin(__builtin_bswap32)))
+#define HB_FAST_INT_ACCESS 1
+#else
+#define HB_FAST_INT_ACCESS 0
+#endif
+#endif
+
 template 
 struct BEInt;
 template 
@@ -101,21 +114,25 @@ struct BEInt
 template 
 struct BEInt
 {
+  struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
+
   public:
   BEInt () = default;
-  constexpr BEInt (Type V) : v {uint8_t ((V >>  8) & 0xFF),
-                                uint8_t ((V      ) & 0xFF)} {}
 
-  struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
-  constexpr operator Type () const
-  {
-#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
-    defined(__BYTE_ORDER) && \
-    (__BYTE_ORDER == __BIG_ENDIAN || \
-     (__BYTE_ORDER == __LITTLE_ENDIAN && \
-      hb_has_builtin(__builtin_bswap16)))
-    /* Spoon-feed the compiler a big-endian integer with alignment 1.
-     * https://github.com/harfbuzz/harfbuzz/pull/1398 */
+  BEInt (Type V)
+#if HB_FAST_INT_ACCESS
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+  { ((packed_uint16_t *) v)->v = __builtin_bswap16 (V); }
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+  { ((packed_uint16_t *) v)->v = V; }
+#endif
+#else
+    : v {uint8_t ((V >>  8) & 0xFF),
+         uint8_t ((V      ) & 0xFF)} {}
+#endif
+
+  constexpr operator Type () const {
+#if HB_FAST_INT_ACCESS
 #if __BYTE_ORDER == __LITTLE_ENDIAN
     return __builtin_bswap16 (((packed_uint16_t *) v)->v);
 #else /* __BYTE_ORDER == __BIG_ENDIAN */
@@ -146,22 +163,27 @@ struct BEInt
 template 
 struct BEInt
 {
+  struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
+
   public:
   BEInt () = default;
-  constexpr BEInt (Type V) : v {uint8_t ((V >> 24) & 0xFF),
-                                uint8_t ((V >> 16) & 0xFF),
-                                uint8_t ((V >>  8) & 0xFF),
-                                uint8_t ((V      ) & 0xFF)} {}
 
-  struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
+  BEInt (Type V)
+#if HB_FAST_INT_ACCESS
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+  { ((packed_uint32_t *) v)->v = __builtin_bswap32 (V); }
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+  { ((packed_uint32_t *) v)->v = V; }
+#endif
+#else
+    : v {uint8_t ((V >> 24) & 0xFF),
+         uint8_t ((V >> 16) & 0xFF),
+         uint8_t ((V >>  8) & 0xFF),
+         uint8_t ((V      ) & 0xFF)} {}
+#endif
+
   constexpr operator Type () const {
-#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
-    defined(__BYTE_ORDER) && \
-    (__BYTE_ORDER == __BIG_ENDIAN || \
-     (__BYTE_ORDER == __LITTLE_ENDIAN && \
-      hb_has_builtin(__builtin_bswap32)))
-    /* Spoon-feed the compiler a big-endian integer with alignment 1.
-     * https://github.com/harfbuzz/harfbuzz/pull/1398 */
+#if HB_FAST_INT_ACCESS
 #if __BYTE_ORDER == __LITTLE_ENDIAN
     return __builtin_bswap32 (((packed_uint32_t *) v)->v);
 #else /* __BYTE_ORDER == __BIG_ENDIAN */
@@ -231,12 +253,123 @@ struct
 }
 HB_FUNCOBJ (hb_bool);
 
+
+/* The MIT License
+
+   Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
+
+   Permission is hereby granted, free of charge, to any person
+   obtaining a copy of this software and associated documentation
+   files (the "Software"), to deal in the Software without
+   restriction, including without limitation the rights to use, copy,
+   modify, merge, publish, distribute, sublicense, and/or sell copies
+   of the Software, and to permit persons to whom the Software is
+   furnished to do so, subject to the following conditions:
+
+   The above copyright notice and this permission notice shall be
+   included in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+   SOFTWARE.
+*/
+
+
+// Compression function for Merkle-Damgard construction.
+// This function is generated using the framework provided.
+#define mix(h) (                                        \
+                        (void) ((h) ^= (h) >> 23),              \
+                        (void) ((h) *= 0x2127599bf4325c37ULL),  \
+                        (h) ^= (h) >> 47)
+
+static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed)
+{
+        struct __attribute__((packed)) packed_uint64_t { uint64_t v; };
+        const uint64_t    m = 0x880355f21e6d1965ULL;
+        const packed_uint64_t *pos = (const packed_uint64_t *)buf;
+        const packed_uint64_t *end = pos + (len / 8);
+        const unsigned char *pos2;
+        uint64_t h = seed ^ (len * m);
+        uint64_t v;
+
+#ifndef HB_OPTIMIZE_SIZE
+        if (((uintptr_t) pos & 7) == 0)
+        {
+          while (pos != end)
+          {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+            v  = * (const uint64_t *) (pos++);
+#pragma GCC diagnostic pop
+            h ^= mix(v);
+            h *= m;
+          }
+        }
+        else
+#endif
+        {
+          while (pos != end)
+          {
+            v  = pos++->v;
+            h ^= mix(v);
+            h *= m;
+          }
+        }
+
+        pos2 = (const unsigned char*)pos;
+        v = 0;
+
+        switch (len & 7) {
+        case 7: v ^= (uint64_t)pos2[6] << 48; HB_FALLTHROUGH;
+        case 6: v ^= (uint64_t)pos2[5] << 40; HB_FALLTHROUGH;
+        case 5: v ^= (uint64_t)pos2[4] << 32; HB_FALLTHROUGH;
+        case 4: v ^= (uint64_t)pos2[3] << 24; HB_FALLTHROUGH;
+        case 3: v ^= (uint64_t)pos2[2] << 16; HB_FALLTHROUGH;
+        case 2: v ^= (uint64_t)pos2[1] <<  8; HB_FALLTHROUGH;
+        case 1: v ^= (uint64_t)pos2[0];
+                h ^= mix(v);
+                h *= m;
+        }
+
+        return mix(h);
+}
+
+static inline uint32_t fasthash32(const void *buf, size_t len, uint32_t seed)
+{
+        // the following trick converts the 64-bit hashcode to Fermat
+        // residue, which shall retain information from both the higher
+        // and lower parts of hashcode.
+        uint64_t h = fasthash64(buf, len, seed);
+        return h - (h >> 32);
+}
+
 struct
 {
   private:
 
   template  constexpr auto
-  impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
+  impl (const T& v, hb_priority<2>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
+
+  // Horrible: std:hash() of integers seems to be identity in gcc / clang?!
+  // https://github.com/harfbuzz/harfbuzz/pull/4228
+  //
+  // For performance characteristics see:
+  // https://github.com/harfbuzz/harfbuzz/pull/4228#issuecomment-1565079537
+  template ::value && sizeof (T) <= sizeof (uint32_t))> constexpr auto
+  impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (uint32_t) v * 2654435761u /* Knuh's multiplicative hash */)
+  template ::value && sizeof (T) > sizeof (uint32_t))> constexpr auto
+  impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (uint32_t) (v ^ (v >> 32)) * 2654435761u /* Knuth's multiplicative hash */)
+
+  template ::value)> constexpr auto
+  impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, fasthash32 (std::addressof (v), sizeof (T), 0xf437ffe6))
 
   template  constexpr auto
   impl (const T& v, hb_priority<0>) const HB_RETURN (uint32_t, std::hash>{} (hb_deref (v)))
@@ -551,6 +684,8 @@ struct hb_pair_t
 template  static inline hb_pair_t
 hb_pair (T1&& a, T2&& b) { return hb_pair_t (a, b); }
 
+typedef hb_pair_t hb_codepoint_pair_t;
+
 struct
 {
   template  constexpr typename Pair::first_t
@@ -626,8 +761,10 @@ hb_popcount (T v)
 
   if (sizeof (T) == 8)
   {
-    unsigned int shift = 32;
-    return hb_popcount ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
+    uint64_t y = (uint64_t) v;
+    y -= ((y >> 1) & 0x5555555555555555ull);
+    y = (y & 0x3333333333333333ull) + (y >> 2 & 0x3333333333333333ull);
+    return ((y + (y >> 4)) & 0xf0f0f0f0f0f0f0full) * 0x101010101010101ull >> 56;
   }
 
   if (sizeof (T) == 16)
@@ -851,7 +988,7 @@ static inline void *
 hb_memset (void *s, int c, unsigned int n)
 {
   /* It's illegal to pass NULL to memset(), even if n is zero. */
-  if (unlikely (!n)) return 0;
+  if (unlikely (!n)) return s;
   return memset (s, c, n);
 }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-array.hh b/src/java.desktop/share/native/libharfbuzz/hb-array.hh
index 08b25987061ac..439f18259cf52 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-array.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-array.hh
@@ -75,11 +75,25 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&>
    */
   typedef Type& __item_t__;
   static constexpr bool is_random_access_iterator = true;
+  static constexpr bool has_fast_len = true;
+  Type& __item__ () const
+  {
+    if (unlikely (!length)) return CrapOrNull (Type);
+    return *arrayZ;
+  }
   Type& __item_at__ (unsigned i) const
   {
     if (unlikely (i >= length)) return CrapOrNull (Type);
     return arrayZ[i];
   }
+  void __next__ ()
+  {
+    if (unlikely (!length))
+      return;
+    length--;
+    backwards_length++;
+    arrayZ++;
+  }
   void __forward__ (unsigned n)
   {
     if (unlikely (n > length))
@@ -88,6 +102,14 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&>
     backwards_length += n;
     arrayZ += n;
   }
+  void __prev__ ()
+  {
+    if (unlikely (!backwards_length))
+      return;
+    length++;
+    backwards_length--;
+    arrayZ--;
+  }
   void __rewind__ (unsigned n)
   {
     if (unlikely (n > backwards_length))
@@ -122,9 +144,14 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&>
 
   uint32_t hash () const
   {
-    uint32_t current = 0;
+    // FNV-1a hash function
+    // https://github.com/harfbuzz/harfbuzz/pull/4228
+    uint32_t current = /*cbf29ce4*/0x84222325;
     for (auto &v : *this)
-      current = current * 31 + hb_hash (v);
+    {
+      current = current ^ hb_hash (v);
+      current = current * 16777619;
+    }
     return current;
   }
 
@@ -322,6 +349,7 @@ struct hb_sorted_array_t :
   HB_ITER_USING (iter_base_t);
   static constexpr bool is_random_access_iterator = true;
   static constexpr bool is_sorted_iterator = true;
+  static constexpr bool has_fast_len = true;
 
   hb_sorted_array_t () = default;
   hb_sorted_array_t (const hb_sorted_array_t&) = default;
@@ -449,41 +477,21 @@ inline bool hb_array_t::operator == (const hb_array_t
 inline uint32_t hb_array_t::hash () const
 {
-  uint32_t current = 0;
-  unsigned i = 0;
-
-#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
-    ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__))
-  struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
-  for (; i + 4 <= this->length; i += 4)
-    current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v);
-#endif
-
-  for (; i < this->length; i++)
-    current = current * 31 + hb_hash (this->arrayZ[i]);
-  return current;
+  // https://github.com/harfbuzz/harfbuzz/pull/4228
+  return fasthash32(arrayZ, length, 0xf437ffe6 /* magic? */);
 }
 
 template <>
 inline uint32_t hb_array_t::hash () const
 {
-  uint32_t current = 0;
-  unsigned i = 0;
-
-#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
-    ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__))
-  struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
-  for (; i + 4 <= this->length; i += 4)
-    current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v);
-#endif
-
-  for (; i < this->length; i++)
-    current = current * 31 + hb_hash (this->arrayZ[i]);
-  return current;
+  // https://github.com/harfbuzz/harfbuzz/pull/4228
+  return fasthash32(arrayZ, length, 0xf437ffe6 /* magic? */);
 }
+#endif
 
 
 typedef hb_array_t hb_bytes_t;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh
index 57e94761e800e..459d82e0f2e78 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh
@@ -204,6 +204,7 @@ struct hb_atomic_ptr_t
 
   hb_atomic_ptr_t () = default;
   constexpr hb_atomic_ptr_t (T* v) : v (v) {}
+  hb_atomic_ptr_t (const hb_atomic_ptr_t &other) = delete;
 
   void init (T* v_ = nullptr) { set_relaxed (v_); }
   void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh b/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh
index 9edefd9710657..f541472544acd 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh
@@ -39,10 +39,10 @@ struct hb_bimap_t
     back_map.reset ();
   }
 
-  void resize (unsigned pop)
+  void alloc (unsigned pop)
   {
-    forw_map.resize (pop);
-    back_map.resize (pop);
+    forw_map.alloc (pop);
+    back_map.alloc (pop);
   }
 
   bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
@@ -83,7 +83,6 @@ struct hb_bimap_t
 
   unsigned int get_population () const { return forw_map.get_population (); }
 
-
   protected:
   hb_map_t  forw_map;
   hb_map_t  back_map;
@@ -94,9 +93,31 @@ struct hb_bimap_t
   auto iter () const HB_AUTO_RETURN (+ forw_map.iter())
 };
 
-/* Inremental bimap: only lhs is given, rhs is incrementally assigned */
-struct hb_inc_bimap_t : hb_bimap_t
+/* Incremental bimap: only lhs is given, rhs is incrementally assigned */
+struct hb_inc_bimap_t
 {
+  bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
+
+  unsigned int get_population () const { return forw_map.get_population (); }
+
+  void reset ()
+  {
+    forw_map.reset ();
+    back_map.reset ();
+  }
+
+  void alloc (unsigned pop)
+  {
+    forw_map.alloc (pop);
+    back_map.alloc (pop);
+  }
+
+  void clear ()
+  {
+    forw_map.clear ();
+    back_map.resize (0);
+  }
+
   /* Add a mapping from lhs to rhs with a unique value if lhs is unknown.
    * Return the rhs value as the result.
    */
@@ -105,32 +126,42 @@ struct hb_inc_bimap_t : hb_bimap_t
     hb_codepoint_t  rhs = forw_map[lhs];
     if (rhs == HB_MAP_VALUE_INVALID)
     {
-      rhs = next_value++;
-      set (lhs, rhs);
+      rhs = back_map.length;
+      forw_map.set (lhs, rhs);
+      back_map.push (lhs);
     }
     return rhs;
   }
 
   hb_codepoint_t skip ()
-  { return next_value++; }
+  {
+    hb_codepoint_t start = back_map.length;
+    back_map.push (HB_MAP_VALUE_INVALID);
+    return start;
+  }
 
   hb_codepoint_t skip (unsigned count)
-  { return next_value += count; }
+  {
+    hb_codepoint_t start = back_map.length;
+    back_map.alloc (back_map.length + count);
+    for (unsigned i = 0; i < count; i++)
+      back_map.push (HB_MAP_VALUE_INVALID);
+    return start;
+  }
 
   hb_codepoint_t get_next_value () const
-  { return next_value; }
+  { return back_map.length; }
 
   void add_set (const hb_set_t *set)
   {
-    hb_codepoint_t i = HB_SET_VALUE_INVALID;
-    while (hb_set_next (set, &i)) add (i);
+    for (auto i : *set) add (i);
   }
 
   /* Create an identity map. */
   bool identity (unsigned int size)
   {
     clear ();
-    for (hb_codepoint_t i = 0; i < size; i++) set (i, i);
+    for (hb_codepoint_t i = 0; i < size; i++) add (i);
     return !in_error ();
   }
 
@@ -145,20 +176,30 @@ struct hb_inc_bimap_t : hb_bimap_t
   {
     hb_codepoint_t  count = get_population ();
     hb_vector_t  work;
-    work.resize (count);
+    if (unlikely (!work.resize (count, false))) return;
 
     for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
-      work[rhs] = back_map[rhs];
+      work.arrayZ[rhs] = back_map[rhs];
 
     work.qsort (cmp_id);
 
     clear ();
     for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
-      set (work[rhs], rhs);
+      add (work.arrayZ[rhs]);
   }
 
+  hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }
+  hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map[rhs]; }
+
+  hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); }
+  bool has (hb_codepoint_t lhs) const { return forw_map.has (lhs); }
+
   protected:
-  unsigned int next_value = 0;
+  hb_map_t forw_map;
+  hb_vector_t back_map;
+
+  public:
+  auto keys () const HB_AUTO_RETURN (+ back_map.iter())
 };
 
 #endif /* HB_BIMAP_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh
index 81e2a4997bd63..404a19ce557f8 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh
@@ -89,14 +89,18 @@ struct hb_vector_size_t
 
 struct hb_bit_page_t
 {
-  void init0 () { v.init0 (); }
-  void init1 () { v.init1 (); }
+  void init0 () { v.init0 (); population = 0; }
+  void init1 () { v.init1 (); population = PAGE_BITS; }
+
+  void dirty () { population = UINT_MAX; }
 
   static inline constexpr unsigned len ()
   { return ARRAY_LENGTH_CONST (v); }
 
+  operator bool () const { return !is_empty (); }
   bool is_empty () const
   {
+    if (has_population ()) return !population;
     return
     + hb_iter (v)
     | hb_none
@@ -104,14 +108,11 @@ struct hb_bit_page_t
   }
   uint32_t hash () const
   {
-    return
-    + hb_iter (v)
-    | hb_reduce ([] (uint32_t h, const elt_t &_) { return h * 31 + hb_hash (_); }, (uint32_t) 0u)
-    ;
+    return hb_bytes_t ((const char *) &v, sizeof (v)).hash ();
   }
 
-  void add (hb_codepoint_t g) { elt (g) |= mask (g); }
-  void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
+  void add (hb_codepoint_t g) { elt (g) |= mask (g); dirty (); }
+  void del (hb_codepoint_t g) { elt (g) &= ~mask (g); dirty (); }
   void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); }
   bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
 
@@ -123,20 +124,21 @@ struct hb_bit_page_t
       *la |= (mask (b) << 1) - mask(a);
     else
     {
-      *la |= ~(mask (a) - 1);
+      *la |= ~(mask (a) - 1llu);
       la++;
 
       hb_memset (la, 0xff, (char *) lb - (char *) la);
 
-      *lb |= ((mask (b) << 1) - 1);
+      *lb |= ((mask (b) << 1) - 1llu);
     }
+    dirty ();
   }
   void del_range (hb_codepoint_t a, hb_codepoint_t b)
   {
     elt_t *la = &elt (a);
     elt_t *lb = &elt (b);
     if (la == lb)
-      *la &= ~((mask (b) << 1) - mask(a));
+      *la &= ~((mask (b) << 1llu) - mask(a));
     else
     {
       *la &= mask (a) - 1;
@@ -144,8 +146,9 @@ struct hb_bit_page_t
 
       hb_memset (la, 0, (char *) lb - (char *) la);
 
-      *lb &= ~((mask (b) << 1) - 1);
+      *lb &= ~((mask (b) << 1) - 1llu);
     }
+    dirty ();
   }
   void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
   { if (v) add_range (a, b); else del_range (a, b); }
@@ -216,6 +219,7 @@ struct hb_bit_page_t
     return count;
   }
 
+  bool operator == (const hb_bit_page_t &other) const { return is_equal (other); }
   bool is_equal (const hb_bit_page_t &other) const
   {
     for (unsigned i = 0; i < len (); i++)
@@ -223,20 +227,28 @@ struct hb_bit_page_t
         return false;
     return true;
   }
+  bool operator <= (const hb_bit_page_t &larger_page) const { return is_subset (larger_page); }
   bool is_subset (const hb_bit_page_t &larger_page) const
   {
+    if (has_population () && larger_page.has_population () &&
+        population > larger_page.population)
+      return false;
+
     for (unsigned i = 0; i < len (); i++)
       if (~larger_page.v[i] & v[i])
         return false;
     return true;
   }
 
+  bool has_population () const { return population != UINT_MAX; }
   unsigned int get_population () const
   {
-    return
+    if (has_population ()) return population;
+    population =
     + hb_iter (v)
     | hb_reduce ([] (unsigned pop, const elt_t &_) { return pop + hb_popcount (_); }, 0u)
     ;
+    return population;
   }
 
   bool next (hb_codepoint_t *codepoint) const
@@ -332,9 +344,9 @@ struct hb_bit_page_t
   const elt_t& elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
   static constexpr elt_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); }
 
+  mutable unsigned population;
   vector_t v;
 };
-static_assert (hb_bit_page_t::PAGE_BITS == sizeof (hb_bit_page_t) * 8, "");
 
 
 #endif /* HB_BIT_PAGE_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh
index bf5a0b446defd..2e335549e2603 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh
@@ -136,7 +136,7 @@ struct hb_bit_set_invertible_t
   /* Sink interface. */
   hb_bit_set_invertible_t& operator << (hb_codepoint_t v)
   { add (v); return *this; }
-  hb_bit_set_invertible_t& operator << (const hb_pair_t& range)
+  hb_bit_set_invertible_t& operator << (const hb_codepoint_pair_t& range)
   { add_range (range.first, range.second); return *this; }
 
   bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
@@ -162,7 +162,7 @@ struct hb_bit_set_invertible_t
       auto it1 = iter ();
       auto it2 = other.iter ();
       return hb_all (+ hb_zip (it1, it2)
-                     | hb_map ([](hb_pair_t _) { return _.first == _.second; }));
+                     | hb_map ([](hb_codepoint_pair_t _) { return _.first == _.second; }));
     }
   }
 
@@ -345,6 +345,7 @@ struct hb_bit_set_invertible_t
   struct iter_t : hb_iter_with_fallback_t
   {
     static constexpr bool is_sorted_iterator = true;
+    static constexpr bool has_fast_len = true;
     iter_t (const hb_bit_set_invertible_t &s_ = Null (hb_bit_set_invertible_t),
             bool init = true) : s (&s_), v (INVALID), l(0)
     {
@@ -363,7 +364,7 @@ struct hb_bit_set_invertible_t
     unsigned __len__ () const { return l; }
     iter_t end () const { return iter_t (*s, false); }
     bool operator != (const iter_t& o) const
-    { return s != o.s || v != o.v; }
+    { return v != o.v || s != o.s; }
 
     protected:
     const hb_bit_set_invertible_t *s;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh
index 31ee52f60964c..b900711a33a97 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh
@@ -30,7 +30,6 @@
 
 #include "hb.hh"
 #include "hb-bit-page.hh"
-#include "hb-machinery.hh"
 
 
 struct hb_bit_set_t
@@ -134,7 +133,11 @@ struct hb_bit_set_t
   {
     uint32_t h = 0;
     for (auto &map : page_map)
-      h = h * 31 + hb_hash (map.major) + hb_hash (pages[map.index]);
+    {
+      auto &page = pages.arrayZ[map.index];
+      if (unlikely (page.is_empty ())) continue;
+      h = h * 31 + hb_hash (map.major) + hb_hash (page);
+    }
     return h;
   }
 
@@ -179,6 +182,16 @@ struct hb_bit_set_t
     return true;
   }
 
+  /* Duplicated here from hb-machinery.hh to avoid including it. */
+  template
+  static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int offset)
+  {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+    return * reinterpret_cast ((const char *) P + offset);
+#pragma GCC diagnostic pop
+  }
+
   template 
   void set_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
   {
@@ -342,7 +355,7 @@ struct hb_bit_set_t
   /* Sink interface. */
   hb_bit_set_t& operator << (hb_codepoint_t v)
   { add (v); return *this; }
-  hb_bit_set_t& operator << (const hb_pair_t& range)
+  hb_bit_set_t& operator << (const hb_codepoint_pair_t& range)
   { add_range (range.first, range.second); return *this; }
 
   bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
@@ -402,7 +415,6 @@ struct hb_bit_set_t
       uint32_t spm = page_map[spi].major;
       uint32_t lpm = larger_set.page_map[lpi].major;
       auto sp = page_at (spi);
-      auto lp = larger_set.page_at (lpi);
 
       if (spm < lpm && !sp.is_empty ())
         return false;
@@ -410,6 +422,7 @@ struct hb_bit_set_t
       if (lpm < spm)
         continue;
 
+      auto lp = larger_set.page_at (lpi);
       if (!sp.is_subset (lp))
         return false;
 
@@ -549,6 +562,7 @@ struct hb_bit_set_t
         count--;
         page_map.arrayZ[count] = page_map.arrayZ[a];
         page_at (count).v = op (page_at (a).v, other.page_at (b).v);
+        page_at (count).dirty ();
       }
       else if (page_map.arrayZ[a - 1].major > other.page_map.arrayZ[b - 1].major)
       {
@@ -567,7 +581,7 @@ struct hb_bit_set_t
           count--;
           page_map.arrayZ[count].major = other.page_map.arrayZ[b].major;
           page_map.arrayZ[count].index = next_page++;
-          page_at (count).v = other.page_at (b).v;
+          page_at (count) = other.page_at (b);
         }
       }
     }
@@ -585,7 +599,7 @@ struct hb_bit_set_t
         count--;
         page_map.arrayZ[count].major = other.page_map.arrayZ[b].major;
         page_map.arrayZ[count].index = next_page++;
-        page_at (count).v = other.page_at (b).v;
+        page_at (count) = other.page_at (b);
       }
     assert (!count);
     resize (newCount);
@@ -623,6 +637,7 @@ struct hb_bit_set_t
         *codepoint = INVALID;
         return false;
       }
+      last_page_lookup = i;
     }
 
     const auto* pages_array = pages.arrayZ;
@@ -632,7 +647,6 @@ struct hb_bit_set_t
       if (pages_array[current.index].next (codepoint))
       {
         *codepoint += current.major * page_t::PAGE_BITS;
-        last_page_lookup = i;
         return true;
       }
       i++;
@@ -649,7 +663,6 @@ struct hb_bit_set_t
         return true;
       }
     }
-    last_page_lookup = 0;
     *codepoint = INVALID;
     return false;
   }
@@ -863,6 +876,7 @@ struct hb_bit_set_t
   struct iter_t : hb_iter_with_fallback_t
   {
     static constexpr bool is_sorted_iterator = true;
+    static constexpr bool has_fast_len = true;
     iter_t (const hb_bit_set_t &s_ = Null (hb_bit_set_t),
             bool init = true) : s (&s_), v (INVALID), l(0)
     {
@@ -899,7 +913,7 @@ struct hb_bit_set_t
 
     /* The extra page_map length is necessary; can't just rely on vector here,
      * since the next check would be tricked because a null page also has
-     * major==0, which we can't distinguish from an actualy major==0 page... */
+     * major==0, which we can't distinguish from an actually major==0 page... */
     unsigned i = last_page_lookup;
     if (likely (i < page_map.length))
     {
@@ -921,7 +935,7 @@ struct hb_bit_set_t
       memmove (page_map.arrayZ + i + 1,
                page_map.arrayZ + i,
                (page_map.length - 1 - i) * page_map.item_size);
-      page_map[i] = map;
+      page_map.arrayZ[i] = map;
     }
 
     last_page_lookup = i;
@@ -933,7 +947,7 @@ struct hb_bit_set_t
 
     /* The extra page_map length is necessary; can't just rely on vector here,
      * since the next check would be tricked because a null page also has
-     * major==0, which we can't distinguish from an actualy major==0 page... */
+     * major==0, which we can't distinguish from an actually major==0 page... */
     unsigned i = last_page_lookup;
     if (likely (i < page_map.length))
     {
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-json.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-json.hh
index 7b9fc557f737d..2a90cbfe3eaef 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-json.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-json.hh
@@ -32,7 +32,7 @@
 #include "hb.hh"
 
 
-#line 33 "hb-buffer-deserialize-json.hh"
+#line 36 "hb-buffer-deserialize-json.hh"
 static const unsigned char _deserialize_json_trans_keys[] = {
         0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u,
         48u, 57u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u,
@@ -555,12 +555,12 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
 
-#line 552 "hb-buffer-deserialize-json.hh"
+#line 559 "hb-buffer-deserialize-json.hh"
         {
         cs = deserialize_json_start;
         }
 
-#line 555 "hb-buffer-deserialize-json.hh"
+#line 564 "hb-buffer-deserialize-json.hh"
         {
         int _slen;
         int _trans;
@@ -772,7 +772,7 @@ _resume:
         *end_ptr = p;
 }
         break;
-#line 733 "hb-buffer-deserialize-json.hh"
+#line 776 "hb-buffer-deserialize-json.hh"
         }
 
 _again:
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-glyphs.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-glyphs.hh
index cf9c281e86ec5..8e526ce4e2a02 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-glyphs.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-glyphs.hh
@@ -32,7 +32,7 @@
 #include "hb.hh"
 
 
-#line 33 "hb-buffer-deserialize-text-glyphs.hh"
+#line 36 "hb-buffer-deserialize-text-glyphs.hh"
 static const unsigned char _deserialize_text_glyphs_trans_keys[] = {
         0u, 0u, 48u, 57u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u,
         48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u,
@@ -349,12 +349,12 @@ _hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
 
-#line 346 "hb-buffer-deserialize-text-glyphs.hh"
+#line 353 "hb-buffer-deserialize-text-glyphs.hh"
         {
         cs = deserialize_text_glyphs_start;
         }
 
-#line 349 "hb-buffer-deserialize-text-glyphs.hh"
+#line 358 "hb-buffer-deserialize-text-glyphs.hh"
         {
         int _slen;
         int _trans;
@@ -550,7 +550,7 @@ _resume:
         *end_ptr = p;
 }
         break;
-#line 516 "hb-buffer-deserialize-text-glyphs.hh"
+#line 554 "hb-buffer-deserialize-text-glyphs.hh"
         }
 
 _again:
@@ -667,7 +667,7 @@ _again:
         *end_ptr = p;
 }
         break;
-#line 616 "hb-buffer-deserialize-text-glyphs.hh"
+#line 671 "hb-buffer-deserialize-text-glyphs.hh"
         }
         }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh
index f0c9465453327..6a1706ccb725f 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh
@@ -32,7 +32,7 @@
 #include "hb.hh"
 
 
-#line 33 "hb-buffer-deserialize-text-unicode.hh"
+#line 36 "hb-buffer-deserialize-text-unicode.hh"
 static const unsigned char _deserialize_text_unicode_trans_keys[] = {
         0u, 0u, 9u, 117u, 43u, 102u, 48u, 102u, 48u, 57u, 9u, 124u, 9u, 124u, 9u, 124u,
         9u, 124u, 0
@@ -197,12 +197,12 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
   hb_glyph_info_t info = {0};
   const hb_glyph_position_t pos = {0};
 
-#line 194 "hb-buffer-deserialize-text-unicode.hh"
+#line 201 "hb-buffer-deserialize-text-unicode.hh"
         {
         cs = deserialize_text_unicode_start;
         }
 
-#line 197 "hb-buffer-deserialize-text-unicode.hh"
+#line 206 "hb-buffer-deserialize-text-unicode.hh"
         {
         int _slen;
         int _trans;
@@ -269,7 +269,7 @@ _resume:
         *end_ptr = p;
 }
         break;
-#line 256 "hb-buffer-deserialize-text-unicode.hh"
+#line 273 "hb-buffer-deserialize-text-unicode.hh"
         }
 
 _again:
@@ -307,7 +307,7 @@ _again:
         *end_ptr = p;
 }
         break;
-#line 289 "hb-buffer-deserialize-text-unicode.hh"
+#line 311 "hb-buffer-deserialize-text-unicode.hh"
         }
         }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc
index f2fef3137e529..3bdea30ed36c7 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc
@@ -162,14 +162,8 @@ buffer_verify_unsafe_to_break (hb_buffer_t  *buffer,
     hb_buffer_set_flags (fragment, flags);
 
     hb_buffer_append (fragment, text_buffer, text_start, text_end);
-    if (!hb_shape_full (font, fragment, features, num_features, shapers))
-    {
-      buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
-      hb_buffer_destroy (reconstruction);
-      hb_buffer_destroy (fragment);
-      return false;
-    }
-    else if (!fragment->successful || fragment->shaping_failed)
+    if (!hb_shape_full (font, fragment, features, num_features, shapers) ||
+        fragment->successful || fragment->shaping_failed)
     {
       hb_buffer_destroy (reconstruction);
       hb_buffer_destroy (fragment);
@@ -185,15 +179,18 @@ buffer_verify_unsafe_to_break (hb_buffer_t  *buffer,
   }
 
   bool ret = true;
-  hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
-  if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+  if (likely (reconstruction->successful))
   {
-    buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed.");
-    ret = false;
+    hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
+    if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+    {
+      buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed.");
+      ret = false;
 
-    /* Return the reconstructed result instead so it can be inspected. */
-    hb_buffer_set_length (buffer, 0);
-    hb_buffer_append (buffer, reconstruction, 0, -1);
+      /* Return the reconstructed result instead so it can be inspected. */
+      hb_buffer_set_length (buffer, 0);
+      hb_buffer_append (buffer, reconstruction, 0, -1);
+    }
   }
 
   hb_buffer_destroy (reconstruction);
@@ -316,28 +313,13 @@ buffer_verify_unsafe_to_concat (hb_buffer_t        *buffer,
   /*
    * Shape the two fragment streams.
    */
-  if (!hb_shape_full (font, fragments[0], features, num_features, shapers))
-  {
-    buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
-    ret = false;
-    goto out;
-  }
-  else if (!fragments[0]->successful || fragments[0]->shaping_failed)
-  {
-    ret = true;
-    goto out;
-  }
-  if (!hb_shape_full (font, fragments[1], features, num_features, shapers))
-  {
-    buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
-    ret = false;
+  if (!hb_shape_full (font, fragments[0], features, num_features, shapers) ||
+      !fragments[0]->successful || fragments[0]->shaping_failed)
     goto out;
-  }
-  else if (!fragments[1]->successful || fragments[1]->shaping_failed)
-  {
-    ret = true;
+
+  if (!hb_shape_full (font, fragments[1], features, num_features, shapers) ||
+      !fragments[1]->successful || fragments[1]->shaping_failed)
     goto out;
-  }
 
   if (!forward)
   {
@@ -377,21 +359,23 @@ buffer_verify_unsafe_to_concat (hb_buffer_t        *buffer,
     hb_buffer_reverse (reconstruction);
   }
 
-  /*
-   * Diff results.
-   */
-  diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
-  if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+  if (likely (reconstruction->successful))
   {
-    buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed.");
-    ret = false;
+    /*
+     * Diff results.
+     */
+    diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
+    if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+    {
+      buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed.");
+      ret = false;
 
-    /* Return the reconstructed result instead so it can be inspected. */
-    hb_buffer_set_length (buffer, 0);
-    hb_buffer_append (buffer, reconstruction, 0, -1);
+      /* Return the reconstructed result instead so it can be inspected. */
+      hb_buffer_set_length (buffer, 0);
+      hb_buffer_append (buffer, reconstruction, 0, -1);
+    }
   }
 
-
 out:
   hb_buffer_destroy (reconstruction);
   hb_buffer_destroy (fragments[0]);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc
index 69d8c961930a9..5f9329e07edf7 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc
@@ -268,7 +268,7 @@ hb_buffer_t::similar (const hb_buffer_t &src)
   unicode = hb_unicode_funcs_reference (src.unicode);
   flags = src.flags;
   cluster_level = src.cluster_level;
-  replacement = src.invisible;
+  replacement = src.replacement;
   invisible = src.invisible;
   not_found = src.not_found;
 }
@@ -499,12 +499,12 @@ hb_buffer_t::set_masks (hb_mask_t    value,
                         unsigned int cluster_start,
                         unsigned int cluster_end)
 {
-  hb_mask_t not_mask = ~mask;
-  value &= mask;
-
   if (!mask)
     return;
 
+  hb_mask_t not_mask = ~mask;
+  value &= mask;
+
   unsigned int count = len;
   for (unsigned int i = 0; i < count; i++)
     if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
@@ -1327,7 +1327,7 @@ hb_buffer_get_invisible_glyph (const hb_buffer_t *buffer)
  * Sets the #hb_codepoint_t that replaces characters not found in
  * the font during shaping.
  *
- * The not-found glyph defaults to zero, sometimes knows as the
+ * The not-found glyph defaults to zero, sometimes known as the
  * ".notdef" glyph.  This API allows for differentiating the two.
  *
  * Since: 3.1.0
@@ -2076,7 +2076,7 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g
  * hb_buffer_diff:
  * @buffer: a buffer.
  * @reference: other buffer to compare to.
- * @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1.
+ * @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepoint_t) -1.
  * @position_fuzz: allowed absolute difference in position values.
  *
  * If dottedcircle_glyph is (hb_codepoint_t) -1 then #HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.h b/src/java.desktop/share/native/libharfbuzz/hb-buffer.h
index 9b21ffb10fa15..6fc215d162779 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.h
@@ -99,7 +99,7 @@ typedef struct hb_glyph_info_t {
  *                                 layout, by avoiding re-shaping of each line
  *                                 after line-breaking, by limiting the
  *                                 reshaping to a small piece around the
- *                                 breaking positin only, even if the breaking
+ *                                 breaking position only, even if the breaking
  *                                 position carries the
  *                                 #HB_GLYPH_FLAG_UNSAFE_TO_BREAK or when
  *                                 hyphenation or other text transformation
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh
index c1476364de571..7f8ce14e90d58 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh
@@ -464,13 +464,16 @@ struct hb_buffer_t
                       start, end,
                       true);
   }
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
   void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1)
   {
     if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
       return;
     _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
                       start, end,
-                      true);
+                      false);
   }
   void unsafe_to_break_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
   {
@@ -478,6 +481,9 @@ struct hb_buffer_t
                       start, end,
                       true, true);
   }
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
   void unsafe_to_concat_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
   {
     if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
@@ -493,6 +499,13 @@ struct hb_buffer_t
 
   HB_NODISCARD HB_INTERNAL bool enlarge (unsigned int size);
 
+  HB_NODISCARD bool resize (unsigned length)
+  {
+    assert (!have_output);
+    if (unlikely (!ensure (length))) return false;
+    len = length;
+    return true;
+  }
   HB_NODISCARD bool ensure (unsigned int size)
   { return likely (!size || size < allocated) ? true : enlarge (size); }
 
@@ -553,7 +566,7 @@ struct hb_buffer_t
   bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
   {
 #ifdef HB_NO_BUFFER_MESSAGE
-   return true;
+    return true;
 #else
     if (likely (!messaging ()))
       return true;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cache.hh b/src/java.desktop/share/native/libharfbuzz/hb-cache.hh
index f40c8610dbb5a..8c7e0c655e6f5 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-cache.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-cache.hh
@@ -62,14 +62,12 @@ struct hb_cache_t
   static_assert ((key_bits >= cache_bits), "");
   static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), "");
 
-  hb_cache_t () { init (); }
-
-  void init () { clear (); }
+  hb_cache_t () { clear (); }
 
   void clear ()
   {
-    for (unsigned i = 0; i < ARRAY_LENGTH (values); i++)
-      values[i] = -1;
+    for (auto &v : values)
+      v = -1;
   }
 
   bool get (unsigned int key, unsigned int *value) const
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh
index e92e8140fd0f8..8d9ff5faf6d7e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh
@@ -26,6 +26,8 @@
 #ifndef HB_CFF_INTERP_COMMON_HH
 #define HB_CFF_INTERP_COMMON_HH
 
+extern HB_INTERNAL const unsigned char *endchar_str;
+
 namespace CFF {
 
 using namespace OT;
@@ -336,8 +338,6 @@ struct byte_str_ref_t
   hb_ubytes_t       str;
 };
 
-using byte_str_array_t = hb_vector_t;
-
 /* stack */
 template 
 struct cff_stack_t
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh
index 52b52c3f769d2..2628effa5cc7b 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh
@@ -883,14 +883,12 @@ struct cs_interpreter_t : interpreter_t
 
     unsigned max_ops = HB_CFF_MAX_OPS;
     for (;;) {
-      if (unlikely (!--max_ops))
+      OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
+      if (unlikely (SUPER::env.in_error () || !--max_ops))
       {
         SUPER::env.set_error ();
-        break;
-      }
-      OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
-      if (unlikely (SUPER::env.in_error ()))
         return false;
+      }
       if (SUPER::env.is_endchar ())
         break;
     }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-common.cc b/src/java.desktop/share/native/libharfbuzz/hb-common.cc
index 8b94dcb366d9d..3afab4284e68a 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-common.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-common.cc
@@ -815,7 +815,7 @@ parse_tag (const char **pp, const char *end, hb_tag_t *tag)
   }
 
   const char *p = *pp;
-  while (*pp < end && (ISALNUM(**pp) || **pp == '_'))
+  while (*pp < end && (**pp != ' ' && **pp != '=' && **pp != '[' && **pp != quote))
     (*pp)++;
 
   if (p == *pp || *pp - p > 4)
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-common.h b/src/java.desktop/share/native/libharfbuzz/hb-common.h
index ebdeadd1fd195..0d7956764cff6 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-common.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-common.h
@@ -104,6 +104,16 @@ typedef int hb_bool_t;
  *
  **/
 typedef uint32_t hb_codepoint_t;
+
+/**
+ * HB_CODEPOINT_INVALID:
+ *
+ * Unused #hb_codepoint_t value.
+ *
+ * Since: 8.0.0
+ */
+#define HB_CODEPOINT_INVALID ((hb_codepoint_t) -1)
+
 /**
  * hb_position_t:
  *
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-config.hh b/src/java.desktop/share/native/libharfbuzz/hb-config.hh
index 52adaad4384c0..816c55c7d367a 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-config.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-config.hh
@@ -44,14 +44,14 @@
 #ifdef HB_TINY
 #define HB_LEAN
 #define HB_MINI
+#define HB_OPTIMIZE_SIZE
+#define HB_OPTIMIZE_SIZE_MORE
+#define HB_MINIMIZE_MEMORY_USAGE
 #define HB_NO_MT
 #define HB_NO_UCD_UNASSIGNED
 #ifndef NDEBUG
 #define NDEBUG
 #endif
-#ifndef __OPTIMIZE_SIZE__
-#define __OPTIMIZE_SIZE__
-#endif
 #endif
 
 #ifdef HB_LEAN
@@ -97,6 +97,12 @@
 #define HB_NO_BORING_EXPANSION
 #endif
 
+#ifdef __OPTIMIZE_SIZE__
+#ifndef HB_OPTIMIZE_SIZE
+#define HB_OPTIMIZE_SIZE
+#endif
+#endif
+
 #if defined(HAVE_CONFIG_OVERRIDE_H) || defined(HB_CONFIG_OVERRIDE_H)
 #ifndef HB_CONFIG_OVERRIDE_H
 #define HB_CONFIG_OVERRIDE_H "config-override.h"
@@ -108,7 +114,8 @@
 
 #ifdef HB_NO_BORING_EXPANSION
 #define HB_NO_BEYOND_64K
-#define HB_NO_AVAR2
+#define HB_NO_CUBIC_GLYF
+#define HB_NO_VAR_COMPOSITES
 #endif
 
 #ifdef HB_DISABLE_DEPRECATED
@@ -175,21 +182,27 @@
 #define HB_NO_OT_SHAPER_MYANMAR_ZAWGYI
 #endif
 
-#ifdef NDEBUG
-#ifndef HB_NDEBUG
-#define HB_NDEBUG
-#endif
+#ifdef HB_OPTIMIZE_SIZE_MORE
+#define HB_NO_OT_RULESETS_FAST_PATH
 #endif
 
-#ifdef __OPTIMIZE_SIZE__
-#ifndef HB_OPTIMIZE_SIZE
-#define HB_OPTIMIZE_SIZE
-#endif
+#ifdef HB_MINIMIZE_MEMORY_USAGE
+#define HB_NO_GDEF_CACHE
+#define HB_NO_OT_LAYOUT_LOOKUP_CACHE
+#define HB_NO_OT_FONT_ADVANCE_CACHE
+#define HB_NO_OT_FONT_CMAP_CACHE
 #endif
 
 #ifdef HB_OPTIMIZE_SIZE
-#define HB_NO_OT_LAYOUT_LOOKUP_CACHE
+#define HB_OPTIMIZE_SIZE_VAL 1
+#else
+#define HB_OPTIMIZE_SIZE_VAL 0
 #endif
 
+#ifdef HB_MINIMIZE_MEMORY_USAGE
+#define HB_MINIMIZE_MEMORY_USAGE_VAL 1
+#else
+#define HB_MINIMIZE_MEMORY_USAGE_VAL 0
+#endif
 
 #endif /* HB_CONFIG_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-debug.hh b/src/java.desktop/share/native/libharfbuzz/hb-debug.hh
index 91a24a7152182..341e61e57c696 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-debug.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-debug.hh
@@ -265,8 +265,9 @@ static inline void _hb_warn_no_return (bool returned)
   }
 }
 template <>
-/*static*/ inline void _hb_warn_no_return (bool returned HB_UNUSED)
-{}
+/*static*/ inline void _hb_warn_no_return (bool returned HB_UNUSED) {}
+template <>
+/*static*/ inline void _hb_warn_no_return (bool returned HB_UNUSED) {}
 
 template 
 struct hb_auto_trace_t
@@ -389,6 +390,10 @@ struct hb_no_trace_t {
 #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
 #endif
 
+#ifndef HB_DEBUG_WASM
+#define HB_DEBUG_WASM (HB_DEBUG+0)
+#endif
+
 /*
  * With tracing.
  */
@@ -446,12 +451,26 @@ struct hb_no_trace_t {
 #define HB_DEBUG_SUBSET_REPACK (HB_DEBUG+0)
 #endif
 
+#ifndef HB_DEBUG_PAINT
+#define HB_DEBUG_PAINT (HB_DEBUG+0)
+#endif
+#if HB_DEBUG_PAINT
+#define TRACE_PAINT(this) \
+  HB_UNUSED hb_auto_trace_t trace \
+  (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+   " ")
+#else
+#define TRACE_PAINT(this) HB_UNUSED hb_no_trace_t trace
+#endif
+
+
 #ifndef HB_DEBUG_DISPATCH
 #define HB_DEBUG_DISPATCH ( \
         HB_DEBUG_APPLY + \
         HB_DEBUG_SANITIZE + \
         HB_DEBUG_SERIALIZE + \
         HB_DEBUG_SUBSET + \
+        HB_DEBUG_PAINT + \
         0)
 #endif
 #if HB_DEBUG_DISPATCH
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h b/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h
index a9e63de853d33..200e8ff49288b 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h
@@ -255,6 +255,52 @@ HB_EXTERN hb_position_t
 hb_font_get_glyph_v_kerning (hb_font_t *font,
                              hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
 
+
+/**
+ * hb_font_get_glyph_shape_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @draw_funcs: The draw functions to send the shape data to
+ * @draw_data: The data accompanying the draw functions
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * Since: 4.0.0
+ * Deprecated: 7.0.0: Use #hb_font_draw_glyph_func_t instead
+ **/
+typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data,
+                                                hb_codepoint_t glyph,
+                                                hb_draw_funcs_t *draw_funcs, void *draw_data,
+                                                void *user_data);
+
+/**
+ * hb_font_funcs_set_glyph_shape_func:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets the implementation function for #hb_font_get_glyph_shape_func_t,
+ * which is the same as #hb_font_draw_glyph_func_t.
+ *
+ * Since: 4.0.0
+ * Deprecated: 7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead
+ **/
+HB_DEPRECATED_FOR (hb_font_funcs_set_draw_glyph_func)
+HB_EXTERN void
+hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
+                                    hb_font_get_glyph_shape_func_t func,
+                                    void *user_data, hb_destroy_func_t destroy);
+
+HB_DEPRECATED_FOR (hb_font_draw_glyph)
+HB_EXTERN void
+hb_font_get_glyph_shape (hb_font_t *font,
+                         hb_codepoint_t glyph,
+                         hb_draw_funcs_t *dfuncs, void *draw_data);
+
+
 #endif
 
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.hh b/src/java.desktop/share/native/libharfbuzz/hb-draw.hh
index 6021ddb78fe58..e1adf9ddc9f5c 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-draw.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.hh
@@ -93,50 +93,57 @@ struct hb_draw_funcs_t
                      !user_data ? nullptr : user_data->close_path); }
 
 
-  void move_to (void *draw_data, hb_draw_state_t &st,
-                float to_x, float to_y)
+  void
+  HB_ALWAYS_INLINE
+  move_to (void *draw_data, hb_draw_state_t &st,
+           float to_x, float to_y)
   {
-    if (st.path_open) close_path (draw_data, st);
+    if (unlikely (st.path_open)) close_path (draw_data, st);
     st.current_x = to_x;
     st.current_y = to_y;
   }
 
-  void line_to (void *draw_data, hb_draw_state_t &st,
-                float to_x, float to_y)
+  void
+  HB_ALWAYS_INLINE
+  line_to (void *draw_data, hb_draw_state_t &st,
+           float to_x, float to_y)
   {
-    if (!st.path_open) start_path (draw_data, st);
+    if (unlikely (!st.path_open)) start_path (draw_data, st);
     emit_line_to (draw_data, st, to_x, to_y);
     st.current_x = to_x;
     st.current_y = to_y;
   }
 
   void
+  HB_ALWAYS_INLINE
   quadratic_to (void *draw_data, hb_draw_state_t &st,
                 float control_x, float control_y,
                 float to_x, float to_y)
   {
-    if (!st.path_open) start_path (draw_data, st);
+    if (unlikely (!st.path_open)) start_path (draw_data, st);
     emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y);
     st.current_x = to_x;
     st.current_y = to_y;
   }
 
   void
+  HB_ALWAYS_INLINE
   cubic_to (void *draw_data, hb_draw_state_t &st,
             float control1_x, float control1_y,
             float control2_x, float control2_y,
             float to_x, float to_y)
   {
-    if (!st.path_open) start_path (draw_data, st);
+    if (unlikely (!st.path_open)) start_path (draw_data, st);
     emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
     st.current_x = to_x;
     st.current_y = to_y;
   }
 
   void
+  HB_ALWAYS_INLINE
   close_path (void *draw_data, hb_draw_state_t &st)
   {
-    if (st.path_open)
+    if (likely (st.path_open))
     {
       if ((st.path_start_x != st.current_x) || (st.path_start_y != st.current_y))
         emit_line_to (draw_data, st, st.path_start_x, st.path_start_y);
@@ -168,6 +175,7 @@ struct hb_draw_session_t
 
   ~hb_draw_session_t () { close_path (); }
 
+  HB_ALWAYS_INLINE
   void move_to (float to_x, float to_y)
   {
     if (likely (not_slanted))
@@ -177,6 +185,7 @@ struct hb_draw_session_t
       funcs->move_to (draw_data, st,
                       to_x + to_y * slant, to_y);
   }
+  HB_ALWAYS_INLINE
   void line_to (float to_x, float to_y)
   {
     if (likely (not_slanted))
@@ -187,6 +196,7 @@ struct hb_draw_session_t
                       to_x + to_y * slant, to_y);
   }
   void
+  HB_ALWAYS_INLINE
   quadratic_to (float control_x, float control_y,
                 float to_x, float to_y)
   {
@@ -200,6 +210,7 @@ struct hb_draw_session_t
                            to_x + to_y * slant, to_y);
   }
   void
+  HB_ALWAYS_INLINE
   cubic_to (float control1_x, float control1_y,
             float control2_x, float control2_y,
             float to_x, float to_y)
@@ -215,6 +226,7 @@ struct hb_draw_session_t
                        control2_x + control2_y * slant, control2_y,
                        to_x + to_y * slant, to_y);
   }
+  HB_ALWAYS_INLINE
   void close_path ()
   {
     funcs->close_path (draw_data, st);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.cc b/src/java.desktop/share/native/libharfbuzz/hb-font.cc
index 5cfed3b04903a..9ce55bbeb89f3 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-font.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-font.cc
@@ -1066,7 +1066,7 @@ hb_font_get_nominal_glyph (hb_font_t      *font,
  * @glyph_stride: The stride between successive glyph IDs
  *
  * Fetches the nominal glyph IDs for a sequence of Unicode code points. Glyph
- * IDs must be returned in a #hb_codepoint_t output parameter. Stopes at the
+ * IDs must be returned in a #hb_codepoint_t output parameter. Stops at the
  * first unsupported glyph ID.
  *
  * Return value: the number of code points processed
@@ -1389,6 +1389,7 @@ hb_font_get_glyph_from_name (hb_font_t      *font,
   return font->get_glyph_from_name (name, len, glyph);
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_font_get_glyph_shape:
  * @font: #hb_font_t to work upon
@@ -1410,6 +1411,7 @@ hb_font_get_glyph_shape (hb_font_t *font,
 {
   hb_font_draw_glyph (font, glyph, dfuncs, draw_data);
 }
+#endif
 
 /**
  * hb_font_draw_glyph:
@@ -2648,7 +2650,6 @@ hb_font_set_variations (hb_font_t            *font,
       if (axes[axis_index].axisTag == tag)
         design_coords[axis_index] = v;
   }
-  font->face->table.avar->map_coords (normalized, coords_length);
 
   hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized);
   _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
@@ -2720,8 +2721,6 @@ hb_font_set_variation (hb_font_t *font,
     if (axes[axis_index].axisTag == tag)
       design_coords[axis_index] = value;
 
-  font->face->table.avar->map_coords (normalized, coords_length);
-
   hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized);
   _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
 
@@ -3058,6 +3057,7 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t          *ffuncs,
 #endif
 
 
+#ifndef HB_DISABLE_DEPRECATED
 void
 hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t               *ffuncs,
                                    hb_font_get_glyph_shape_func_t  func,
@@ -3066,3 +3066,4 @@ hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t               *ffuncs,
 {
   hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy);
 }
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.h b/src/java.desktop/share/native/libharfbuzz/hb-font.h
index 23301c13fc85c..f16658d9d8876 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-font.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-font.h
@@ -485,25 +485,6 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
                                                          hb_codepoint_t *glyph,
                                                          void *user_data);
 
-/**
- * hb_font_get_glyph_shape_func_t:
- * @font: #hb_font_t to work upon
- * @font_data: @font user data pointer
- * @glyph: The glyph ID to query
- * @draw_funcs: The draw functions to send the shape data to
- * @draw_data: The data accompanying the draw functions
- * @user_data: User data pointer passed by the caller
- *
- * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
- *
- * Since: 4.0.0
- * Deprecated: 7.0.0: Use #hb_font_draw_glyph_func_t instead
- **/
-typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data,
-                                                hb_codepoint_t glyph,
-                                                hb_draw_funcs_t *draw_funcs, void *draw_data,
-                                                void *user_data);
-
 /**
  * hb_font_draw_glyph_func_t:
  * @font: #hb_font_t to work upon
@@ -803,24 +784,6 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
                                         hb_font_get_glyph_from_name_func_t func,
                                         void *user_data, hb_destroy_func_t destroy);
 
-/**
- * hb_font_funcs_set_glyph_shape_func:
- * @ffuncs: A font-function structure
- * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
- * @user_data: Data to pass to @func
- * @destroy: (nullable): The function to call when @user_data is not needed anymore
- *
- * Sets the implementation function for #hb_font_get_glyph_shape_func_t,
- * which is the same as #hb_font_draw_glyph_func_t.
- *
- * Since: 4.0.0
- * Deprecated: 7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead
- **/
-HB_EXTERN void
-hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
-                                    hb_font_get_glyph_shape_func_t func,
-                                    void *user_data, hb_destroy_func_t destroy);
-
 /**
  * hb_font_funcs_set_draw_glyph_func:
  * @ffuncs: A font-function structure
@@ -828,8 +791,7 @@ hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
  * @user_data: Data to pass to @func
  * @destroy: (nullable): The function to call when @user_data is not needed anymore
  *
- * Sets the implementation function for #hb_font_draw_glyph_func_t,
- * which is the same as #hb_font_get_glyph_shape_func_t.
+ * Sets the implementation function for #hb_font_draw_glyph_func_t.
  *
  * Since: 7.0.0
  **/
@@ -934,11 +896,6 @@ hb_font_get_glyph_from_name (hb_font_t *font,
                              const char *name, int len, /* -1 means nul-terminated */
                              hb_codepoint_t *glyph);
 
-HB_EXTERN void
-hb_font_get_glyph_shape (hb_font_t *font,
-                         hb_codepoint_t glyph,
-                         hb_draw_funcs_t *dfuncs, void *draw_data);
-
 HB_EXTERN void
 hb_font_draw_glyph (hb_font_t *font,
                     hb_codepoint_t glyph,
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc
index 9b1fa8d53f268..32f5d3012da80 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc
@@ -114,7 +114,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
   ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
 
   ft_font->cached_serial = (unsigned) -1;
-  ft_font->advance_cache.init ();
+  new (&ft_font->advance_cache) hb_ft_advance_cache_t;
 
   return ft_font;
 }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-iter.hh b/src/java.desktop/share/native/libharfbuzz/hb-iter.hh
index bcd4eb8ebc4f2..ad45dcf2c1d4b 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-iter.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-iter.hh
@@ -63,6 +63,7 @@ struct hb_iter_t
   static constexpr bool is_iterator = true;
   static constexpr bool is_random_access_iterator = false;
   static constexpr bool is_sorted_iterator = false;
+  static constexpr bool has_fast_len = false; // Should be checked in combination with is_random_access_iterator.
 
   private:
   /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
@@ -393,7 +394,7 @@ struct hb_map_iter_t :
 
   private:
   Iter it;
-  hb_reference_wrapper f;
+  mutable hb_reference_wrapper f;
 };
 
 template 
@@ -456,8 +457,8 @@ struct hb_filter_iter_t :
 
   private:
   Iter it;
-  hb_reference_wrapper p;
-  hb_reference_wrapper f;
+  mutable hb_reference_wrapper p;
+  mutable hb_reference_wrapper f;
 };
 template 
 struct hb_filter_iter_factory_t
@@ -841,7 +842,7 @@ struct
   template 
   auto operator () (Iterable&& it, unsigned count) const HB_AUTO_RETURN
-  ( hb_zip (hb_range (count), it) | hb_map (hb_second) )
+  ( hb_zip (hb_range (count), it) | hb_map_retains_sorting (hb_second) )
 
   /* Specialization arrays. */
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-kern.hh b/src/java.desktop/share/native/libharfbuzz/hb-kern.hh
index fd47d566d0524..1f2c8d5811bcd 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-kern.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-kern.hh
@@ -53,7 +53,7 @@ struct hb_kern_machine_t
       return;
 
     buffer->unsafe_to_concat ();
-    OT::hb_ot_apply_context_t c (1, font, buffer);
+    OT::hb_ot_apply_context_t c (1, font, buffer, hb_blob_get_empty ());
     c.set_lookup_mask (kern_mask);
     c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
     auto &skippy_iter = c.iter_input;
@@ -70,7 +70,7 @@ struct hb_kern_machine_t
         continue;
       }
 
-      skippy_iter.reset (idx, 1);
+      skippy_iter.reset (idx);
       unsigned unsafe_to;
       if (!skippy_iter.next (&unsafe_to))
       {
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-limits.hh b/src/java.desktop/share/native/libharfbuzz/hb-limits.hh
index 0f60e9e21013b..25c1e71e133c4 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-limits.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-limits.hh
@@ -89,6 +89,10 @@
 #endif
 
 
+#ifndef HB_GLYF_VAR_COMPOSITE_MAX_AXES
+#define HB_GLYF_VAR_COMPOSITE_MAX_AXES 4096
+#endif
+
 #ifndef HB_GLYF_MAX_POINTS
 #define HB_GLYF_MAX_POINTS 20000
 #endif
@@ -102,7 +106,7 @@
 #endif
 
 #ifndef HB_COLRV1_MAX_EDGE_COUNT
-#define HB_COLRV1_MAX_EDGE_COUNT 1024
+#define HB_COLRV1_MAX_EDGE_COUNT 65536
 #endif
 
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh
index 3a048fc124265..580c9f0c78519 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh
@@ -180,6 +180,9 @@ struct hb_lazy_loader_t : hb_data_wrapper_t
                                  hb_lazy_loader_t
                                 >::value Funcs;
 
+  hb_lazy_loader_t () = default;
+  hb_lazy_loader_t (const hb_lazy_loader_t &other) = delete;
+
   void init0 () {} /* Init, when memory is already set to 0. No-op for us. */
   void init ()  { instance.set_relaxed (nullptr); }
   void fini ()  { do_destroy (instance.get_acquire ()); init (); }
@@ -278,7 +281,11 @@ struct hb_lazy_loader_t : hb_data_wrapper_t
 template 
 struct hb_face_lazy_loader_t : hb_lazy_loader_t,
-                                                hb_face_t, WheresFace> {};
+                                                hb_face_t, WheresFace>
+{
+  // Hack; have them here for API parity with hb_table_lazy_loader_t
+  hb_blob_t *get_blob () { return this->get ()->get_blob (); }
+};
 
 template 
 struct hb_table_lazy_loader_t : hb_lazy_loader_t (face);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-map.cc b/src/java.desktop/share/native/libharfbuzz/hb-map.cc
index 48913a6a10df1..6ba943f046886 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-map.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-map.cc
@@ -365,7 +365,7 @@ hb_map_update (hb_map_t *map,
  * @key: (out): Key retrieved
  * @value: (out): Value retrieved
  *
- * Fetches the next key/value paire in @map.
+ * Fetches the next key/value pair in @map.
  *
  * Set @idx to -1 to get started.
  *
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-map.h b/src/java.desktop/share/native/libharfbuzz/hb-map.h
index 12d8970f48f28..b72e2abaaa019 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-map.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-map.h
@@ -44,7 +44,7 @@ HB_BEGIN_DECLS
  *
  * Since: 1.7.7
  */
-#define HB_MAP_VALUE_INVALID ((hb_codepoint_t) -1)
+#define HB_MAP_VALUE_INVALID HB_CODEPOINT_INVALID
 
 /**
  * hb_map_t:
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-map.hh b/src/java.desktop/share/native/libharfbuzz/hb-map.hh
index 3b24dc9455ac4..d31323733cc5a 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-map.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-map.hh
@@ -45,9 +45,9 @@ struct hb_hashmap_t
   hb_hashmap_t ()  { init (); }
   ~hb_hashmap_t () { fini (); }
 
-  hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (o.population); hb_copy (o, *this); }
+  hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { alloc (o.population); hb_copy (o, *this); }
   hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); }
-  hb_hashmap_t& operator= (const hb_hashmap_t& o)  { reset (); resize (o.population); hb_copy (o, *this); return *this; }
+  hb_hashmap_t& operator= (const hb_hashmap_t& o)  { reset (); alloc (o.population); hb_copy (o, *this); return *this; }
   hb_hashmap_t& operator= (hb_hashmap_t&& o)  { hb_swap (*this, o); return *this; }
 
   hb_hashmap_t (std::initializer_list> lst) : hb_hashmap_t ()
@@ -60,29 +60,32 @@ struct hb_hashmap_t
   hb_hashmap_t (const Iterable &o) : hb_hashmap_t ()
   {
     auto iter = hb_iter (o);
-    if (iter.is_random_access_iterator)
-      resize (hb_len (iter));
+    if (iter.is_random_access_iterator || iter.has_fast_len)
+      alloc (hb_len (iter));
     hb_copy (iter, *this);
   }
 
   struct item_t
   {
     K key;
-    uint32_t hash : 30;
+    uint32_t is_real_ : 1;
     uint32_t is_used_ : 1;
-    uint32_t is_tombstone_ : 1;
+    uint32_t hash : 30;
     V value;
 
     item_t () : key (),
+                is_real_ (false), is_used_ (false),
                 hash (0),
-                is_used_ (false), is_tombstone_ (false),
                 value () {}
 
+    // Needed for https://github.com/harfbuzz/harfbuzz/issues/4138
+    K& get_key () { return key; }
+    V& get_value () { return value; }
+
     bool is_used () const { return is_used_; }
     void set_used (bool is_used) { is_used_ = is_used; }
-    bool is_tombstone () const { return is_tombstone_; }
-    void set_tombstone (bool is_tombstone) { is_tombstone_ = is_tombstone; }
-    bool is_real () const { return is_used_ && !is_tombstone_; }
+    void set_real (bool is_real) { is_real_ = is_real; }
+    bool is_real () const { return is_real_; }
 
     template 
@@ -98,10 +101,15 @@ struct hb_hashmap_t
     bool operator == (const K &o) const { return hb_deref (key) == hb_deref (o); }
     bool operator == (const item_t &o) const { return *this == o.key; }
     hb_pair_t get_pair() const { return hb_pair_t (key, value); }
-    hb_pair_t get_pair_ref() const { return hb_pair_t (key, value); }
+    hb_pair_t get_pair_ref() { return hb_pair_t (key, value); }
 
     uint32_t total_hash () const
-    { return (hash * 31) + hb_hash (value); }
+    { return (hash * 31u) + hb_hash (value); }
+
+    static constexpr bool is_trivial = hb_is_trivially_constructible(K) &&
+                                       hb_is_trivially_destructible(K) &&
+                                       hb_is_trivially_constructible(V) &&
+                                       hb_is_trivially_destructible(V);
   };
 
   hb_object_header_t header;
@@ -110,6 +118,7 @@ struct hb_hashmap_t
   unsigned int occupancy; /* Including tombstones. */
   unsigned int mask;
   unsigned int prime;
+  unsigned int max_chain_length;
   item_t *items;
 
   friend void swap (hb_hashmap_t& a, hb_hashmap_t& b)
@@ -123,6 +132,7 @@ struct hb_hashmap_t
     hb_swap (a.occupancy, b.occupancy);
     hb_swap (a.mask, b.mask);
     hb_swap (a.prime, b.prime);
+    hb_swap (a.max_chain_length, b.max_chain_length);
     hb_swap (a.items, b.items);
   }
   void init ()
@@ -133,16 +143,19 @@ struct hb_hashmap_t
     population = occupancy = 0;
     mask = 0;
     prime = 0;
+    max_chain_length = 0;
     items = nullptr;
   }
   void fini ()
   {
     hb_object_fini (this);
 
-    if (likely (items)) {
+    if (likely (items))
+    {
       unsigned size = mask + 1;
-      for (unsigned i = 0; i < size; i++)
-        items[i].~item_t ();
+      if (!item_t::is_trivial)
+        for (unsigned i = 0; i < size; i++)
+          items[i].~item_t ();
       hb_free (items);
       items = nullptr;
     }
@@ -157,7 +170,7 @@ struct hb_hashmap_t
 
   bool in_error () const { return !successful; }
 
-  bool resize (unsigned new_population = 0)
+  bool alloc (unsigned new_population = 0)
   {
     if (unlikely (!successful)) return false;
 
@@ -171,8 +184,11 @@ struct hb_hashmap_t
       successful = false;
       return false;
     }
-    for (auto &_ : hb_iter (new_items, new_size))
-      new (&_) item_t ();
+    if (!item_t::is_trivial)
+      for (auto &_ : hb_iter (new_items, new_size))
+        new (&_) item_t ();
+    else
+      hb_memset (new_items, 0, (size_t) new_size * sizeof (item_t));
 
     unsigned int old_size = size ();
     item_t *old_items = items;
@@ -181,6 +197,7 @@ struct hb_hashmap_t
     population = occupancy = 0;
     mask = new_size - 1;
     prime = prime_for (power);
+    max_chain_length = power * 2;
     items = new_items;
 
     /* Insert back old items. */
@@ -192,7 +209,8 @@ struct hb_hashmap_t
                        old_items[i].hash,
                        std::move (old_items[i].value));
       }
-      old_items[i].~item_t ();
+      if (!item_t::is_trivial)
+        old_items[i].~item_t ();
     }
 
     hb_free (old_items);
@@ -201,72 +219,129 @@ struct hb_hashmap_t
   }
 
   template 
-  bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool is_delete=false)
+  bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool overwrite = true)
   {
     if (unlikely (!successful)) return false;
-    if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false;
-    item_t &item = item_for_hash (key, hash);
+    if (unlikely ((occupancy + occupancy / 2) >= mask && !alloc ())) return false;
+
+    hash &= 0x3FFFFFFF; // We only store lower 30bit of hash
+    unsigned int tombstone = (unsigned int) -1;
+    unsigned int i = hash % prime;
+    unsigned length = 0;
+    unsigned step = 0;
+    while (items[i].is_used ())
+    {
+      if ((std::is_integral::value || items[i].hash == hash) &&
+          items[i] == key)
+      {
+        if (!overwrite)
+          return false;
+        else
+          break;
+      }
+      if (!items[i].is_real () && tombstone == (unsigned) -1)
+        tombstone = i;
+      i = (i + ++step) & mask;
+      length++;
+    }
 
-    if (is_delete && !(item == key))
-      return true; /* Trying to delete non-existent key. */
+    item_t &item = items[tombstone == (unsigned) -1 ? i : tombstone];
 
     if (item.is_used ())
     {
       occupancy--;
-      if (!item.is_tombstone ())
-        population--;
+      population -= item.is_real ();
     }
 
     item.key = std::forward (key);
     item.value = std::forward (value);
     item.hash = hash;
     item.set_used (true);
-    item.set_tombstone (is_delete);
+    item.set_real (true);
 
     occupancy++;
-    if (!is_delete)
-      population++;
+    population++;
+
+    if (unlikely (length > max_chain_length) && occupancy * 8 > mask)
+      alloc (mask - 8); // This ensures we jump to next larger size
 
     return true;
   }
 
   template 
-  bool set (const K &key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward (value)); }
+  bool set (const K &key, VV&& value, bool overwrite = true) { return set_with_hash (key, hb_hash (key), std::forward (value), overwrite); }
   template 
-  bool set (K &&key, VV&& value) { return set_with_hash (std::move (key), hb_hash (key), std::forward (value)); }
+  bool set (K &&key, VV&& value, bool overwrite = true)
+  {
+    uint32_t hash = hb_hash (key);
+    return set_with_hash (std::move (key), hash, std::forward (value), overwrite);
+  }
+  bool add (const K &key)
+  {
+    uint32_t hash = hb_hash (key);
+    return set_with_hash (key, hash, item_t::default_value ());
+  }
 
   const V& get_with_hash (const K &key, uint32_t hash) const
   {
-    if (unlikely (!items)) return item_t::default_value ();
-    auto &item = item_for_hash (key, hash);
-    return item.is_real () && item == key ? item.value : item_t::default_value ();
+    if (!items) return item_t::default_value ();
+    auto *item = fetch_item (key, hb_hash (key));
+    if (item)
+      return item->value;
+    return item_t::default_value ();
   }
   const V& get (const K &key) const
   {
-    if (unlikely (!items)) return item_t::default_value ();
+    if (!items) return item_t::default_value ();
     return get_with_hash (key, hb_hash (key));
   }
 
-  void del (const K &key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); }
+  void del (const K &key)
+  {
+    if (!items) return;
+    auto *item = fetch_item (key, hb_hash (key));
+    if (item)
+    {
+      item->set_real (false);
+      population--;
+    }
+  }
 
   /* Has interface. */
   const V& operator [] (K k) const { return get (k); }
   template 
-  bool has (K key, VV **vp = nullptr) const
+  bool has (const K &key, VV **vp = nullptr) const
   {
-    if (unlikely (!items))
-      return false;
-    auto &item = item_for_hash (key, hb_hash (key));
-    if (item.is_real () && item == key)
+    if (!items) return false;
+    auto *item = fetch_item (key, hb_hash (key));
+    if (item)
     {
-      if (vp) *vp = std::addressof (item.value);
+      if (vp) *vp = std::addressof (item->value);
       return true;
     }
-    else
-      return false;
+    return false;
+  }
+  item_t *fetch_item (const K &key, uint32_t hash) const
+  {
+    hash &= 0x3FFFFFFF; // We only store lower 30bit of hash
+    unsigned int i = hash % prime;
+    unsigned step = 0;
+    while (items[i].is_used ())
+    {
+      if ((std::is_integral::value || items[i].hash == hash) &&
+          items[i] == key)
+      {
+        if (items[i].is_real ())
+          return &items[i];
+        else
+          return nullptr;
+      }
+      i = (i + ++step) & mask;
+    }
+    return nullptr;
   }
   /* Projection. */
-  V operator () (K k) const { return get (k); }
+  const V& operator () (K k) const { return get (k); }
 
   unsigned size () const { return mask ? mask + 1 : 0; }
 
@@ -323,39 +398,37 @@ struct hb_hashmap_t
 
   auto iter_items () const HB_AUTO_RETURN
   (
-    + hb_iter (items, size ())
+    + hb_iter (items, this->size ())
     | hb_filter (&item_t::is_real)
   )
   auto iter_ref () const HB_AUTO_RETURN
   (
-    + iter_items ()
+    + this->iter_items ()
     | hb_map (&item_t::get_pair_ref)
   )
   auto iter () const HB_AUTO_RETURN
   (
-    + iter_items ()
+    + this->iter_items ()
     | hb_map (&item_t::get_pair)
   )
   auto keys_ref () const HB_AUTO_RETURN
   (
-    + iter_items ()
-    | hb_map (&item_t::key)
+    + this->iter_items ()
+    | hb_map (&item_t::get_key)
   )
   auto keys () const HB_AUTO_RETURN
   (
-    + iter_items ()
-    | hb_map (&item_t::key)
+    + this->keys_ref ()
     | hb_map (hb_ridentity)
   )
   auto values_ref () const HB_AUTO_RETURN
   (
-    + iter_items ()
-    | hb_map (&item_t::value)
+    + this->iter_items ()
+    | hb_map (&item_t::get_value)
   )
   auto values () const HB_AUTO_RETURN
   (
-    + iter_items ()
-    | hb_map (&item_t::value)
+    + this->values_ref ()
     | hb_map (hb_ridentity)
   )
 
@@ -393,23 +466,6 @@ struct hb_hashmap_t
   hb_hashmap_t& operator << (const hb_pair_t& v)
   { set (std::move (v.first), std::move (v.second)); return *this; }
 
-  item_t& item_for_hash (const K &key, uint32_t hash) const
-  {
-    hash &= 0x3FFFFFFF; // We only store lower 30bit of hash
-    unsigned int i = hash % prime;
-    unsigned int step = 0;
-    unsigned int tombstone = (unsigned) -1;
-    while (items[i].is_used ())
-    {
-      if (items[i].hash == hash && items[i] == key)
-        return items[i];
-      if (tombstone == (unsigned) -1 && items[i].is_tombstone ())
-        tombstone = i;
-      i = (i + ++step) & mask;
-    }
-    return items[tombstone == (unsigned) -1 ? i : tombstone];
-  }
-
   static unsigned int prime_for (unsigned int shift)
   {
     /* Following comment and table copied from glib. */
@@ -480,7 +536,7 @@ struct hb_map_t : hb_hashmap_t> lst) : hashmap (lst) {}
+  hb_map_t (std::initializer_list lst) : hashmap (lst) {}
   template 
   hb_map_t (const Iterable &o) : hashmap (o) {}
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-meta.hh b/src/java.desktop/share/native/libharfbuzz/hb-meta.hh
index 454321499c472..d8d12f0aeb3db 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-meta.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-meta.hh
@@ -153,8 +153,8 @@ struct hb_reference_wrapper
   hb_reference_wrapper (T v) : v (v) {}
   bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
   bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
-  operator T () const { return v; }
-  T get () const { return v; }
+  operator T& () { return v; }
+  T& get () { return v; }
   T v;
 };
 template 
@@ -163,8 +163,8 @@ struct hb_reference_wrapper
   hb_reference_wrapper (T& v) : v (std::addressof (v)) {}
   bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
   bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
-  operator T& () const { return *v; }
-  T& get () const { return *v; }
+  operator T& () { return *v; }
+  T& get () { return *v; }
   T* v;
 };
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-multimap.hh b/src/java.desktop/share/native/libharfbuzz/hb-multimap.hh
index b4a8cc62a3e3c..0184279c12760 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-multimap.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-multimap.hh
@@ -38,10 +38,10 @@ struct hb_multimap_t
 {
   void add (hb_codepoint_t k, hb_codepoint_t v)
   {
-    hb_codepoint_t *i;
-    if (multiples_indices.has (k, &i))
+    hb_vector_t *m;
+    if (multiples.has (k, &m))
     {
-      multiples_values[*i].push (v);
+      m->push (v);
       return;
     }
 
@@ -51,12 +51,7 @@ struct hb_multimap_t
       hb_codepoint_t old = *old_v;
       singulars.del (k);
 
-      multiples_indices.set (k, multiples_values.length);
-      auto *vec = multiples_values.push ();
-
-      vec->push (old);
-      vec->push (v);
-
+      multiples.set (k, hb_vector_t {old, v});
       return;
     }
 
@@ -69,22 +64,31 @@ struct hb_multimap_t
     if (singulars.has (k, &v))
       return hb_array (v, 1);
 
-    hb_codepoint_t *i;
-    if (multiples_indices.has (k, &i))
-      return multiples_values[*i].as_array ();
+    hb_vector_t *m;
+    if (multiples.has (k, &m))
+      return m->as_array ();
 
     return hb_array_t ();
   }
 
   bool in_error () const
   {
-    return singulars.in_error () || multiples_indices.in_error () || multiples_values.in_error ();
+    if (singulars.in_error () || multiples.in_error ())
+      return true;
+    for (const auto &m : multiples.values_ref ())
+      if (m.in_error ())
+        return true;
+    return false;
+  }
+
+  void alloc (unsigned size)
+  {
+    singulars.alloc (size);
   }
 
   protected:
   hb_map_t singulars;
-  hb_map_t multiples_indices;
-  hb_vector_t> multiples_values;
+  hb_hashmap_t> multiples;
 };
 
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-null.hh b/src/java.desktop/share/native/libharfbuzz/hb-null.hh
index 8a9ebbfc2d758..4a5270e340025 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-null.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-null.hh
@@ -37,7 +37,7 @@
 
 /* Global nul-content Null pool.  Enlarge as necessary. */
 
-#define HB_NULL_POOL_SIZE 448
+#define HB_NULL_POOL_SIZE 640
 
 template 
 struct _hb_has_min_size : hb_false_type {};
@@ -85,7 +85,7 @@ using hb_null_size = _hb_null_size;
 template 
 struct _hb_static_size : hb_integral_constant {};
 template 
-struct _hb_static_size> : hb_integral_constant {};
+struct _hb_static_size> : hb_integral_constant {};
 template 
 using hb_static_size = _hb_static_size;
 #define hb_static_size(T) hb_static_size::value
@@ -176,7 +176,7 @@ template 
 static inline Type& Crap () {
   static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
   Type *obj = reinterpret_cast (_hb_CrapPool);
-  memcpy (obj, &Null (Type), sizeof (*obj));
+  memcpy (obj, std::addressof (Null (Type)), sizeof (*obj));
   return *obj;
 }
 template 
@@ -211,11 +211,11 @@ struct hb_nonnull_ptr_t
   T * operator = (T *v_)   { return v = v_; }
   T * operator -> () const { return get (); }
   T & operator * () const  { return *get (); }
-  T ** operator & () const { return &v; }
+  T ** operator & () const { return std::addressof (v); }
   /* Only auto-cast to const types. */
   template  operator const C * () const { return get (); }
   operator const char * () const { return (const char *) get (); }
-  T * get () const { return v ? v : const_cast (&Null (T)); }
+  T * get () const { return v ? v : const_cast (std::addressof (Null (T))); }
   T * get_raw () const { return v; }
 
   private:
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh b/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh
index 07f3ebe0c7dff..9d2867e483550 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh
@@ -31,7 +31,7 @@
 #include "hb.hh"
 
 
-#line 32 "hb-number-parser.hh"
+#line 35 "hb-number-parser.hh"
 static const unsigned char _double_parser_trans_keys[] = {
         0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u,
         46u, 101u, 0
@@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
 
   int cs;
 
-#line 132 "hb-number-parser.hh"
+#line 139 "hb-number-parser.hh"
         {
         cs = double_parser_start;
         }
 
-#line 135 "hb-number-parser.hh"
+#line 144 "hb-number-parser.hh"
         {
         int _slen;
         int _trans;
@@ -198,7 +198,7 @@ _resume:
           exp_overflow = true;
 }
         break;
-#line 187 "hb-number-parser.hh"
+#line 202 "hb-number-parser.hh"
         }
 
 _again:
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh b/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh
index c02eb41d1001e..387b1430ac1ec 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh
@@ -131,7 +131,7 @@ typedef struct OpenTypeOffsetTable
     sfnt_version = sfnt_tag;
     /* Take space for numTables, searchRange, entrySelector, RangeShift
      * and the TableRecords themselves.  */
-    unsigned num_items = it.len ();
+    unsigned num_items = hb_len (it);
     if (unlikely (!tables.serialize (c, num_items))) return_trace (false);
 
     const char *dir_end = (const char *) c->head;
@@ -145,7 +145,7 @@ typedef struct OpenTypeOffsetTable
       unsigned len = blob->length;
 
       /* Allocate room for the table and copy it. */
-      char *start = (char *) c->allocate_size (len);
+      char *start = (char *) c->allocate_size (len, false);
       if (unlikely (!start)) return false;
 
       TableRecord &rec = tables.arrayZ[i];
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh b/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh
index 4639d80babc86..25142da44a6cb 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh
@@ -312,6 +312,8 @@ struct _hb_has_null
 template 
 struct OffsetTo : Offset
 {
+  using target_t = Type;
+
   // Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time.
   static_assert (has_null == false ||
                  (hb_has_null_size (Type) || !hb_has_min_size (Type)), "");
@@ -416,12 +418,15 @@ struct OffsetTo : Offset
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this))) return_trace (false);
-    if (unlikely (this->is_null ())) return_trace (true);
+    //if (unlikely (this->is_null ())) return_trace (true);
     if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false);
     return_trace (true);
   }
 
   template 
+#ifndef HB_OPTIMIZE_SIZE
+  HB_ALWAYS_INLINE
+#endif
   bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
@@ -462,24 +467,16 @@ struct UnsizedArrayOf
 
   HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf);
 
-  const Type& operator [] (int i_) const
+  const Type& operator [] (unsigned int i) const
   {
-    unsigned int i = (unsigned int) i_;
-    const Type *p = &arrayZ[i];
-    if (unlikely ((const void *) p < (const void *) arrayZ)) return Null (Type); /* Overflowed. */
-    _hb_compiler_memory_r_barrier ();
-    return *p;
+    return arrayZ[i];
   }
-  Type& operator [] (int i_)
+  Type& operator [] (unsigned int i)
   {
-    unsigned int i = (unsigned int) i_;
-    Type *p = &arrayZ[i];
-    if (unlikely ((const void *) p < (const void *) arrayZ)) return Crap (Type); /* Overflowed. */
-    _hb_compiler_memory_r_barrier ();
-    return *p;
+    return arrayZ[i];
   }
 
-  unsigned int get_size (unsigned int len) const
+  static unsigned int get_size (unsigned int len)
   { return len * Type::static_size; }
 
   template  operator T * () { return arrayZ; }
@@ -533,6 +530,7 @@ struct UnsizedArrayOf
   }
 
   template 
+  HB_ALWAYS_INLINE
   bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
@@ -721,6 +719,7 @@ struct ArrayOf
   }
 
   template 
+  HB_ALWAYS_INLINE
   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
@@ -736,7 +735,7 @@ struct ArrayOf
   bool sanitize_shallow (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (len.sanitize (c) && c->check_array (arrayZ, len));
+    return_trace (len.sanitize (c) && c->check_array_sized (arrayZ, len, sizeof (LenType)));
   }
 
   public:
@@ -797,7 +796,7 @@ template 
 using List16OfOffset16To = List16OfOffsetTo;
 
 /* An array starting at second element. */
-template 
+template 
 struct HeadlessArrayOf
 {
   static constexpr unsigned item_size = Type::static_size;
@@ -861,6 +860,7 @@ struct HeadlessArrayOf
   }
 
   template 
+  HB_ALWAYS_INLINE
   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
@@ -878,7 +878,7 @@ struct HeadlessArrayOf
   {
     TRACE_SANITIZE (this);
     return_trace (lenP1.sanitize (c) &&
-                  (!lenP1 || c->check_array (arrayZ, lenP1 - 1)));
+                  (!lenP1 || c->check_array_sized (arrayZ, lenP1 - 1, sizeof (LenType))));
   }
 
   public:
@@ -887,6 +887,7 @@ struct HeadlessArrayOf
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
+template  using HeadlessArray16Of = HeadlessArrayOf;
 
 /* An array storing length-1. */
 template 
@@ -912,6 +913,7 @@ struct ArrayOfM1
   { return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
 
   template 
+  HB_ALWAYS_INLINE
   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
@@ -929,7 +931,7 @@ struct ArrayOfM1
   {
     TRACE_SANITIZE (this);
     return_trace (lenM1.sanitize (c) &&
-                  (c->check_array (arrayZ, lenM1 + 1)));
+                  (c->check_array_sized (arrayZ, lenM1 + 1, sizeof (LenType))));
   }
 
   public:
@@ -1096,6 +1098,7 @@ struct VarSizedBinSearchArrayOf
   { return header.static_size + header.nUnits * header.unitSize; }
 
   template 
+  HB_ALWAYS_INLINE
   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh
index d31a328e8adf7..081c333f50f52 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh
@@ -48,12 +48,24 @@ static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offs
 
 struct code_pair_t
 {
-  hb_codepoint_t code;
+  unsigned code;
   hb_codepoint_t glyph;
 };
 
+
 using str_buff_t = hb_vector_t;
 using str_buff_vec_t = hb_vector_t;
+using glyph_to_sid_map_t = hb_vector_t;
+
+struct length_f_t
+{
+  template 
+  unsigned operator () (const Iterable &_) const { return hb_len (hb_iter (_)); }
+
+  unsigned operator () (unsigned _) const { return _; }
+}
+HB_FUNCOBJ (length_f);
 
 /* CFF INDEX */
 template 
@@ -62,42 +74,52 @@ struct CFFIndex
   unsigned int offset_array_size () const
   { return offSize * (count + 1); }
 
-  CFFIndex *copy (hb_serialize_context_t *c) const
-  {
-    TRACE_SERIALIZE (this);
-    unsigned int size = get_size ();
-    CFFIndex *out = c->allocate_size (size, false);
-    if (likely (out))
-      hb_memcpy (out, this, size);
-    return_trace (out);
-  }
-
   template 
   bool serialize (hb_serialize_context_t *c,
-                  const Iterable &iterable)
+                  const Iterable &iterable,
+                  const unsigned *p_data_size = nullptr)
   {
     TRACE_SERIALIZE (this);
+    unsigned data_size;
+    if (p_data_size)
+      data_size = *p_data_size;
+    else
+      total_size (iterable, &data_size);
+
     auto it = hb_iter (iterable);
-    serialize_header(c, + it | hb_map (hb_iter) | hb_map (hb_len));
+    if (unlikely (!serialize_header (c, +it, data_size))) return_trace (false);
+    unsigned char *ret = c->allocate_size (data_size, false);
+    if (unlikely (!ret)) return_trace (false);
     for (const auto &_ : +it)
-      hb_iter (_).copy (c);
+    {
+      unsigned len = _.length;
+      if (!len)
+        continue;
+      if (len <= 1)
+      {
+        *ret++ = *_.arrayZ;
+        continue;
+      }
+      hb_memcpy (ret, _.arrayZ, len);
+      ret += len;
+    }
     return_trace (true);
   }
 
   template 
   bool serialize_header (hb_serialize_context_t *c,
-                        Iterator it)
+                         Iterator it,
+                         unsigned data_size)
   {
     TRACE_SERIALIZE (this);
 
-    unsigned total = + it | hb_reduce (hb_add, 0);
-    unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8;
+    unsigned off_size = (hb_bit_storage (data_size + 1) + 7) / 8;
 
     /* serialize CFFIndex header */
     if (unlikely (!c->extend_min (this))) return_trace (false);
-    this->count = it.len ();
+    this->count = hb_len (it);
     if (!this->count) return_trace (true);
     if (unlikely (!c->extend (this->offSize))) return_trace (false);
     this->offSize = off_size;
@@ -106,25 +128,88 @@ struct CFFIndex
 
     /* serialize indices */
     unsigned int offset = 1;
-    unsigned int i = 0;
-    for (unsigned _ : +it)
+    if (HB_OPTIMIZE_SIZE_VAL)
     {
-      set_offset_at (i++, offset);
-      offset += _;
+      unsigned int i = 0;
+      for (const auto &_ : +it)
+      {
+        set_offset_at (i++, offset);
+        offset += length_f (_);
+      }
+      set_offset_at (i, offset);
     }
-    set_offset_at (i, offset);
-
+    else
+      switch (off_size)
+      {
+        case 1:
+        {
+          HBUINT8 *p = (HBUINT8 *) offsets;
+          for (const auto &_ : +it)
+          {
+            *p++ = offset;
+            offset += length_f (_);
+          }
+          *p = offset;
+        }
+        break;
+        case 2:
+        {
+          HBUINT16 *p = (HBUINT16 *) offsets;
+          for (const auto &_ : +it)
+          {
+            *p++ = offset;
+            offset += length_f (_);
+          }
+          *p = offset;
+        }
+        break;
+        case 3:
+        {
+          HBUINT24 *p = (HBUINT24 *) offsets;
+          for (const auto &_ : +it)
+          {
+            *p++ = offset;
+            offset += length_f (_);
+          }
+          *p = offset;
+        }
+        break;
+        case 4:
+        {
+          HBUINT32 *p = (HBUINT32 *) offsets;
+          for (const auto &_ : +it)
+          {
+            *p++ = offset;
+            offset += length_f (_);
+          }
+          *p = offset;
+        }
+        break;
+        default:
+        break;
+      }
+
+    assert (offset == data_size + 1);
     return_trace (true);
   }
 
   template 
-  static unsigned total_size (const Iterable &iterable)
+  static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr)
   {
-    auto it = + hb_iter (iterable) | hb_map (hb_iter) | hb_map (hb_len);
-    if (!it) return 0;
+    auto it = + hb_iter (iterable);
+    if (!it)
+    {
+      if (data_size) *data_size = 0;
+      return min_size;
+    }
+
+    unsigned total = 0;
+    for (const auto &_ : +it)
+      total += length_f (_);
+
+    if (data_size) *data_size = total;
 
-    unsigned total = + it | hb_reduce (hb_add, 0);
     unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8;
 
     return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total;
@@ -133,13 +218,16 @@ struct CFFIndex
   void set_offset_at (unsigned int index, unsigned int offset)
   {
     assert (index <= count);
-    HBUINT8 *p = offsets + offSize * index + offSize;
+
     unsigned int size = offSize;
-    for (; size; size--)
+    const HBUINT8 *p = offsets;
+    switch (size)
     {
-      --p;
-      *p = offset & 0xFF;
-      offset >>= 8;
+      case 1: ((HBUINT8  *) p)[index] = offset; break;
+      case 2: ((HBUINT16 *) p)[index] = offset; break;
+      case 3: ((HBUINT24 *) p)[index] = offset; break;
+      case 4: ((HBUINT32 *) p)[index] = offset; break;
+      default: return;
     }
   }
 
@@ -149,37 +237,30 @@ struct CFFIndex
     assert (index <= count);
 
     unsigned int size = offSize;
-    const HBUINT8 *p = offsets + size * index;
+    const HBUINT8 *p = offsets;
     switch (size)
     {
-      case 1: return * (HBUINT8  *) p;
-      case 2: return * (HBUINT16 *) p;
-      case 3: return * (HBUINT24 *) p;
-      case 4: return * (HBUINT32 *) p;
+      case 1: return ((HBUINT8  *) p)[index];
+      case 2: return ((HBUINT16 *) p)[index];
+      case 3: return ((HBUINT24 *) p)[index];
+      case 4: return ((HBUINT32 *) p)[index];
       default: return 0;
     }
   }
 
-  unsigned int length_at (unsigned int index) const
-  {
-    unsigned offset0 = offset_at (index);
-    unsigned offset1 = offset_at (index + 1);
-    if (unlikely (offset1 < offset0 || offset1 > offset_at (count)))
-      return 0;
-    return offset1 - offset0;
-  }
-
   const unsigned char *data_base () const
-  { return (const unsigned char *) this + min_size + offSize.static_size + offset_array_size (); }
+  { return (const unsigned char *) this + min_size + offSize.static_size - 1 + offset_array_size (); }
   public:
 
   hb_ubytes_t operator [] (unsigned int index) const
   {
     if (unlikely (index >= count)) return hb_ubytes_t ();
     _hb_compiler_memory_r_barrier ();
-    unsigned length = length_at (index);
-    if (unlikely (!length)) return hb_ubytes_t ();
-    return hb_ubytes_t (data_base () + offset_at (index) - 1, length);
+    unsigned offset0 = offset_at (index);
+    unsigned offset1 = offset_at (index + 1);
+    if (unlikely (offset1 < offset0 || offset1 > offset_at (count)))
+      return hb_ubytes_t ();
+    return hb_ubytes_t (data_base () + offset0, offset1 - offset0);
   }
 
   unsigned int get_size () const
@@ -197,7 +278,7 @@ struct CFFIndex
                            (count < count + 1u &&
                             c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 &&
                             c->check_array (offsets, offSize, count + 1u) &&
-                            c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count) - 1)))));
+                            c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count))))));
   }
 
   public:
@@ -211,47 +292,6 @@ struct CFFIndex
   DEFINE_SIZE_MIN (COUNT::static_size);
 };
 
-template 
-struct CFFIndexOf : CFFIndex
-{
-  template 
-  bool serialize (hb_serialize_context_t *c,
-                  unsigned int offSize_,
-                  const DATA *dataArray,
-                  unsigned int dataArrayLen,
-                  const hb_vector_t &dataSizeArray,
-                  const PARAM1 ¶m1,
-                  const PARAM2 ¶m2)
-  {
-    TRACE_SERIALIZE (this);
-    /* serialize CFFIndex header */
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    this->count = dataArrayLen;
-    this->offSize = offSize_;
-    if (unlikely (!c->allocate_size (offSize_ * (dataArrayLen + 1), false)))
-      return_trace (false);
-
-    /* serialize indices */
-    unsigned int  offset = 1;
-    unsigned int  i = 0;
-    for (; i < dataArrayLen; i++)
-    {
-      this->set_offset_at (i, offset);
-      offset += dataSizeArray[i];
-    }
-    this->set_offset_at (i, offset);
-
-    /* serialize data */
-    for (unsigned int i = 0; i < dataArrayLen; i++)
-    {
-      TYPE *dest = c->start_embed ();
-      if (unlikely (!dest || !dest->serialize (c, dataArray[i], param1, param2)))
-        return_trace (false);
-    }
-    return_trace (true);
-  }
-};
-
 /* Top Dict, Font Dict, Private Dict */
 struct Dict : UnsizedByteStr
 {
@@ -327,7 +367,7 @@ struct table_info_t
 };
 
 template 
-struct FDArray : CFFIndexOf
+struct FDArray : CFFIndex
 {
   template 
   bool serialize (hb_serialize_context_t *c,
@@ -338,7 +378,11 @@ struct FDArray : CFFIndexOf
 
     /* serialize INDEX data */
     hb_vector_t sizes;
+    if (it.is_random_access_iterator)
+      sizes.alloc (hb_len (it));
+
     c->push ();
+    char *data_base = c->head;
     + it
     | hb_map ([&] (const hb_pair_t &_)
     {
@@ -348,10 +392,16 @@ struct FDArray : CFFIndexOf
               })
     | hb_sink (sizes)
     ;
+    unsigned data_size = c->head - data_base;
     c->pop_pack (false);
 
+    if (unlikely (sizes.in_error ())) return_trace (false);
+
+    /* It just happens that the above is packed right after the header below.
+     * Such a hack. */
+
     /* serialize INDEX header */
-    return_trace (CFFIndex::serialize_header (c, hb_iter (sizes)));
+    return_trace (CFFIndex::serialize_header (c, hb_iter (sizes), data_size));
   }
 };
 
@@ -368,8 +418,11 @@ struct FDSelect0 {
     return_trace (true);
   }
 
-  hb_codepoint_t get_fd (hb_codepoint_t glyph) const
-  { return (hb_codepoint_t) fds[glyph]; }
+  unsigned get_fd (hb_codepoint_t glyph) const
+  { return fds[glyph]; }
+
+  hb_pair_t get_fd_range (hb_codepoint_t glyph) const
+  { return {fds[glyph], glyph + 1}; }
 
   unsigned int get_size (unsigned int num_glyphs) const
   { return HBUINT8::static_size * num_glyphs; }
@@ -427,12 +480,20 @@ struct FDSelect3_4
     return +1;
   }
 
-  hb_codepoint_t get_fd (hb_codepoint_t glyph) const
+  unsigned get_fd (hb_codepoint_t glyph) const
   {
     auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range);
     return range ? range->fd : ranges[nRanges () - 1].fd;
   }
 
+  hb_pair_t get_fd_range (hb_codepoint_t glyph) const
+  {
+    auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range);
+    unsigned fd = range ? range->fd : ranges[nRanges () - 1].fd;
+    hb_codepoint_t end = range ? range[1].first : ranges[nRanges () - 1].first;
+    return {fd, end};
+  }
+
   GID_TYPE        &nRanges ()       { return ranges.len; }
   GID_TYPE         nRanges () const { return ranges.len; }
   GID_TYPE       &sentinel ()       { return StructAfter (ranges[nRanges () - 1]); }
@@ -469,7 +530,7 @@ struct FDSelect
     }
   }
 
-  hb_codepoint_t get_fd (hb_codepoint_t glyph) const
+  unsigned get_fd (hb_codepoint_t glyph) const
   {
     if (this == &Null (FDSelect)) return 0;
 
@@ -480,6 +541,18 @@ struct FDSelect
     default:return 0;
     }
   }
+  /* Returns pair of fd and one after last glyph in range. */
+  hb_pair_t get_fd_range (hb_codepoint_t glyph) const
+  {
+    if (this == &Null (FDSelect)) return {0, 1};
+
+    switch (format)
+    {
+    case 0: return u.format0.get_fd_range (glyph);
+    case 3: return u.format3.get_fd_range (glyph);
+    default:return {0, 1};
+    }
+  }
 
   bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
   {
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc
index 505af15e5c572..6fcc8c4658782 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc
@@ -574,11 +574,11 @@ bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h
 
 struct get_seac_param_t
 {
-  get_seac_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff) {}
+  get_seac_param_t (const OT::cff1::accelerator_subset_t *_cff) : cff (_cff) {}
 
   bool has_seac () const { return base && accent; }
 
-  const OT::cff1::accelerator_t *cff;
+  const OT::cff1::accelerator_subset_t *cff;
   hb_codepoint_t  base = 0;
   hb_codepoint_t  accent = 0;
 };
@@ -596,7 +596,7 @@ struct cff1_cs_opset_seac_t : cff1_cs_opset_t= num_glyphs))) return false;
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh
index 60bc308f90cc2..d1310c66fde18 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh
@@ -28,7 +28,7 @@
 #define HB_OT_CFF1_TABLE_HH
 
 #include "hb-ot-cff-common.hh"
-#include "hb-subset-cff1.hh"
+#include "hb-subset-cff-common.hh"
 #include "hb-draw.hh"
 #include "hb-paint.hh"
 
@@ -44,7 +44,7 @@ namespace CFF {
  * CFF -- Compact Font Format (CFF)
  * https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf
  */
-#define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ')
+#define HB_OT_TAG_CFF1 HB_TAG('C','F','F',' ')
 
 #define CFF_UNDEF_SID   CFF_UNDEF_CODE
 
@@ -52,7 +52,6 @@ enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 };
 enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 };
 
 typedef CFFIndex  CFF1Index;
-template  struct CFF1IndexOf : CFFIndexOf {};
 
 typedef CFFIndex CFF1Index;
 typedef CFF1Index          CFF1CharStrings;
@@ -110,6 +109,7 @@ struct Encoding1 {
 
   hb_codepoint_t get_code (hb_codepoint_t glyph) const
   {
+    /* TODO: Add cache like get_sid. */
     assert (glyph > 0);
     glyph--;
     for (unsigned int i = 0; i < nRanges (); i++)
@@ -173,11 +173,7 @@ struct Encoding
   bool serialize (hb_serialize_context_t *c, const Encoding &src)
   {
     TRACE_SERIALIZE (this);
-    unsigned int size = src.get_size ();
-    Encoding *dest = c->allocate_size (size);
-    if (unlikely (!dest)) return_trace (false);
-    hb_memcpy (dest, &src, size);
-    return_trace (true);
+    return_trace (c->embed (src));
   }
 
   /* serialize a subset Encoding */
@@ -312,26 +308,29 @@ struct Encoding
 };
 
 /* Charset */
-struct Charset0 {
-  bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const
+struct Charset0
+{
+  bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs, unsigned *num_charset_entries) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c));
+    if (num_charset_entries) *num_charset_entries = num_glyphs;
+    return_trace (sids.sanitize (c, num_glyphs - 1));
   }
 
   hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const
   {
     if (unlikely (glyph >= num_glyphs)) return 0;
-    if (glyph == 0)
+    if (unlikely (glyph == 0))
       return 0;
     else
       return sids[glyph - 1];
   }
 
-  void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const
+  void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
   {
+    mapping->resize (num_glyphs, false);
     for (hb_codepoint_t gid = 1; gid < num_glyphs; gid++)
-      mapping->set (gid, sids[gid - 1]);
+      mapping->arrayZ[gid] = {sids[gid - 1], gid};
   }
 
   hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const
@@ -347,13 +346,13 @@ struct Charset0 {
     return 0;
   }
 
-  unsigned int get_size (unsigned int num_glyphs) const
+  static unsigned int get_size (unsigned int num_glyphs)
   {
     assert (num_glyphs > 0);
-    return HBUINT16::static_size * (num_glyphs - 1);
+    return UnsizedArrayOf::get_size (num_glyphs - 1);
   }
 
-  HBUINT16  sids[HB_VAR_ARRAY];
+  UnsizedArrayOf sids;
 
   DEFINE_SIZE_ARRAY(0, sids);
 };
@@ -374,38 +373,62 @@ struct Charset_Range {
 
 template 
 struct Charset1_2 {
-  bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const
+  bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs, unsigned *num_charset_entries) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
       return_trace (false);
     num_glyphs--;
-    for (unsigned int i = 0; num_glyphs > 0; i++)
+    unsigned i;
+    for (i = 0; num_glyphs > 0; i++)
     {
       if (unlikely (!ranges[i].sanitize (c) || (num_glyphs < ranges[i].nLeft + 1)))
         return_trace (false);
       num_glyphs -= (ranges[i].nLeft + 1);
     }
+    if (num_charset_entries)
+      *num_charset_entries = i;
     return_trace (true);
   }
 
-  hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const
+  hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs,
+                          code_pair_t *cache = nullptr) const
   {
     if (unlikely (glyph >= num_glyphs)) return 0;
-    if (glyph == 0) return 0;
-    glyph--;
-    for (unsigned int i = 0;; i++)
+    unsigned i;
+    hb_codepoint_t start_glyph;
+    if (cache && likely (cache->glyph <= glyph))
     {
-      if (glyph <= ranges[i].nLeft)
-        return (hb_codepoint_t) ranges[i].first + glyph;
-      glyph -= (ranges[i].nLeft + 1);
+      i = cache->code;
+      start_glyph = cache->glyph;
+    }
+    else
+    {
+      if (unlikely (glyph == 0)) return 0;
+      i = 0;
+      start_glyph = 1;
+    }
+    glyph -= start_glyph;
+    for (;; i++)
+    {
+      unsigned count = ranges[i].nLeft;
+      if (glyph <= count)
+      {
+        if (cache)
+          *cache = {i, start_glyph};
+        return ranges[i].first + glyph;
+      }
+      count++;
+      start_glyph += count;
+      glyph -= count;
     }
 
     return 0;
   }
 
-  void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const
+  void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
   {
+    mapping->resize (num_glyphs, false);
     hb_codepoint_t gid = 1;
     if (gid >= num_glyphs)
       return;
@@ -413,8 +436,9 @@ struct Charset1_2 {
     {
       hb_codepoint_t sid = ranges[i].first;
       unsigned count = ranges[i].nLeft + 1;
+      unsigned last = gid + count;
       for (unsigned j = 0; j < count; j++)
-        mapping->set (gid++, sid++);
+        mapping->arrayZ[gid++] = {sid++, last - 1};
 
       if (gid >= num_glyphs)
         break;
@@ -439,21 +463,26 @@ struct Charset1_2 {
 
   unsigned int get_size (unsigned int num_glyphs) const
   {
-    unsigned int size = HBUINT8::static_size;
-    int glyph = (int)num_glyphs;
+    int glyph = (int) num_glyphs;
+    unsigned num_ranges = 0;
 
     assert (glyph > 0);
     glyph--;
     for (unsigned int i = 0; glyph > 0; i++)
     {
       glyph -= (ranges[i].nLeft + 1);
-      size += Charset_Range::static_size;
+      num_ranges++;
     }
 
-    return size;
+    return get_size_for_ranges (num_ranges);
+  }
+
+  static unsigned int get_size_for_ranges (unsigned int num_ranges)
+  {
+    return UnsizedArrayOf >::get_size (num_ranges);
   }
 
-  Charset_Range   ranges[HB_VAR_ARRAY];
+  UnsizedArrayOf> ranges;
 
   DEFINE_SIZE_ARRAY (0, ranges);
 };
@@ -469,11 +498,7 @@ struct Charset
   bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
-    unsigned int size = src.get_size (num_glyphs);
-    Charset *dest = c->allocate_size (size);
-    if (unlikely (!dest)) return_trace (false);
-    hb_memcpy (dest, &src, size);
-    return_trace (true);
+    return_trace (c->embed ((const char *) &src, src.get_size (num_glyphs)));
   }
 
   /* serialize a subset Charset */
@@ -490,13 +515,13 @@ struct Charset
     {
     case 0:
     {
-      Charset0 *fmt0 = c->allocate_size (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1));
+      Charset0 *fmt0 = c->allocate_size (Charset0::get_size (num_glyphs), false);
       if (unlikely (!fmt0)) return_trace (false);
       unsigned int glyph = 0;
       for (unsigned int i = 0; i < sid_ranges.length; i++)
       {
-        hb_codepoint_t sid = sid_ranges[i].code;
-        for (int left = (int)sid_ranges[i].glyph; left >= 0; left--)
+        hb_codepoint_t sid = sid_ranges.arrayZ[i].code;
+        for (int left = (int)sid_ranges.arrayZ[i].glyph; left >= 0; left--)
           fmt0->sids[glyph++] = sid++;
       }
     }
@@ -504,29 +529,35 @@ struct Charset
 
     case 1:
     {
-      Charset1 *fmt1 = c->allocate_size (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length);
+      Charset1 *fmt1 = c->allocate_size (Charset1::get_size_for_ranges (sid_ranges.length), false);
       if (unlikely (!fmt1)) return_trace (false);
+      hb_codepoint_t all_glyphs = 0;
       for (unsigned int i = 0; i < sid_ranges.length; i++)
       {
-        if (unlikely (!(sid_ranges[i].glyph <= 0xFF)))
-          return_trace (false);
-        fmt1->ranges[i].first = sid_ranges[i].code;
-        fmt1->ranges[i].nLeft = sid_ranges[i].glyph;
+        auto &_ = sid_ranges.arrayZ[i];
+        all_glyphs |= _.glyph;
+        fmt1->ranges[i].first = _.code;
+        fmt1->ranges[i].nLeft = _.glyph;
       }
+      if (unlikely (!(all_glyphs <= 0xFF)))
+        return_trace (false);
     }
     break;
 
     case 2:
     {
-      Charset2 *fmt2 = c->allocate_size (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length);
+      Charset2 *fmt2 = c->allocate_size (Charset2::get_size_for_ranges (sid_ranges.length), false);
       if (unlikely (!fmt2)) return_trace (false);
+      hb_codepoint_t all_glyphs = 0;
       for (unsigned int i = 0; i < sid_ranges.length; i++)
       {
-        if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF)))
-          return_trace (false);
-        fmt2->ranges[i].first = sid_ranges[i].code;
-        fmt2->ranges[i].nLeft = sid_ranges[i].glyph;
+        auto &_ = sid_ranges.arrayZ[i];
+        all_glyphs |= _.glyph;
+        fmt2->ranges[i].first = _.code;
+        fmt2->ranges[i].nLeft = _.glyph;
       }
+      if (unlikely (!(all_glyphs <= 0xFFFF)))
+        return_trace (false);
     }
     break;
 
@@ -545,18 +576,19 @@ struct Charset
     }
   }
 
-  hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs) const
+  hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs,
+                          code_pair_t *cache = nullptr) const
   {
     switch (format)
     {
     case 0: return u.format0.get_sid (glyph, num_glyphs);
-    case 1: return u.format1.get_sid (glyph, num_glyphs);
-    case 2: return u.format2.get_sid (glyph, num_glyphs);
+    case 1: return u.format1.get_sid (glyph, num_glyphs, cache);
+    case 2: return u.format2.get_sid (glyph, num_glyphs, cache);
     default:return 0;
     }
   }
 
-  void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const
+  void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
   {
     switch (format)
     {
@@ -578,7 +610,7 @@ struct Charset
     }
   }
 
-  bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c, unsigned *num_charset_entries) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
@@ -586,9 +618,9 @@ struct Charset
 
     switch (format)
     {
-    case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs ()));
-    case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs ()));
-    case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs ()));
+    case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs (), num_charset_entries));
+    case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs (), num_charset_entries));
+    case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs (), num_charset_entries));
     default:return_trace (false);
     }
   }
@@ -606,10 +638,10 @@ struct Charset
 struct CFF1StringIndex : CFF1Index
 {
   bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings,
-                  const hb_inc_bimap_t &sidmap)
+                  const hb_vector_t &sidmap)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely ((strings.count == 0) || (sidmap.get_population () == 0)))
+    if (unlikely ((strings.count == 0) || (sidmap.length == 0)))
     {
       if (unlikely (!c->extend_min (this->count)))
         return_trace (false);
@@ -617,15 +649,13 @@ struct CFF1StringIndex : CFF1Index
       return_trace (true);
     }
 
-    byte_str_array_t bytesArray;
-    if (!bytesArray.resize (sidmap.get_population ()))
-      return_trace (false);
-    for (unsigned int i = 0; i < strings.count; i++)
-    {
-      hb_codepoint_t  j = sidmap[i];
-      if (j != HB_MAP_VALUE_INVALID)
-        bytesArray[j] = strings[i];
-    }
+    if (unlikely (sidmap.in_error ())) return_trace (false);
+
+    // Save this in a vector since serialize() iterates it twice.
+    hb_vector_t bytesArray (+ hb_iter (sidmap)
+                                         | hb_map (strings));
+
+    if (unlikely (bytesArray.in_error ())) return_trace (false);
 
     bool result = CFF1Index::serialize (c, bytesArray);
     return_trace (result);
@@ -932,7 +962,7 @@ struct cff1_private_dict_opset_t : dict_opset_t
   }
 };
 
-struct cff1_private_dict_opset_subset : dict_opset_t
+struct cff1_private_dict_opset_subset_t : dict_opset_t
 {
   static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_subset_t& dictval)
   {
@@ -978,7 +1008,7 @@ typedef dict_interpreter_t cff1_font_dict_interpreter_t;
 
 typedef CFF1Index CFF1NameIndex;
-typedef CFF1IndexOf CFF1TopDictIndex;
+typedef CFF1Index CFF1TopDictIndex;
 
 struct cff1_font_dict_values_mod_t
 {
@@ -1019,7 +1049,7 @@ using namespace CFF;
 
 struct cff1
 {
-  static constexpr hb_tag_t tableTag = HB_OT_TAG_cff1;
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF1;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -1031,8 +1061,12 @@ struct cff1
   template 
   struct accelerator_templ_t
   {
-    void init (hb_face_t *face)
+    static constexpr hb_tag_t tableTag = cff1::tableTag;
+
+    accelerator_templ_t (hb_face_t *face)
     {
+      if (!face) return;
+
       topDict.init ();
       fontDicts.init ();
       privateDicts.init ();
@@ -1046,22 +1080,22 @@ struct cff1
       const OT::cff1 *cff = this->blob->template as ();
 
       if (cff == &Null (OT::cff1))
-      { fini (); return; }
+        goto fail;
 
       nameIndex = &cff->nameIndex (cff);
       if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc))
-      { fini (); return; }
+        goto fail;
 
       topDictIndex = &StructAtOffset (nameIndex, nameIndex->get_size ());
       if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0))
-      { fini (); return; }
+        goto fail;
 
       { /* parse top dict */
         const hb_ubytes_t topDictStr = (*topDictIndex)[0];
-        if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
+        if (unlikely (!topDictStr.sanitize (&sc)))   goto fail;
         cff1_top_dict_interp_env_t env (topDictStr);
         cff1_top_dict_interpreter_t top_interp (env);
-        if (unlikely (!top_interp.interpret (topDict))) { fini (); return; }
+        if (unlikely (!top_interp.interpret (topDict)))   goto fail;
       }
 
       if (is_predef_charset ())
@@ -1069,7 +1103,7 @@ struct cff1
       else
       {
         charset = &StructAtOffsetOrNull (cff, topDict.CharsetOffset);
-        if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc))) { fini (); return; }
+        if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc, &num_charset_entries)))   goto fail;
       }
 
       fdCount = 1;
@@ -1079,7 +1113,7 @@ struct cff1
         fdSelect = &StructAtOffsetOrNull (cff, topDict.FDSelectOffset);
         if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) ||
             (fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
-        { fini (); return; }
+          goto fail;
 
         fdCount = fdArray->count;
       }
@@ -1092,36 +1126,36 @@ struct cff1
       encoding = &Null (Encoding);
       if (is_CID ())
       {
-        if (unlikely (charset == &Null (Charset))) { fini (); return; }
+        if (unlikely (charset == &Null (Charset)))   goto fail;
       }
       else
       {
         if (!is_predef_encoding ())
         {
           encoding = &StructAtOffsetOrNull (cff, topDict.EncodingOffset);
-          if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; }
+          if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc)))   goto fail;
         }
       }
 
       stringIndex = &StructAtOffset (topDictIndex, topDictIndex->get_size ());
       if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc))
-      { fini (); return; }
+        goto fail;
 
       globalSubrs = &StructAtOffset (stringIndex, stringIndex->get_size ());
       if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc))
-      { fini (); return; }
+        goto fail;
 
       charStrings = &StructAtOffsetOrNull (cff, topDict.charStringsOffset);
 
       if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
-      { fini (); return; }
+        goto fail;
 
       num_glyphs = charStrings->count;
       if (num_glyphs != sc.get_num_glyphs ())
-      { fini (); return; }
+        goto fail;
 
       if (unlikely (!privateDicts.resize (fdCount)))
-      { fini (); return; }
+        goto fail;
       for (unsigned int i = 0; i < fdCount; i++)
         privateDicts[i].init ();
 
@@ -1131,27 +1165,27 @@ struct cff1
         for (unsigned int i = 0; i < fdCount; i++)
         {
           hb_ubytes_t fontDictStr = (*fdArray)[i];
-          if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
+          if (unlikely (!fontDictStr.sanitize (&sc)))   goto fail;
           cff1_font_dict_values_t *font;
           cff1_top_dict_interp_env_t env (fontDictStr);
           cff1_font_dict_interpreter_t font_interp (env);
           font = fontDicts.push ();
-          if (unlikely (fontDicts.in_error ())) { fini (); return; }
+          if (unlikely (fontDicts.in_error ()))   goto fail;
 
           font->init ();
-          if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
+          if (unlikely (!font_interp.interpret (*font)))   goto fail;
           PRIVDICTVAL *priv = &privateDicts[i];
           const hb_ubytes_t privDictStr = StructAtOffset (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
-          if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
+          if (unlikely (!privDictStr.sanitize (&sc)))   goto fail;
           num_interp_env_t env2 (privDictStr);
           dict_interpreter_t priv_interp (env2);
           priv->init ();
-          if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
+          if (unlikely (!priv_interp.interpret (*priv)))   goto fail;
 
           priv->localSubrs = &StructAtOffsetOrNull (&privDictStr, priv->subrsOffset);
           if (priv->localSubrs != &Null (CFF1Subrs) &&
               unlikely (!priv->localSubrs->sanitize (&sc)))
-          { fini (); return; }
+            goto fail;
         }
       }
       else  /* non-CID */
@@ -1160,20 +1194,25 @@ struct cff1
         PRIVDICTVAL *priv = &privateDicts[0];
 
         const hb_ubytes_t privDictStr = StructAtOffset (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
-        if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
+        if (unlikely (!privDictStr.sanitize (&sc)))   goto fail;
         num_interp_env_t env (privDictStr);
         dict_interpreter_t priv_interp (env);
         priv->init ();
-        if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
+        if (unlikely (!priv_interp.interpret (*priv)))   goto fail;
 
         priv->localSubrs = &StructAtOffsetOrNull (&privDictStr, priv->subrsOffset);
         if (priv->localSubrs != &Null (CFF1Subrs) &&
             unlikely (!priv->localSubrs->sanitize (&sc)))
-        { fini (); return; }
+          goto fail;
       }
-    }
 
-    void fini ()
+      return;
+
+      fail:
+        _fini ();
+    }
+    ~accelerator_templ_t () { _fini (); }
+    void _fini ()
     {
       sc.end_processing ();
       topDict.fini ();
@@ -1183,6 +1222,8 @@ struct cff1
       blob = nullptr;
     }
 
+    hb_blob_t *get_blob () const { return blob; }
+
     bool is_valid () const { return blob; }
     bool   is_CID () const { return topDict.is_CID (); }
 
@@ -1203,13 +1244,14 @@ struct cff1
 
     bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; }
 
-    hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const
+    hb_codepoint_t glyph_to_code (hb_codepoint_t glyph,
+                                  code_pair_t *glyph_to_sid_cache = nullptr) const
     {
       if (encoding != &Null (Encoding))
         return encoding->get_code (glyph);
       else
       {
-        hb_codepoint_t sid = glyph_to_sid (glyph);
+        hb_codepoint_t sid = glyph_to_sid (glyph, glyph_to_sid_cache);
         if (sid == 0) return 0;
         hb_codepoint_t code = 0;
         switch (topDict.EncodingOffset)
@@ -1227,12 +1269,14 @@ struct cff1
       }
     }
 
-    hb_map_t *create_glyph_to_sid_map () const
+    glyph_to_sid_map_t *create_glyph_to_sid_map () const
     {
       if (charset != &Null (Charset))
       {
-        hb_map_t *mapping = hb_map_create ();
-        mapping->set (0, 0);
+        auto *mapping = (glyph_to_sid_map_t *) hb_malloc (sizeof (glyph_to_sid_map_t));
+        if (unlikely (!mapping)) return nullptr;
+        mapping = new (mapping) glyph_to_sid_map_t ();
+        mapping->push (code_pair_t {0, 1});
         charset->collect_glyph_to_sid_map (mapping, num_glyphs);
         return mapping;
       }
@@ -1240,10 +1284,11 @@ struct cff1
         return nullptr;
     }
 
-    hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const
+    hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph,
+                                 code_pair_t *cache = nullptr) const
     {
       if (charset != &Null (Charset))
-        return charset->get_sid (glyph, num_glyphs);
+        return charset->get_sid (glyph, num_glyphs, cache);
       else
       {
         hb_codepoint_t sid = 0;
@@ -1312,19 +1357,17 @@ struct cff1
     hb_vector_t privateDicts;
 
     unsigned int             num_glyphs = 0;
+    unsigned int             num_charset_entries = 0;
   };
 
   struct accelerator_t : accelerator_templ_t
   {
-    accelerator_t (hb_face_t *face)
+    accelerator_t (hb_face_t *face) : SUPER (face)
     {
-      SUPER::init (face);
-
       glyph_names.set_relaxed (nullptr);
 
       if (!is_valid ()) return;
       if (is_CID ()) return;
-
     }
     ~accelerator_t ()
     {
@@ -1334,8 +1377,6 @@ struct cff1
         names->fini ();
         hb_free (names);
       }
-
-      SUPER::fini ();
     }
 
     bool get_glyph_name (hb_codepoint_t glyph,
@@ -1386,9 +1427,10 @@ struct cff1
           /* TODO */
 
           /* fill glyph names */
+          code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID};
           for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
           {
-            hb_codepoint_t      sid = glyph_to_sid (gid);
+            hb_codepoint_t      sid = glyph_to_sid (gid, &glyph_to_sid_cache);
             gname_t     gname;
             gname.sid = sid;
             if (sid < cff1_std_strings_length)
@@ -1426,7 +1468,6 @@ struct cff1
 
     HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
     HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const;
-    HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
     HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
 
     private:
@@ -1453,9 +1494,24 @@ struct cff1
     typedef accelerator_templ_t SUPER;
   };
 
-  struct accelerator_subset_t : accelerator_templ_t {};
+  struct accelerator_subset_t : accelerator_templ_t
+  {
+    accelerator_subset_t (hb_face_t *face) : SUPER (face) {}
+    ~accelerator_subset_t ()
+    {
+      if (cff_accelerator)
+        cff_subset_accelerator_t::destroy (cff_accelerator);
+    }
 
-  bool subset (hb_subset_context_t *c) const { return hb_subset_cff1 (c); }
+    HB_INTERNAL bool subset (hb_subset_context_t *c) const;
+    HB_INTERNAL bool serialize (hb_serialize_context_t *c,
+                                struct cff1_subset_plan &plan) const;
+    HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
+
+    mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr;
+
+    typedef accelerator_templ_t SUPER;
+  };
 
   protected:
   HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid);
@@ -1479,6 +1535,10 @@ struct cff1_accelerator_t : cff1::accelerator_t {
   cff1_accelerator_t (hb_face_t *face) : cff1::accelerator_t (face) {}
 };
 
+struct cff1_subset_accelerator_t : cff1::accelerator_subset_t {
+  cff1_subset_accelerator_t (hb_face_t *face) : cff1::accelerator_subset_t (face) {}
+};
+
 } /* namespace OT */
 
 #endif /* HB_OT_CFF1_TABLE_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh
index bfbc26b96ec43..db10f22ec52e6 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh
@@ -28,7 +28,7 @@
 #define HB_OT_CFF2_TABLE_HH
 
 #include "hb-ot-cff-common.hh"
-#include "hb-subset-cff2.hh"
+#include "hb-subset-cff-common.hh"
 #include "hb-draw.hh"
 #include "hb-paint.hh"
 
@@ -38,10 +38,9 @@ namespace CFF {
  * CFF2 -- Compact Font Format (CFF) Version 2
  * https://docs.microsoft.com/en-us/typography/opentype/spec/cff2
  */
-#define HB_OT_TAG_cff2 HB_TAG('C','F','F','2')
+#define HB_OT_TAG_CFF2 HB_TAG('C','F','F','2')
 
 typedef CFFIndex  CFF2Index;
-template  struct CFF2IndexOf : CFFIndexOf {};
 
 typedef CFF2Index         CFF2CharStrings;
 typedef Subrs   CFF2Subrs;
@@ -379,7 +378,7 @@ using namespace CFF;
 
 struct cff2
 {
-  static constexpr hb_tag_t tableTag = HB_OT_TAG_cff2;
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF2;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -391,8 +390,12 @@ struct cff2
   template 
   struct accelerator_templ_t
   {
+    static constexpr hb_tag_t tableTag = cff2::tableTag;
+
     accelerator_templ_t (hb_face_t *face)
     {
+      if (!face) return;
+
       topDict.init ();
       fontDicts.init ();
       privateDicts.init ();
@@ -464,7 +467,6 @@ struct cff2
           goto fail;
       }
 
-
       return;
 
       fail:
@@ -481,11 +483,13 @@ struct cff2
       blob = nullptr;
     }
 
-    hb_map_t *create_glyph_to_sid_map () const
+    hb_vector_t *create_glyph_to_sid_map () const
     {
       return nullptr;
     }
 
+    hb_blob_t *get_blob () const { return blob; }
+
     bool is_valid () const { return blob; }
 
     protected:
@@ -518,9 +522,24 @@ struct cff2
     HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
   };
 
-  typedef accelerator_templ_t accelerator_subset_t;
+  struct accelerator_subset_t : accelerator_templ_t
+  {
+    accelerator_subset_t (hb_face_t *face) : SUPER (face) {}
+    ~accelerator_subset_t ()
+    {
+      if (cff_accelerator)
+        cff_subset_accelerator_t::destroy (cff_accelerator);
+    }
+
+    HB_INTERNAL bool subset (hb_subset_context_t *c) const;
+    HB_INTERNAL bool serialize (hb_serialize_context_t *c,
+                                struct cff2_subset_plan &plan,
+                                hb_array_t normalized_coords) const;
+
+    mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr;
 
-  bool subset (hb_subset_context_t *c) const { return hb_subset_cff2 (c); }
+    typedef accelerator_templ_t SUPER;
+  };
 
   public:
   FixedVersion         version;        /* Version of CFF2 table. set to 0x0200u */
@@ -535,6 +554,10 @@ struct cff2_accelerator_t : cff2::accelerator_t {
   cff2_accelerator_t (hb_face_t *face) : cff2::accelerator_t (face) {}
 };
 
+struct cff2_subset_accelerator_t : cff2::accelerator_subset_t {
+  cff2_subset_accelerator_t (hb_face_t *face) : cff2::accelerator_subset_t (face) {}
+};
+
 } /* namespace OT */
 
 #endif /* HB_OT_CFF2_TABLE_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh
index eb1dd2bc0d184..7e6ced3df4c0d 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh
@@ -277,10 +277,10 @@ struct CmapSubtableFormat4
       }
     } writer(c);
 
-    writer.end_code_ = c->allocate_size (HBUINT16::static_size * segcount);
-    c->allocate_size (2); // padding
-    writer.start_code_ = c->allocate_size (HBUINT16::static_size * segcount);
-    writer.id_delta_ = c->allocate_size (HBINT16::static_size * segcount);
+    writer.end_code_ = c->allocate_size (HBUINT16::static_size * segcount, false);
+    (void) c->allocate_size (2); // padding
+    writer.start_code_ = c->allocate_size (HBUINT16::static_size * segcount, false);
+    writer.id_delta_ = c->allocate_size (HBINT16::static_size * segcount, false);
 
     if (unlikely (!writer.end_code_ || !writer.start_code_ || !writer.id_delta_)) return false;
 
@@ -325,7 +325,7 @@ struct CmapSubtableFormat4
   {
     auto format4_iter =
     + it
-    | hb_filter ([&] (const hb_pair_t _)
+    | hb_filter ([&] (const hb_codepoint_pair_t _)
                  { return _.first <= 0xFFFF; })
     ;
 
@@ -335,7 +335,7 @@ struct CmapSubtableFormat4
     if (unlikely (!c->extend_min (this))) return;
     this->format = 4;
 
-    hb_vector_t> cp_to_gid {
+    hb_vector_t cp_to_gid {
       format4_iter
     };
 
@@ -757,8 +757,7 @@ struct CmapSubtableLongSegmented
       hb_codepoint_t gid = this->groups[i].glyphID;
       if (!gid)
       {
-        /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */
-        if (! T::group_get_glyph (this->groups[i], end)) continue;
+        if (T::formatNumber == 13) continue;
         start++;
         gid++;
       }
@@ -766,11 +765,13 @@ struct CmapSubtableLongSegmented
       if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
         end = start + (hb_codepoint_t) num_glyphs - gid;
 
+      mapping->alloc (mapping->get_population () + end - start + 1);
+
       for (unsigned cp = start; cp <= end; cp++)
       {
         unicodes->add (cp);
         mapping->set (cp, gid);
-        gid++;
+        gid += T::increment;
       }
     }
   }
@@ -794,6 +795,9 @@ struct CmapSubtableLongSegmented
 
 struct CmapSubtableFormat12 : CmapSubtableLongSegmented
 {
+  static constexpr int increment = 1;
+  static constexpr int formatNumber = 12;
+
   static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
                                          hb_codepoint_t u)
   { return likely (group.startCharCode <= group.endCharCode) ?
@@ -866,6 +870,9 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented
 
 struct CmapSubtableFormat13 : CmapSubtableLongSegmented
 {
+  static constexpr int increment = 0;
+  static constexpr int formatNumber = 13;
+
   static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
                                          hb_codepoint_t u HB_UNUSED)
   { return group.glyphID; }
@@ -917,8 +924,7 @@ struct DefaultUVS : SortedArray32Of
   DefaultUVS* copy (hb_serialize_context_t *c,
                     const hb_set_t *unicodes) const
   {
-    DefaultUVS *out = c->start_embed ();
-    if (unlikely (!out)) return nullptr;
+    auto *out = c->start_embed ();
     auto snap = c->snapshot ();
 
     HBUINT32 len;
@@ -931,8 +937,7 @@ struct DefaultUVS : SortedArray32Of
       hb_codepoint_t start = HB_SET_VALUE_INVALID;
       hb_codepoint_t end = HB_SET_VALUE_INVALID;
 
-      for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
-           unicodes->next (&u);)
+      for (auto u : *unicodes)
       {
         if (!as_array ().bsearch (u))
           continue;
@@ -1067,9 +1072,7 @@ struct NonDefaultUVS : SortedArray32Of
                        const hb_set_t *glyphs_requested,
                        const hb_map_t *glyph_map) const
   {
-    NonDefaultUVS *out = c->start_embed ();
-    if (unlikely (!out)) return nullptr;
-
+    auto *out = c->start_embed ();
     auto it =
     + as_array ()
     | hb_filter ([&] (const UVSMapping& _)
@@ -1767,7 +1770,6 @@ struct cmap
     TRACE_SUBSET (this);
 
     cmap *cmap_prime = c->serializer->start_embed ();
-    if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false);
 
     auto encodingrec_iter =
     + hb_iter (encodingRecord)
@@ -1798,7 +1800,7 @@ struct cmap
 
     auto it =
     + c->plan->unicode_to_new_gid_list.iter ()
-    | hb_filter ([&] (const hb_pair_t _)
+    | hb_filter ([&] (const hb_codepoint_pair_t _)
                  { return (_.second != HB_MAP_VALUE_INVALID); })
     ;
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc
index 884cea0f6b3da..deec909b22e79 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc
@@ -38,8 +38,8 @@
 
 #include "hb-ot-cmap-table.hh"
 #include "hb-ot-glyf-table.hh"
-#include "hb-ot-cff1-table.hh"
 #include "hb-ot-cff2-table.hh"
+#include "hb-ot-cff1-table.hh"
 #include "hb-ot-hmtx-table.hh"
 #include "hb-ot-post-table.hh"
 #include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
@@ -64,13 +64,17 @@
 using hb_ot_font_cmap_cache_t    = hb_cache_t<21, 16, 8, true>;
 using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>;
 
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
 static hb_user_data_key_t hb_ot_font_cmap_cache_user_data_key;
+#endif
 
 struct hb_ot_font_t
 {
   const hb_ot_face_t *ot_face;
 
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
   hb_ot_font_cmap_cache_t *cmap_cache;
+#endif
 
   /* h_advance caching */
   mutable hb_atomic_int_t cached_coords_serial;
@@ -86,6 +90,7 @@ _hb_ot_font_create (hb_font_t *font)
 
   ot_font->ot_face = &font->face->table;
 
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
   // retry:
   auto *cmap_cache  = (hb_ot_font_cmap_cache_t *) hb_face_get_user_data (font->face,
                                                                          &hb_ot_font_cmap_cache_user_data_key);
@@ -93,7 +98,7 @@ _hb_ot_font_create (hb_font_t *font)
   {
     cmap_cache = (hb_ot_font_cmap_cache_t *) hb_malloc (sizeof (hb_ot_font_cmap_cache_t));
     if (unlikely (!cmap_cache)) goto out;
-    cmap_cache->init ();
+    new (cmap_cache) hb_ot_font_cmap_cache_t ();
     if (unlikely (!hb_face_set_user_data (font->face,
                                           &hb_ot_font_cmap_cache_user_data_key,
                                           cmap_cache,
@@ -112,6 +117,7 @@ _hb_ot_font_create (hb_font_t *font)
   }
   out:
   ot_font->cmap_cache = cmap_cache;
+#endif
 
   return ot_font;
 }
@@ -136,7 +142,11 @@ hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
 {
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   const hb_ot_face_t *ot_face = ot_font->ot_face;
-  return ot_face->cmap->get_nominal_glyph (unicode, glyph, ot_font->cmap_cache);
+  hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+  cmap_cache = ot_font->cmap_cache;
+#endif
+  return ot_face->cmap->get_nominal_glyph (unicode, glyph, cmap_cache);
 }
 
 static unsigned int
@@ -151,10 +161,14 @@ hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
 {
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   const hb_ot_face_t *ot_face = ot_font->ot_face;
+  hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+  cmap_cache = ot_font->cmap_cache;
+#endif
   return ot_face->cmap->get_nominal_glyphs (count,
                                             first_unicode, unicode_stride,
                                             first_glyph, glyph_stride,
-                                            ot_font->cmap_cache);
+                                            cmap_cache);
 }
 
 static hb_bool_t
@@ -167,9 +181,13 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
 {
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   const hb_ot_face_t *ot_face = ot_font->ot_face;
+  hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+  cmap_cache = ot_font->cmap_cache;
+#endif
   return ot_face->cmap->get_variation_glyph (unicode,
                                              variation_selector, glyph,
-                                             ot_font->cmap_cache);
+                                             cmap_cache);
 }
 
 static void
@@ -188,7 +206,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
 
   hb_position_t *orig_first_advance = first_advance;
 
-#ifndef HB_NO_VAR
+#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
   const OT::HVAR &HVAR = *hmtx.var_table;
   const OT::VariationStore &varStore = &HVAR + HVAR.varStore;
   OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
@@ -212,8 +230,8 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
         use_cache = false;
         goto out;
       }
+      new (cache) hb_ot_font_advance_cache_t;
 
-      cache->init ();
       if (unlikely (!ot_font->advance_cache.cmpexch (nullptr, cache)))
       {
         hb_free (cache);
@@ -237,7 +255,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
   { /* Use cache. */
     if (ot_font->cached_coords_serial.get_acquire () != (int) font->serial_coords)
     {
-      ot_font->advance_cache->init ();
+      ot_font->advance_cache->clear ();
       ot_font->cached_coords_serial.set_release (font->serial_coords);
     }
 
@@ -258,7 +276,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
     }
   }
 
-#ifndef HB_NO_VAR
+#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
   OT::VariationStore::destroy_cache (varStore_cache);
 #endif
 
@@ -293,7 +311,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
 
   if (vmtx.has_data ())
   {
-#ifndef HB_NO_VAR
+#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
     const OT::VVAR &VVAR = *vmtx.var_table;
     const OT::VariationStore &varStore = &VVAR + VVAR.varStore;
     OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
@@ -308,7 +326,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
       first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride);
     }
 
-#ifndef HB_NO_VAR
+#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
     OT::VariationStore::destroy_cache (varStore_cache);
 #endif
   }
@@ -418,8 +436,8 @@ hb_ot_get_glyph_extents (hb_font_t *font,
 #endif
   if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
 #ifndef HB_NO_OT_FONT_CFF
-  if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
   if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
+  if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
 #endif
 
   return false;
@@ -507,8 +525,8 @@ hb_ot_draw_glyph (hb_font_t *font,
                                     embolden ? &outline : draw_data, font->slant_xy);
     if (!font->face->table.glyf->get_path (font, glyph, draw_session))
 #ifndef HB_NO_CFF
-    if (!font->face->table.cff1->get_path (font, glyph, draw_session))
     if (!font->face->table.cff2->get_path (font, glyph, draw_session))
+    if (!font->face->table.cff1->get_path (font, glyph, draw_session))
 #endif
     {}
   }
@@ -547,8 +565,8 @@ hb_ot_paint_glyph (hb_font_t *font,
 #endif
   if (font->face->table.glyf->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
 #ifndef HB_NO_CFF
-  if (font->face->table.cff1->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
   if (font->face->table.cff2->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
+  if (font->face->table.cff1->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
 #endif
 }
 #endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh
index e13321ee6fa1a..77e68dbca42ef 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh
@@ -46,21 +46,23 @@ struct DeviceRecord
 
   template
-  bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it)
+  bool serialize (hb_serialize_context_t *c,
+                  unsigned pixelSize,
+                  Iterator it,
+                  const hb_vector_t new_to_old_gid_list,
+                  unsigned num_glyphs)
   {
     TRACE_SERIALIZE (this);
 
-    unsigned length = it.len ();
-
-    if (unlikely (!c->extend (this, length)))  return_trace (false);
+    if (unlikely (!c->extend (this, num_glyphs)))  return_trace (false);
 
     this->pixelSize = pixelSize;
     this->maxWidth =
     + it
     | hb_reduce (hb_max, 0u);
 
-    + it
-    | hb_sink (widthsZ.as_array (length));
+    for (auto &_ : new_to_old_gid_list)
+      widthsZ[_.first] = *it++;
 
     return_trace (true);
   }
@@ -89,7 +91,11 @@ struct hdmx
 
   template
-  bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it)
+  bool serialize (hb_serialize_context_t *c,
+                  unsigned version,
+                  Iterator it,
+                  const hb_vector_t &new_to_old_gid_list,
+                  unsigned num_glyphs)
   {
     TRACE_SERIALIZE (this);
 
@@ -97,10 +103,10 @@ struct hdmx
 
     this->version = version;
     this->numRecords = it.len ();
-    this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0);
+    this->sizeDeviceRecord = DeviceRecord::get_size (num_glyphs);
 
     for (const hb_item_type& _ : +it)
-      c->start_embed ()->serialize (c, _.first, _.second);
+      c->start_embed ()->serialize (c, _.first, _.second, new_to_old_gid_list, num_glyphs);
 
     return_trace (c->successful ());
   }
@@ -110,31 +116,30 @@ struct hdmx
   {
     TRACE_SUBSET (this);
 
-    hdmx *hdmx_prime = c->serializer->start_embed  ();
-    if (unlikely (!hdmx_prime)) return_trace (false);
+    auto *hdmx_prime = c->serializer->start_embed  ();
 
+    unsigned num_input_glyphs = get_num_glyphs ();
     auto it =
     + hb_range ((unsigned) numRecords)
-    | hb_map ([c, this] (unsigned _)
+    | hb_map ([c, num_input_glyphs, this] (unsigned _)
         {
           const DeviceRecord *device_record =
             &StructAtOffset (&firstDeviceRecord,
                                            _ * sizeDeviceRecord);
           auto row =
-            + hb_range (c->plan->num_output_glyphs ())
-            | hb_map (c->plan->reverse_glyph_map)
-            | hb_map ([this, c, device_record] (hb_codepoint_t _)
+            + hb_iter (c->plan->new_to_old_gid_list)
+            | hb_map ([num_input_glyphs, device_record] (hb_codepoint_pair_t _)
                       {
-                        if (c->plan->is_empty_glyph (_))
-                          return Null (HBUINT8);
-                        return device_record->widthsZ.as_array (get_num_glyphs ()) [_];
+                        return device_record->widthsZ.as_array (num_input_glyphs) [_.second];
                       })
             ;
           return hb_pair ((unsigned) device_record->pixelSize, +row);
         })
     ;
 
-    hdmx_prime->serialize (c->serializer, version, it);
+    hdmx_prime->serialize (c->serializer, version, it,
+                           c->plan->new_to_old_gid_list,
+                           c->plan->num_output_glyphs ());
     return_trace (true);
   }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh
index e830fd09cf0da..39e1f4830a588 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh
@@ -83,7 +83,7 @@ struct hmtxvmtx
   bool subset_update_header (hb_subset_context_t *c,
                              unsigned int num_hmetrics,
                              const hb_hashmap_t> *mtx_map,
-                             const hb_map_t *bounds_map) const
+                             const hb_vector_t &bounds_vec) const
   {
     hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table (c->plan->source, H::tableTag);
     hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob);
@@ -114,6 +114,7 @@ struct hmtxvmtx
         HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET,   caretOffset);
       }
 
+      bool empty = true;
       int min_lsb = 0x7FFF;
       int min_rsb = 0x7FFF;
       int max_extent = -0x7FFF;
@@ -125,9 +126,10 @@ struct hmtxvmtx
         int lsb = _.second.second;
         max_adv = hb_max (max_adv, adv);
 
-        if (bounds_map->has (gid))
+        if (bounds_vec[gid] != 0xFFFFFFFF)
         {
-          unsigned bound_width = bounds_map->get (gid);
+          empty = false;
+          unsigned bound_width = bounds_vec[gid];
           int rsb = adv - lsb - bound_width;
           int extent = lsb + bound_width;
           min_lsb = hb_min (min_lsb, lsb);
@@ -137,7 +139,7 @@ struct hmtxvmtx
       }
 
       table->advanceMax = max_adv;
-      if (!bounds_map->is_empty ())
+      if (!empty)
       {
         table->minLeadingBearing = min_lsb;
         table->minTrailingBearing = min_rsb;
@@ -156,32 +158,32 @@ struct hmtxvmtx
            hb_requires (hb_is_iterator (Iterator))>
   void serialize (hb_serialize_context_t *c,
                   Iterator it,
-                  unsigned num_long_metrics)
+                  const hb_vector_t new_to_old_gid_list,
+                  unsigned num_long_metrics,
+                  unsigned total_num_metrics)
   {
-    unsigned idx = 0;
-    for (auto _ : it)
+    LongMetric* long_metrics = c->allocate_size (num_long_metrics * LongMetric::static_size);
+    FWORD* short_metrics = c->allocate_size ((total_num_metrics - num_long_metrics) * FWORD::static_size);
+    if (!long_metrics || !short_metrics) return;
+
+    short_metrics -= num_long_metrics;
+
+    for (auto _ : new_to_old_gid_list)
     {
-      if (idx < num_long_metrics)
-      {
-        LongMetric lm;
-        lm.advance = _.first;
-        lm.sb = _.second;
-        if (unlikely (!c->embed (&lm))) return;
-      }
-      else if (idx < 0x10000u)
+      hb_codepoint_t gid = _.first;
+      auto mtx = *it++;
+
+      if (gid < num_long_metrics)
       {
-        FWORD *sb = c->allocate_size (FWORD::static_size);
-        if (unlikely (!sb)) return;
-        *sb = _.second;
+        LongMetric& lm = long_metrics[gid];
+        lm.advance = mtx.first;
+        lm.sb = mtx.second;
       }
+      // TODO(beyond-64k): This assumes that maxp.numGlyphs is 0xFFFF.
+      else if (gid < 0x10000u)
+        short_metrics[gid] = mtx.second;
       else
-      {
-        // TODO: This does not do tail optimization.
-        UFWORD *adv = c->allocate_size (UFWORD::static_size);
-        if (unlikely (!adv)) return;
-        *adv = _.first;
-      }
-      idx++;
+        ((UFWORD*) short_metrics)[gid] = mtx.first;
     }
   }
 
@@ -189,8 +191,7 @@ struct hmtxvmtx
   {
     TRACE_SUBSET (this);
 
-    T *table_prime = c->serializer->start_embed  ();
-    if (unlikely (!table_prime)) return_trace (false);
+    auto *table_prime = c->serializer->start_embed  ();
 
     accelerator_t _mtx (c->plan->source);
     unsigned num_long_metrics;
@@ -199,6 +200,8 @@ struct hmtxvmtx
       /* Determine num_long_metrics to encode. */
       auto& plan = c->plan;
 
+      // TODO Don't consider retaingid holes here.
+
       num_long_metrics = hb_min (plan->num_output_glyphs (), 0xFFFFu);
       unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx);
       while (num_long_metrics > 1 &&
@@ -209,31 +212,36 @@ struct hmtxvmtx
     }
 
     auto it =
-    + hb_range (c->plan->num_output_glyphs ())
-    | hb_map ([c, &_mtx, mtx_map] (unsigned _)
+    + hb_iter (c->plan->new_to_old_gid_list)
+    | hb_map ([c, &_mtx, mtx_map] (hb_codepoint_pair_t _)
               {
-                if (!mtx_map->has (_))
+                hb_codepoint_t new_gid = _.first;
+                hb_codepoint_t old_gid = _.second;
+
+                hb_pair_t *v = nullptr;
+                if (!mtx_map->has (new_gid, &v))
                 {
-                  hb_codepoint_t old_gid;
-                  if (!c->plan->old_gid_for_new_gid (_, &old_gid))
-                    return hb_pair (0u, 0);
                   int lsb = 0;
                   if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb))
                     (void) _glyf_get_leading_bearing_without_var_unscaled (c->plan->source, old_gid, !T::is_horizontal, &lsb);
                   return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
                 }
-                return mtx_map->get (_);
+                return *v;
               })
     ;
 
-    table_prime->serialize (c->serializer, it, num_long_metrics);
+    table_prime->serialize (c->serializer,
+                            it,
+                            c->plan->new_to_old_gid_list,
+                            num_long_metrics,
+                            c->plan->num_output_glyphs ());
 
     if (unlikely (c->serializer->in_error ()))
       return_trace (false);
 
     // Amend header num hmetrics
     if (unlikely (!subset_update_header (c, num_long_metrics, mtx_map,
-                                         T::is_horizontal ? &c->plan->bounds_width_map : &c->plan->bounds_height_map)))
+                                         T::is_horizontal ? c->plan->bounds_width_vec : c->plan->bounds_height_vec)))
       return_trace (false);
 
     return_trace (true);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh
index bcf12221619f9..0e57a6c790994 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh
@@ -170,8 +170,8 @@ struct FeatMinMaxRecord
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
-                          minCoord.sanitize (c, this) &&
-                          maxCoord.sanitize (c, this)));
+                          minCoord.sanitize (c, base) &&
+                          maxCoord.sanitize (c, base)));
   }
 
   protected:
@@ -187,7 +187,6 @@ struct FeatMinMaxRecord
                                  * of MinMax table (may be NULL) */
   public:
   DEFINE_SIZE_STATIC (8);
-
 };
 
 struct MinMax
@@ -274,7 +273,7 @@ struct BaseLangSysRecord
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
-                          minMax.sanitize (c, this)));
+                          minMax.sanitize (c, base)));
   }
 
   protected:
@@ -297,7 +296,8 @@ struct BaseScript
   const BaseCoord &get_base_coord (int baseline_tag_index) const
   { return (this+baseValues).get_base_coord (baseline_tag_index); }
 
-  bool has_data () const { return baseValues; }
+  bool has_values () const { return baseValues; }
+  bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -383,7 +383,7 @@ struct Axis
                      const BaseCoord **coord) const
   {
     const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
-    if (!base_script.has_data ())
+    if (!base_script.has_values ())
     {
       *coord = nullptr;
       return false;
@@ -410,7 +410,7 @@ struct Axis
                     const BaseCoord **max_coord) const
   {
     const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
-    if (!base_script.has_data ())
+    if (!base_script.has_min_max ())
     {
       *min_coord = *max_coord = nullptr;
       return false;
@@ -425,8 +425,8 @@ struct Axis
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
-                          (this+baseTagList).sanitize (c) &&
-                          (this+baseScriptList).sanitize (c)));
+                          baseTagList.sanitize (c, this) &&
+                          baseScriptList.sanitize (c, this)));
   }
 
   protected:
@@ -473,14 +473,13 @@ struct BASE
     return true;
   }
 
-  /* TODO: Expose this separately sometime? */
   bool get_min_max (hb_font_t      *font,
                     hb_direction_t  direction,
                     hb_tag_t        script_tag,
                     hb_tag_t        language_tag,
                     hb_tag_t        feature_tag,
                     hb_position_t  *min,
-                    hb_position_t  *max)
+                    hb_position_t  *max) const
   {
     const BaseCoord *min_coord, *max_coord;
     if (!get_axis (direction).get_min_max (script_tag, language_tag, feature_tag,
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh
index 1ff697b1b632d..9216a9a0fe70f 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh
@@ -55,19 +55,22 @@ static bool ClassDef_remap_and_serialize (
     hb_serialize_context_t *c,
     const hb_set_t &klasses,
     bool use_class_zero,
-    hb_sorted_vector_t> &glyph_and_klass, /* IN/OUT */
+    hb_sorted_vector_t &glyph_and_klass, /* IN/OUT */
     hb_map_t *klass_map /*IN/OUT*/);
 
 struct hb_collect_feature_substitutes_with_var_context_t
 {
   const hb_map_t *axes_index_tag_map;
-  const hb_hashmap_t *axes_location;
+  const hb_hashmap_t *axes_location;
   hb_hashmap_t> *record_cond_idx_map;
   hb_hashmap_t *feature_substitutes_map;
+  bool& insert_catch_all_feature_variation_record;
 
   // not stored in subset_plan
   hb_set_t *feature_indices;
   bool apply;
+  bool variation_applied;
+  bool universal;
   unsigned cur_record_idx;
   hb_hashmap_t, unsigned> *conditionset_map;
 };
@@ -188,27 +191,15 @@ struct hb_collect_variation_indices_context_t :
   static return_t default_return_value () { return hb_empty_t (); }
 
   hb_set_t *layout_variation_indices;
-  hb_hashmap_t> *varidx_delta_map;
-  hb_font_t *font;
-  const VariationStore *var_store;
   const hb_set_t *glyph_set;
   const hb_map_t *gpos_lookups;
-  float *store_cache;
 
   hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_,
-                                          hb_hashmap_t> *varidx_delta_map_,
-                                          hb_font_t *font_,
-                                          const VariationStore *var_store_,
                                           const hb_set_t *glyph_set_,
-                                          const hb_map_t *gpos_lookups_,
-                                          float *store_cache_) :
+                                          const hb_map_t *gpos_lookups_) :
                                         layout_variation_indices (layout_variation_indices_),
-                                        varidx_delta_map (varidx_delta_map_),
-                                        font (font_),
-                                        var_store (var_store_),
                                         glyph_set (glyph_set_),
-                                        gpos_lookups (gpos_lookups_),
-                                        store_cache (store_cache_) {}
+                                        gpos_lookups (gpos_lookups_) {}
 };
 
 template
@@ -807,7 +798,7 @@ struct Feature
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
     out->featureParams.serialize_subset (c, featureParams, this, tag);
 
@@ -981,7 +972,7 @@ struct RecordListOfFeature : RecordListOf
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
     + hb_enumerate (*this)
     | hb_filter (l->feature_index_map, hb_first)
@@ -1078,7 +1069,7 @@ struct LangSys
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
     const uint32_t *v;
     out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu;
@@ -1188,7 +1179,7 @@ struct Script
       return false;
 
     auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
     bool defaultLang = false;
     if (has_default_lang_sys ())
@@ -1247,7 +1238,7 @@ struct RecordListOfScript : RecordListOf