diff --git a/.github/actions/config/action.yml b/.github/actions/config/action.yml
index 5f648ffc022..931988accc3 100644
--- a/.github/actions/config/action.yml
+++ b/.github/actions/config/action.yml
@@ -41,6 +41,6 @@ runs:
id: read-config
run: |
# Extract value from configuration file
- value="$(grep -h ${{ inputs.var }}= make/conf/github-actions.conf | cut -d '=' -f 2-)"
+ value="$(grep -h '^${{ inputs.var }}'= make/conf/github-actions.conf | cut -d '=' -f 2-)"
echo "value=$value" >> $GITHUB_OUTPUT
shell: bash
diff --git a/.github/actions/upload-bundles/action.yml b/.github/actions/upload-bundles/action.yml
index b35ee3a42e9..4e974ae58ba 100644
--- a/.github/actions/upload-bundles/action.yml
+++ b/.github/actions/upload-bundles/action.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
@@ -45,6 +45,7 @@ runs:
jdk_bundle_tar_gz="$(ls build/*/bundles/jdk-*_bin${{ inputs.debug-suffix }}.tar.gz 2> /dev/null || true)"
symbols_bundle="$(ls build/*/bundles/jdk-*_bin${{ inputs.debug-suffix }}-symbols.tar.gz 2> /dev/null || true)"
tests_bundle="$(ls build/*/bundles/jdk-*_bin-tests${{ inputs.debug-suffix }}.tar.gz 2> /dev/null || true)"
+ static_libs_bundle="$(ls build/*/bundles/jdk-*_bin-static-libs${{ inputs.debug-suffix }}.tar.gz 2> /dev/null || true)"
mkdir bundles
@@ -60,8 +61,11 @@ runs:
if [[ "$tests_bundle" != "" ]]; then
mv "$tests_bundle" "bundles/tests-${{ inputs.platform }}${{ inputs.debug-suffix }}.tar.gz"
fi
+ if [[ "$static_libs_bundle" != "" ]]; then
+ mv "$static_libs_bundle" "bundles/static-libs-${{ inputs.platform }}${{ inputs.debug-suffix }}.tar.gz"
+ fi
- if [[ "$jdk_bundle_zip$jdk_bundle_tar_gz$symbols_bundle$tests_bundle" != "" ]]; then
+ if [[ "$jdk_bundle_zip$jdk_bundle_tar_gz$symbols_bundle$tests_bundle$static_libs_bundle" != "" ]]; then
echo 'bundles-found=true' >> $GITHUB_OUTPUT
else
echo 'bundles-found=false' >> $GITHUB_OUTPUT
diff --git a/.github/scripts/gen-build-failure-report.sh b/.github/scripts/gen-build-failure-report.sh
index fd3215fc7fe..2dda69a3f33 100644
--- a/.github/scripts/gen-build-failure-report.sh
+++ b/.github/scripts/gen-build-failure-report.sh
@@ -24,12 +24,19 @@
# questions.
#
+# Import common utils
+. .github/scripts/report-utils.sh
+
GITHUB_STEP_SUMMARY="$1"
BUILD_DIR="$(ls -d build/*)"
# Send signal to the do-build action that we failed
touch "$BUILD_DIR/build-failure"
+# Collect hs_errs for build-time crashes, e.g. javac, jmod, jlink, CDS.
+# These usually land in make/
+hs_err_files=$(ls make/hs_err*.log 2> /dev/null || true)
+
(
echo '### :boom: Build failure summary'
echo ''
@@ -46,6 +53,20 @@ touch "$BUILD_DIR/build-failure"
echo ''
echo ''
+ for hs_err in $hs_err_files; do
+ echo "View HotSpot error log: "$hs_err" "
+ echo ''
+ echo '```'
+ echo "$hs_err:"
+ echo ''
+ cat "$hs_err"
+ echo '```'
+ echo ' '
+ echo ''
+ done
+
echo ''
echo ':arrow_right: To see the entire test log, click the job in the list to the left. To download logs, see the `failure-logs` [artifact above](#artifacts).'
) >> $GITHUB_STEP_SUMMARY
+
+truncate_summary
diff --git a/.github/scripts/gen-test-results.sh b/.github/scripts/gen-test-results.sh
index 9e85eef4dc0..bdf3eb3b9cb 100644
--- a/.github/scripts/gen-test-results.sh
+++ b/.github/scripts/gen-test-results.sh
@@ -24,6 +24,9 @@
# questions.
#
+# Import common utils
+. .github/scripts/report-utils.sh
+
GITHUB_STEP_SUMMARY="$1"
test_suite_name=$(cat build/run-test-prebuilt/test-support/test-last-ids.txt)
@@ -89,18 +92,6 @@ for test in $failures $errors; do
fi
done >> $GITHUB_STEP_SUMMARY
-# With many failures, the summary can easily exceed 1024 kB, the limit set by Github
-# Trim it down if so.
-summary_size=$(wc -c < $GITHUB_STEP_SUMMARY)
-if [[ $summary_size -gt 1000000 ]]; then
- # Trim to below 1024 kB, and cut off after the last detail group
- head -c 1000000 $GITHUB_STEP_SUMMARY | tac | sed -n -e '/<\/details>/,$ p' | tac > $GITHUB_STEP_SUMMARY.tmp
- mv $GITHUB_STEP_SUMMARY.tmp $GITHUB_STEP_SUMMARY
- (
- echo ''
- echo ':x: **WARNING: Summary is too large and has been truncated.**'
- echo ''
- ) >> $GITHUB_STEP_SUMMARY
-fi
-
echo ':arrow_right: To see the entire test log, click the job in the list to the left.' >> $GITHUB_STEP_SUMMARY
+
+truncate_summary
diff --git a/.github/scripts/report-utils.sh b/.github/scripts/report-utils.sh
new file mode 100644
index 00000000000..da5b6c04b3c
--- /dev/null
+++ b/.github/scripts/report-utils.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+#
+# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+function truncate_summary() {
+ # With large hs_errs, the summary can easily exceed 1024 kB, the limit set by Github
+ # Trim it down if so.
+ summary_size=$(wc -c < $GITHUB_STEP_SUMMARY)
+ if [[ $summary_size -gt 1000000 ]]; then
+ # Trim to below 1024 kB, and cut off after the last detail group
+ head -c 1000000 $GITHUB_STEP_SUMMARY | tac | sed -n -e '/<\/details>/,$ p' | tac > $GITHUB_STEP_SUMMARY.tmp
+ mv $GITHUB_STEP_SUMMARY.tmp $GITHUB_STEP_SUMMARY
+ (
+ echo ''
+ echo ':x: **WARNING: Summary is too large and has been truncated.**'
+ echo ''
+ ) >> $GITHUB_STEP_SUMMARY
+ fi
+}
diff --git a/.github/workflows/build-alpine-linux.yml b/.github/workflows/build-alpine-linux.yml
new file mode 100644
index 00000000000..ac5870ca675
--- /dev/null
+++ b/.github/workflows/build-alpine-linux.yml
@@ -0,0 +1,112 @@
+#
+# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+name: 'Build (alpine-linux)'
+
+on:
+ workflow_call:
+ inputs:
+ platform:
+ required: true
+ type: string
+ extra-conf-options:
+ required: false
+ type: string
+ make-target:
+ required: false
+ type: string
+ default: 'product-bundles test-bundles'
+ debug-levels:
+ required: false
+ type: string
+ default: '[ "debug", "release" ]'
+ apk-extra-packages:
+ required: false
+ type: string
+ configure-arguments:
+ required: false
+ type: string
+ make-arguments:
+ required: false
+ type: string
+
+jobs:
+ build-linux:
+ name: build
+ runs-on: ubuntu-22.04
+ container:
+ image: alpine:3.20
+
+ strategy:
+ fail-fast: false
+ matrix:
+ debug-level: ${{ fromJSON(inputs.debug-levels) }}
+ include:
+ - debug-level: debug
+ flags: --with-debug-level=fastdebug
+ suffix: -debug+
+
+ steps:
+ - name: 'Checkout the JDK source'
+ uses: actions/checkout@v4
+
+ - name: 'Install toolchain and dependencies'
+ run: |
+ apk update
+ apk add alpine-sdk alsa-lib-dev autoconf bash cups-dev cups-libs fontconfig-dev freetype-dev grep libx11-dev libxext-dev libxrandr-dev libxrender-dev libxt-dev libxtst-dev linux-headers wget zip ${{ inputs.apk-extra-packages }}
+
+ - name: 'Get the BootJDK'
+ id: bootjdk
+ uses: ./.github/actions/get-bootjdk
+ with:
+ platform: alpine-linux-x64
+
+ - name: 'Configure'
+ run: >
+ bash configure
+ --with-conf-name=${{ inputs.platform }}
+ ${{ matrix.flags }}
+ --with-version-opt=${GITHUB_ACTOR}-${GITHUB_SHA}
+ --with-boot-jdk=${{ steps.bootjdk.outputs.path }}
+ --with-zlib=system
+ --with-jmod-compress=zip-1
+ ${{ inputs.extra-conf-options }} ${{ inputs.configure-arguments }} || (
+ echo "Dumping config.log:" &&
+ cat config.log &&
+ exit 1)
+
+ - name: 'Build'
+ id: build
+ uses: ./.github/actions/do-build
+ with:
+ make-target: '${{ inputs.make-target }} ${{ inputs.make-arguments }}'
+ platform: ${{ inputs.platform }}
+ debug-suffix: '${{ matrix.suffix }}'
+
+ - name: 'Upload bundles'
+ uses: ./.github/actions/upload-bundles
+ with:
+ platform: ${{ inputs.platform }}
+ debug-suffix: '${{ matrix.suffix }}'
diff --git a/.github/workflows/build-cross-compile.yml b/.github/workflows/build-cross-compile.yml
index fa5a8a61a0a..8e97ff4439f 100644
--- a/.github/workflows/build-cross-compile.yml
+++ b/.github/workflows/build-cross-compile.yml
@@ -131,6 +131,7 @@ jobs:
id: create-sysroot
run: >
sudo debootstrap
+ --no-merged-usr
--arch=${{ matrix.debian-arch }}
--verbose
--include=fakeroot,symlinks,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype-dev,libpng-dev
@@ -151,6 +152,9 @@ jobs:
rm -rf sysroot/usr/{sbin,bin,share}
rm -rf sysroot/usr/lib/{apt,gcc,udev,systemd}
rm -rf sysroot/usr/libexec/gcc
+ # /{bin,sbin,lib}/ are not symbolic links to /usr/{bin,sbin,lib}/ when debootstrap with --no-merged-usr
+ rm -rf sysroot/{sbin,bin}
+ rm -rf sysroot/lib/{udev,systemd}
if: steps.create-sysroot.outcome == 'success' && steps.get-cached-sysroot.outputs.cache-hit != 'true'
- name: 'Remove broken sysroot'
diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml
index f3ea4e4fb6a..b1d4278f8b4 100644
--- a/.github/workflows/build-linux.yml
+++ b/.github/workflows/build-linux.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
@@ -133,8 +133,12 @@ jobs:
- name: 'Build'
id: build
uses: ./.github/actions/do-build
+ env:
+ # Only build static-libs-bundles for release builds.
+ # For debug builds, building static-libs often exceeds disk space.
+ STATIC_LIBS: ${{ matrix.debug-level == 'release' && 'static-libs-bundles' }}
with:
- make-target: '${{ inputs.make-target }} ${{ inputs.make-arguments }}'
+ make-target: '${{ inputs.make-target }} ${STATIC_LIBS} ${{ inputs.make-arguments }}'
platform: ${{ inputs.platform }}
debug-suffix: '${{ matrix.suffix }}'
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 067548b9768..d5958853701 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -36,7 +36,7 @@ on:
platforms:
description: 'Platform(s) to execute on (comma separated, e.g. "linux-x64, macos, aarch64")'
required: true
- default: 'linux-x64, linux-x86, linux-x64-variants, linux-cross-compile, macos-x64, macos-aarch64, windows-x64, windows-aarch64, docs'
+ default: 'linux-x64, linux-x86-hs, linux-x64-variants, linux-cross-compile, alpine-linux-x64, macos-x64, macos-aarch64, windows-x64, windows-aarch64, docs'
configure-arguments:
description: 'Additional configure arguments'
required: false
@@ -57,11 +57,15 @@ jobs:
select:
name: 'Select platforms'
runs-on: ubuntu-22.04
+ env:
+ # List of platforms to exclude by default
+ EXCLUDED_PLATFORMS: 'alpine-linux-x64'
outputs:
linux-x64: ${{ steps.include.outputs.linux-x64 }}
- linux-x86: ${{ steps.include.outputs.linux-x86 }}
+ linux-x86-hs: ${{ steps.include.outputs.linux-x86-hs }}
linux-x64-variants: ${{ steps.include.outputs.linux-x64-variants }}
linux-cross-compile: ${{ steps.include.outputs.linux-cross-compile }}
+ alpine-linux-x64: ${{ steps.include.outputs.alpine-linux-x64 }}
macos-x64: ${{ steps.include.outputs.macos-x64 }}
macos-aarch64: ${{ steps.include.outputs.macos-aarch64 }}
windows-x64: ${{ steps.include.outputs.windows-x64 }}
@@ -78,6 +82,10 @@ jobs:
# Returns 'true' if the input platform list matches any of the platform monikers given as argument,
# 'false' otherwise.
# arg $1: platform name or names to look for
+
+ # Convert EXCLUDED_PLATFORMS from a comma-separated string to an array
+ IFS=',' read -r -a excluded_array <<< "$EXCLUDED_PLATFORMS"
+
function check_platform() {
if [[ $GITHUB_EVENT_NAME == workflow_dispatch ]]; then
input='${{ github.event.inputs.platforms }}'
@@ -94,7 +102,13 @@ jobs:
normalized_input="$(echo ,$input, | tr -d ' ')"
if [[ "$normalized_input" == ",," ]]; then
- # For an empty input, assume all platforms should run
+ # For an empty input, assume all platforms should run, except those in the EXCLUDED_PLATFORMS list
+ for excluded in "${excluded_array[@]}"; do
+ if [[ "$1" == "$excluded" ]]; then
+ echo 'false'
+ return
+ fi
+ done
echo 'true'
return
else
@@ -105,15 +119,24 @@ jobs:
return
fi
done
+
+ # If not explicitly included, check against the EXCLUDED_PLATFORMS list
+ for excluded in "${excluded_array[@]}"; do
+ if [[ "$1" == "$excluded" ]]; then
+ echo 'false'
+ return
+ fi
+ done
fi
echo 'false'
}
echo "linux-x64=$(check_platform linux-x64 linux x64)" >> $GITHUB_OUTPUT
- echo "linux-x86=$(check_platform linux-x86 linux x86)" >> $GITHUB_OUTPUT
+ echo "linux-x86-hs=$(check_platform linux-x86-hs linux x86)" >> $GITHUB_OUTPUT
echo "linux-x64-variants=$(check_platform linux-x64-variants variants)" >> $GITHUB_OUTPUT
echo "linux-cross-compile=$(check_platform linux-cross-compile cross-compile)" >> $GITHUB_OUTPUT
+ echo "alpine-linux-x64=$(check_platform alpine-linux-x64 alpine-linux x64)" >> $GITHUB_OUTPUT
echo "macos-x64=$(check_platform macos-x64 macos x64)" >> $GITHUB_OUTPUT
echo "macos-aarch64=$(check_platform macos-aarch64 macos aarch64)" >> $GITHUB_OUTPUT
echo "windows-x64=$(check_platform windows-x64 windows x64)" >> $GITHUB_OUTPUT
@@ -135,12 +158,13 @@ jobs:
make-arguments: ${{ github.event.inputs.make-arguments }}
if: needs.select.outputs.linux-x64 == 'true'
- build-linux-x86:
- name: linux-x86
+ build-linux-x86-hs:
+ name: linux-x86-hs
needs: select
uses: ./.github/workflows/build-linux.yml
with:
platform: linux-x86
+ make-target: 'hotspot'
gcc-major-version: '10'
gcc-package-suffix: '-multilib'
apt-architecture: 'i386'
@@ -150,7 +174,7 @@ jobs:
extra-conf-options: '--with-target-bits=32 --enable-fallback-linker --enable-libffi-bundling'
configure-arguments: ${{ github.event.inputs.configure-arguments }}
make-arguments: ${{ github.event.inputs.make-arguments }}
- if: needs.select.outputs.linux-x86 == 'true'
+ if: needs.select.outputs.linux-x86-hs == 'true'
build-linux-x64-hs-nopch:
name: linux-x64-hs-nopch
@@ -220,6 +244,16 @@ jobs:
make-arguments: ${{ github.event.inputs.make-arguments }}
if: needs.select.outputs.linux-cross-compile == 'true'
+ build-alpine-linux-x64:
+ name: alpine-linux-x64
+ needs: select
+ uses: ./.github/workflows/build-alpine-linux.yml
+ with:
+ platform: alpine-linux-x64
+ configure-arguments: ${{ github.event.inputs.configure-arguments }}
+ make-arguments: ${{ github.event.inputs.make-arguments }}
+ if: needs.select.outputs.alpine-linux-x64 == 'true'
+
build-macos-x64:
name: macos-x64
needs: select
@@ -300,16 +334,6 @@ jobs:
bootjdk-platform: linux-x64
runs-on: ubuntu-22.04
- test-linux-x86:
- name: linux-x86
- needs:
- - build-linux-x86
- uses: ./.github/workflows/test.yml
- with:
- platform: linux-x86
- bootjdk-platform: linux-x64
- runs-on: ubuntu-22.04
-
test-macos-x64:
name: macos-x64
needs:
@@ -347,42 +371,40 @@ jobs:
if: always()
needs:
- build-linux-x64
- - build-linux-x86
+ - build-linux-x86-hs
- build-linux-x64-hs-nopch
- build-linux-x64-hs-zero
- build-linux-x64-hs-minimal
- build-linux-x64-hs-optimized
- build-linux-cross-compile
+ - build-alpine-linux-x64
- build-macos-x64
- build-macos-aarch64
- build-windows-x64
- build-windows-aarch64
- test-linux-x64
- - test-linux-x86
- test-macos-x64
+ - test-macos-aarch64
- test-windows-x64
steps:
- # Hack to get hold of the api environment variables that are only defined for actions
- - name: 'Get API configuration'
- id: api
- uses: actions/github-script@v7
- with:
- script: 'return { url: process.env["ACTIONS_RUNTIME_URL"], token: process.env["ACTIONS_RUNTIME_TOKEN"] }'
-
- name: 'Remove bundle artifacts'
run: |
# Find and remove all bundle artifacts
- ALL_ARTIFACT_URLS="$(curl -s \
- -H 'Accept: application/json;api-version=6.0-preview' \
- -H 'Authorization: Bearer ${{ fromJson(steps.api.outputs.result).token }}' \
- '${{ fromJson(steps.api.outputs.result).url }}_apis/pipelines/workflows/${{ github.run_id }}/artifacts?api-version=6.0-preview')"
- BUNDLE_ARTIFACT_URLS="$(echo "$ALL_ARTIFACT_URLS" | jq -r -c '.value | map(select(.name|startswith("bundles-"))) | .[].url')"
- for url in $BUNDLE_ARTIFACT_URLS; do
- echo "Removing $url"
- curl -s \
- -H 'Accept: application/json;api-version=6.0-preview' \
- -H 'Authorization: Bearer ${{ fromJson(steps.api.outputs.result).token }}' \
- -X DELETE "$url" \
+ # See: https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28
+ ALL_ARTIFACT_IDS="$(curl -sL \
+ -H 'Accept: application/vnd.github+json' \
+ -H 'Authorization: Bearer ${{ github.token }}' \
+ -H 'X-GitHub-Api-Version: 2022-11-28' \
+ '${{ github.api_url }}/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts?per_page=100')"
+ BUNDLE_ARTIFACT_IDS="$(echo "$ALL_ARTIFACT_IDS" | jq -r -c '.artifacts | map(select(.name|startswith("bundles-"))) | .[].id')"
+ for id in $BUNDLE_ARTIFACT_IDS; do
+ echo "Removing $id"
+ curl -sL \
+ -X DELETE \
+ -H 'Accept: application/vnd.github+json' \
+ -H 'Authorization: Bearer ${{ github.token }}' \
+ -H 'X-GitHub-Api-Version: 2022-11-28' \
+ "${{ github.api_url }}/repos/${{ github.repository }}/actions/artifacts/$id" \
|| echo "Failed to remove bundle"
done
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 00000000000..f4c5e7e67cb
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,3 @@
+# JDK Vulnerabilities
+
+Please follow the process outlined in the [OpenJDK Vulnerability Policy](https://openjdk.org/groups/vulnerability/report) to disclose vulnerabilities in the JDK.
diff --git a/doc/building.html b/doc/building.html
index 70753155312..c91d876246c 100644
--- a/doc/building.html
+++ b/doc/building.html
@@ -614,10 +614,9 @@
clang
--with-toolchain-type=clang
.
Apple Xcode
The oldest supported version of Xcode is 13.0.
-You will need the Xcode command line developer tools to be able to
-build the JDK. (Actually, only the command line tools are
-needed, not the IDE.) The simplest way to install these is to run:
-xcode-select --install
+You will need to download Xcode either from the App Store or specific
+versions can be easily located via the Xcode Releases website.
When updating Xcode, it is advisable to keep an older version for
building the JDK. To use a specific version of Xcode you have multiple
options:
diff --git a/doc/building.md b/doc/building.md
index 51ac0cad7d9..47ad9e7c72b 100644
--- a/doc/building.md
+++ b/doc/building.md
@@ -422,13 +422,9 @@ To use clang instead of gcc on Linux, use `--with-toolchain-type=clang`.
The oldest supported version of Xcode is 13.0.
-You will need the Xcode command line developer tools to be able to build the
-JDK. (Actually, *only* the command line tools are needed, not the IDE.) The
-simplest way to install these is to run:
-
-```
-xcode-select --install
-```
+You will need to download Xcode either from the App Store or specific versions
+can be easily located via the [Xcode Releases](https://xcodereleases.com)
+website.
When updating Xcode, it is advisable to keep an older version for building the
JDK. To use a specific version of Xcode you have multiple options:
diff --git a/doc/testing.html b/doc/testing.html
index c56dfa31188..b74661b3924 100644
--- a/doc/testing.html
+++ b/doc/testing.html
@@ -434,7 +434,7 @@ FAILURE_HANDLER_TIMEOUT
Sets the argument -timeoutHandlerTimeout
for JTReg. The
default value is 0. This is only valid if the failure handler is
built.
-JTREG_TEST_THREAD_FACTORY
+TEST_THREAD_FACTORY
Sets the -testThreadFactory
for JTReg. It should be the
fully qualified classname of a class which implements
java.util.concurrent.ThreadFactory
. One such implementation
diff --git a/doc/testing.md b/doc/testing.md
index 351745c9293..cdc9bbd2182 100644
--- a/doc/testing.md
+++ b/doc/testing.md
@@ -380,7 +380,7 @@ Defaults to 4.
Sets the argument `-timeoutHandlerTimeout` for JTReg. The default value is 0.
This is only valid if the failure handler is built.
-#### JTREG_TEST_THREAD_FACTORY
+#### TEST_THREAD_FACTORY
Sets the `-testThreadFactory` for JTReg. It should be the fully qualified
classname of a class which implements `java.util.concurrent.ThreadFactory`. One
diff --git a/make/Bundles.gmk b/make/Bundles.gmk
index 0901e415a8a..2ed04c19064 100644
--- a/make/Bundles.gmk
+++ b/make/Bundles.gmk
@@ -284,7 +284,7 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), )
ifeq ($(MACOSX_CODESIGN_MODE), hardened)
# Macosx release build and code signing available.
- ################################################################################
+ ############################################################################
# JDK bundle
$(eval $(call SetupCopyFiles, CREATE_JDK_BUNDLE_DIR_SIGNED, \
SRC := $(JDK_IMAGE_DIR), \
@@ -313,7 +313,7 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), )
PRODUCT_TARGETS += $(BUILD_JDK_BUNDLE)
- ################################################################################
+ ############################################################################
# JRE bundle
$(eval $(call SetupCopyFiles, CREATE_JRE_BUNDLE_DIR_SIGNED, \
SRC := $(JRE_IMAGE_DIR), \
diff --git a/make/CompileInterimLangtools.gmk b/make/CompileInterimLangtools.gmk
index 1a8b6382f81..dbb23de093c 100644
--- a/make/CompileInterimLangtools.gmk
+++ b/make/CompileInterimLangtools.gmk
@@ -65,7 +65,7 @@ $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.compiler.interim/javax/tools/ToolProvider.ja
$(SED) $(INTERIM_TOOL_PROVIDER_PATTERN) $< > $@
java.compiler.interim_EXTRA_FILES := \
- $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.compiler.interim/javax/tools/ToolProvider.java
+ $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.compiler.interim/javax/tools/ToolProvider.java
TARGETS += $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.compiler.interim/javax/tools/ToolProvider.java
diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk
index b1b7a83498d..62c91ee5f78 100644
--- a/make/CompileJavaModules.gmk
+++ b/make/CompileJavaModules.gmk
@@ -75,12 +75,12 @@ $(JDK_OUTPUTDIR)/modules/%_zh_HK.properties: $(JDK_OUTPUTDIR)/modules/%_zh_TW.pr
CreateHkTargets = \
$(call FilterExcludedTranslations, \
- $(patsubst $(TOPDIR)/src/%, $(JDK_OUTPUTDIR)/modules/%, \
- $(subst /share/classes,, \
- $(subst _zh_TW,_zh_HK, $(filter %_zh_TW.properties, $1)) \
- ) \
- ), \
- .properties \
+ $(patsubst $(TOPDIR)/src/%, $(JDK_OUTPUTDIR)/modules/%, \
+ $(subst /share/classes,, \
+ $(subst _zh_TW,_zh_HK, $(filter %_zh_TW.properties, $1)) \
+ ) \
+ ), \
+ .properties \
)
################################################################################
diff --git a/make/CompileToolsJdk.gmk b/make/CompileToolsJdk.gmk
index feba5d8a902..41a19f90ace 100644
--- a/make/CompileToolsJdk.gmk
+++ b/make/CompileToolsJdk.gmk
@@ -52,8 +52,7 @@ $(eval $(call SetupJavaCompilation, BUILD_TOOLS_JDK, \
build/tools/deps \
build/tools/docs \
build/tools/jigsaw \
- build/tools/depend \
- , \
+ build/tools/depend, \
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes, \
DISABLED_WARNINGS := dangling-doc-comments options, \
JAVAC_FLAGS := \
@@ -66,17 +65,19 @@ $(eval $(call SetupJavaCompilation, BUILD_TOOLS_JDK, \
TARGETS += $(BUILD_TOOLS_JDK)
-$(eval $(call SetupCopyFiles,COPY_NIMBUS_TEMPLATES, \
+$(eval $(call SetupCopyFiles, COPY_NIMBUS_TEMPLATES, \
SRC := $(TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus, \
DEST := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/generatenimbus/resources, \
- FILES := $(wildcard $(TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/*.template)))
+ FILES := $(wildcard $(TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/*.template), \
+))
TARGETS += $(COPY_NIMBUS_TEMPLATES)
-$(eval $(call SetupCopyFiles,COPY_CLDRCONVERTER_PROPERTIES, \
+$(eval $(call SetupCopyFiles, COPY_CLDRCONVERTER_PROPERTIES, \
SRC := $(TOPDIR)/make/jdk/src/classes/build/tools/cldrconverter, \
DEST := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/cldrconverter, \
- FILES := $(wildcard $(TOPDIR)/make/jdk/src/classes/build/tools/cldrconverter/*.properties)))
+ FILES := $(wildcard $(TOPDIR)/make/jdk/src/classes/build/tools/cldrconverter/*.properties), \
+))
TARGETS += $(COPY_CLDRCONVERTER_PROPERTIES)
diff --git a/make/CopyInterimTZDB.gmk b/make/CopyInterimTZDB.gmk
index ac390580aa9..e2704b32975 100644
--- a/make/CopyInterimTZDB.gmk
+++ b/make/CopyInterimTZDB.gmk
@@ -30,7 +30,7 @@ include MakeBase.gmk
include CopyFiles.gmk
-##########################################################################################
+################################################################################
### TZDB tool needs files from java.time.zone package
@@ -41,12 +41,13 @@ define tzdb_copyfiles
< $(<) > $@
endef
-$(eval $(call SetupCopyFiles,COPY_INTERIM_TZDB, \
+$(eval $(call SetupCopyFiles, COPY_INTERIM_TZDB, \
SRC := $(TOPDIR)/src/java.base/share/classes/java/time/zone, \
DEST := $(BUILDTOOLS_OUTPUTDIR)/interim_tzdb_classes/build/tools/tzdb, \
FILES := ZoneRules.java ZoneOffsetTransition.java ZoneOffsetTransitionRule.java Ser.java, \
- MACRO := tzdb_copyfiles))
+ MACRO := tzdb_copyfiles, \
+))
-##########################################################################################
+################################################################################
all: $(COPY_INTERIM_TZDB)
diff --git a/make/CreateJmods.gmk b/make/CreateJmods.gmk
index fd36554358b..86bc3b8335e 100644
--- a/make/CreateJmods.gmk
+++ b/make/CreateJmods.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -229,8 +229,21 @@ ifeq ($(INTERIM_JMOD), true)
# Interim JMODs are not shipped anywhere, so there is no reason
# to compress them at all.
JMOD_FLAGS += --compress zip-0
+
+ JMOD_TARGET_OS := $(OPENJDK_BUILD_OS)
+ ifeq ($(JMOD_TARGET_OS), macosx)
+ JMOD_TARGET_OS := macos
+ endif
+
+ JMOD_TARGET_CPU := $(OPENJDK_BUILD_CPU)
+ ifeq ($(JMOD_TARGET_CPU), x86_64)
+ JMOD_TARGET_CPU := amd64
+ endif
+
+ JMOD_TARGET_PLATFORM := $(JMOD_TARGET_OS)-$(JMOD_TARGET_CPU)
else
JMOD_FLAGS += --compress $(JMOD_COMPRESS)
+ JMOD_TARGET_PLATFORM := $(OPENJDK_MODULE_TARGET_PLATFORM)
endif
# Create jmods in the support dir and then move them into place to keep the
@@ -242,7 +255,7 @@ $(eval $(call SetupExecute, create_$(JMOD_FILE), \
SUPPORT_DIR := $(JMODS_SUPPORT_DIR), \
PRE_COMMAND := $(RM) $(JMODS_DIR)/$(JMOD_FILE) $(JMODS_SUPPORT_DIR)/$(JMOD_FILE), \
COMMAND := $(JMOD) $(JMOD_SMALL_FLAGS) create --module-version $(VERSION_SHORT) \
- --target-platform '$(OPENJDK_MODULE_TARGET_PLATFORM)' \
+ --target-platform '$(JMOD_TARGET_PLATFORM)' \
--module-path $(JMODS_DIR) $(JMOD_FLAGS) \
--date $(SOURCE_DATE_ISO_8601) \
$(JMODS_SUPPORT_DIR)/$(JMOD_FILE), \
diff --git a/make/Docs.gmk b/make/Docs.gmk
index 08a9ac662cd..e6a98c4fbd2 100644
--- a/make/Docs.gmk
+++ b/make/Docs.gmk
@@ -247,7 +247,7 @@ define create_overview_file
\
\
#
- ifneq ($$($1_GROUPS),)
+ ifneq ($$($1_GROUPS), )
$1_OVERVIEW_TEXT += \
This document is divided into \
$$(subst 2,two,$$(subst 3,three,$$(words $$($1_GROUPS)))) sections:
\
diff --git a/make/Global.gmk b/make/Global.gmk
index 998ba4d2bda..16a5b05cccb 100644
--- a/make/Global.gmk
+++ b/make/Global.gmk
@@ -28,7 +28,7 @@
###
# Helper macro to allow $(info) to properly print strings beginning with spaces.
-_:=
+_ :=
help:
$(info )
@@ -102,13 +102,14 @@ help:
$(info $(_) # method is 'auto', 'ignore' or 'fail' (default))
$(info $(_) TEST="test1 ..." # Use the given test descriptor(s) for testing, e.g.)
$(info $(_) # make test TEST="jdk_lang gtest:all")
+ $(info $(_) TEST_DEPS="dependency1 ..." # Specify additional dependencies for running tests, e.g docs-jdk
$(info $(_) JTREG="OPT1=x;OPT2=y" # Control the JTREG test harness, use 'make test-only JTREG=help' to list)
$(info $(_) GTEST="OPT1=x;OPT2=y" # Control the GTEST test harness, use 'make test-only GTEST=help' to list)
$(info $(_) MICRO="OPT1=x;OPT2=y" # Control the MICRO test harness, use 'make test-only MICRO=help' to list)
$(info $(_) TEST_OPTS="OPT1=x;..." # Generic control of all test harnesses)
$(info $(_) TEST_VM_OPTS="ARG ..." # Same as setting TEST_OPTS to VM_OPTIONS="ARG ...")
$(info )
- $(if $(all_confs), $(info Available configurations in $(build_dir):) $(foreach var,$(all_confs),$(info * $(var))),\
+ $(if $(all_confs), $(info Available configurations in $(build_dir):) $(foreach var,$(all_confs),$(info * $(var))), \
$(info No configurations were found in $(build_dir).) $(info Run 'bash configure' to create a configuration.))
# We need a dummy rule otherwise make will complain
@true
diff --git a/make/Images.gmk b/make/Images.gmk
index bfad1ad563c..5703a74afa5 100644
--- a/make/Images.gmk
+++ b/make/Images.gmk
@@ -134,11 +134,11 @@ CDS_DUMP_FLAGS = -Xmx128M -Xms128M
# Param1 - VM variant (e.g., server, client, zero, ...)
# Param2 - _nocoops, or empty
define CreateCDSArchive
- $1_$2_DUMP_EXTRA_ARG := $(if $(filter _nocoops, $2),-XX:-UseCompressedOops,)
- $1_$2_DUMP_TYPE := $(if $(filter _nocoops, $2),-NOCOOPS,)
+ $1_$2_DUMP_EXTRA_ARG := $(if $(filter _nocoops, $2), -XX:-UseCompressedOops, )
+ $1_$2_DUMP_TYPE := $(if $(filter _nocoops, $2), -NOCOOPS, )
# Only G1 supports dumping the shared heap, so explicitly use G1 if the JVM supports it.
- $1_$2_CDS_DUMP_FLAGS := $(CDS_DUMP_FLAGS) $(if $(filter g1gc, $(JVM_FEATURES_$1)),-XX:+UseG1GC)
+ $1_$2_CDS_DUMP_FLAGS := $(CDS_DUMP_FLAGS) $(if $(filter g1gc, $(JVM_FEATURES_$1)), -XX:+UseG1GC)
ifeq ($(OPENJDK_TARGET_OS), windows)
$1_$2_CDS_ARCHIVE := bin/$1/classes$2.jsa
@@ -235,7 +235,7 @@ endif
ifeq ($(GCOV_ENABLED), true)
- $(eval $(call SetupCopyFiles,COPY_GCOV_GCNO, \
+ $(eval $(call SetupCopyFiles, COPY_GCOV_GCNO, \
SRC := $(OUTPUTDIR), \
DEST := $(SYMBOLS_IMAGE_DIR)/gcov, \
FILES := $(call FindFiles, $(HOTSPOT_OUTPUTDIR) \
diff --git a/make/Init.gmk b/make/Init.gmk
index 61846217ecc..8918de7d16e 100644
--- a/make/Init.gmk
+++ b/make/Init.gmk
@@ -37,7 +37,7 @@ default:
# serially, regardless of -j.
.NOTPARALLEL:
-ifeq ($(HAS_SPEC),)
+ifeq ($(HAS_SPEC), )
##############################################################################
# This is the default mode. We have not been recursively called with a SPEC.
##############################################################################
@@ -168,7 +168,7 @@ ifeq ($(HAS_SPEC),)
endif
make-info:
- ifneq ($(findstring $(LOG_LEVEL),info debug trace),)
+ ifneq ($(findstring $(LOG_LEVEL), info debug trace), )
$(info Running make as '$(strip $(MAKE) $(MFLAGS) \
$(COMMAND_LINE_VARIABLES) $(MAKECMDGOALS))')
endif
diff --git a/make/InitSupport.gmk b/make/InitSupport.gmk
index ed9cd136c3f..eea593a80db 100644
--- a/make/InitSupport.gmk
+++ b/make/InitSupport.gmk
@@ -32,7 +32,7 @@
ifndef _INITSUPPORT_GMK
_INITSUPPORT_GMK := 1
-ifeq ($(HAS_SPEC),)
+ifeq ($(HAS_SPEC), )
# COMMA is defined in spec.gmk, but that is not included yet
COMMA := ,
@@ -50,7 +50,7 @@ ifeq ($(HAS_SPEC),)
# Make control variables, handled by Init.gmk
INIT_CONTROL_VARIABLES += LOG CONF CONF_NAME SPEC JOBS TEST_JOBS CONF_CHECK \
- COMPARE_BUILD JTREG GTEST MICRO TEST_OPTS TEST_VM_OPTS
+ COMPARE_BUILD JTREG GTEST MICRO TEST_OPTS TEST_VM_OPTS TEST_DEPS
# All known make control variables
MAKE_CONTROL_VARIABLES := $(INIT_CONTROL_VARIABLES) TEST JDK_FILTER SPEC_FILTER
@@ -74,13 +74,13 @@ ifeq ($(HAS_SPEC),)
# Setup information about available configurations, if any.
ifneq ($(CUSTOM_ROOT), )
- build_dir=$(CUSTOM_ROOT)/build
+ build_dir = $(CUSTOM_ROOT)/build
else
- build_dir=$(topdir)/build
+ build_dir = $(topdir)/build
endif
- all_spec_files=$(wildcard $(build_dir)/*/spec.gmk)
+ all_spec_files = $(wildcard $(build_dir)/*/spec.gmk)
# Extract the configuration names from the path
- all_confs=$(patsubst %/spec.gmk, %, $(patsubst $(build_dir)/%, %, $(all_spec_files)))
+ all_confs = $(patsubst %/spec.gmk, %, $(patsubst $(build_dir)/%, %, $(all_spec_files)))
# Check for unknown command-line variables
define CheckControlVariables
@@ -128,7 +128,7 @@ ifeq ($(HAS_SPEC),)
ifeq ($$(CONF_CHECK), )
# Default behavior is fail
CONF_CHECK := fail
- else ifneq ($$(filter-out auto fail ignore, $$(CONF_CHECK)),)
+ else ifneq ($$(filter-out auto fail ignore, $$(CONF_CHECK)), )
$$(info Error: CONF_CHECK must be one of: auto, fail or ignore.)
$$(error Cannot continue)
endif
@@ -147,11 +147,11 @@ ifeq ($(HAS_SPEC),)
$$(info Error: Cannot use CONF_NAME=$$(CONF_NAME) and SPEC=$$(SPEC) at the same time. Choose one.)
$$(error Cannot continue)
endif
- ifeq ($$(wildcard $$(SPEC)),)
+ ifeq ($$(wildcard $$(SPEC)), )
$$(info Error: Cannot locate spec.gmk, given by SPEC=$$(SPEC).)
$$(error Cannot continue)
endif
- ifeq ($$(filter /%, $$(SPEC)),)
+ ifeq ($$(filter /%, $$(SPEC)), )
# If given with relative path, make it absolute
SPECS := $$(CURDIR)/$$(strip $$(SPEC))
else
@@ -162,7 +162,7 @@ ifeq ($(HAS_SPEC),)
override SPEC :=
else
# Use spec.gmk files in the build output directory
- ifeq ($$(all_spec_files),)
+ ifeq ($$(all_spec_files), )
ifneq ($(CUSTOM_ROOT), )
$$(info Error: No configurations found for $$(CUSTOM_ROOT).)
else
@@ -180,7 +180,7 @@ ifeq ($(HAS_SPEC),)
$$(error Cannot continue)
endif
matching_conf := $$(strip $$(filter $$(CONF_NAME), $$(all_confs)))
- ifeq ($$(matching_conf),)
+ ifeq ($$(matching_conf), )
$$(info Error: No configurations found matching CONF_NAME=$$(CONF_NAME).)
$$(info Available configurations in $$(build_dir):)
$$(foreach var, $$(all_confs), $$(info * $$(var)))
@@ -197,15 +197,15 @@ ifeq ($(HAS_SPEC),)
SPECS := $$(build_dir)/$$(matching_conf)/spec.gmk
else ifneq ($$(origin CONF), undefined)
# User have given a CONF= argument.
- ifeq ($$(CONF),)
+ ifeq ($$(CONF), )
# If given CONF=, match all configurations
matching_confs := $$(strip $$(all_confs))
else
# Otherwise select those that contain the given CONF string
- ifeq ($$(patsubst !%,,$$(CONF)),)
+ ifeq ($$(patsubst !%,,$$(CONF)), )
# A CONF starting with ! means we should negate the search term
matching_confs := $$(strip $$(foreach var, $$(all_confs), \
- $$(if $$(findstring $$(subst !,,$$(CONF)), $$(var)), ,$$(var))))
+ $$(if $$(findstring $$(subst !,,$$(CONF)), $$(var)), ,$$(var))))
else
matching_confs := $$(strip $$(foreach var, $$(all_confs), \
$$(if $$(findstring $$(CONF), $$(var)), $$(var))))
@@ -215,12 +215,12 @@ ifeq ($(HAS_SPEC),)
matching_confs := $$(CONF)
# Don't repeat this output on make restarts caused by including
# generated files.
- ifeq ($$(MAKE_RESTARTS),)
+ ifeq ($$(MAKE_RESTARTS), )
$$(info Using exact match for CONF=$$(CONF) (other matches are possible))
endif
endif
endif
- ifeq ($$(matching_confs),)
+ ifeq ($$(matching_confs), )
$$(info Error: No configurations found matching CONF=$$(CONF).)
$$(info Available configurations in $$(build_dir):)
$$(foreach var, $$(all_confs), $$(info * $$(var)))
@@ -228,9 +228,9 @@ ifeq ($(HAS_SPEC),)
else
# Don't repeat this output on make restarts caused by including
# generated files.
- ifeq ($$(MAKE_RESTARTS),)
+ ifeq ($$(MAKE_RESTARTS), )
ifeq ($$(words $$(matching_confs)), 1)
- ifneq ($$(findstring $$(LOG_LEVEL), info debug trace),)
+ ifneq ($$(findstring $$(LOG_LEVEL), info debug trace), )
$$(info Building configuration '$$(matching_confs)' (matching CONF=$$(CONF)))
endif
else
@@ -272,7 +272,7 @@ ifeq ($(HAS_SPEC),)
# count.
main_targets_file := $$(dir $(strip $2))make-support/main-targets.gmk
- ifeq ($$(MAKE_RESTARTS),)
+ ifeq ($$(MAKE_RESTARTS), )
# Only do this if make has not been restarted, and if we do not force it.
ifeq ($(strip $1), FORCE)
$$(shell rm -f $$(main_targets_file))
@@ -316,9 +316,9 @@ else # $(HAS_SPEC)=true
BUILD_LOG_PIPE_SIMPLE := | $(TEE) -a $(BUILD_LOG)
ifneq ($(CUSTOM_ROOT), )
- topdir=$(CUSTOM_ROOT)
+ topdir = $(CUSTOM_ROOT)
else
- topdir=$(TOPDIR)
+ topdir = $(TOPDIR)
endif
# Setup the build environment to match the requested specification on
@@ -349,39 +349,39 @@ else # $(HAS_SPEC)=true
ifneq ($$(findstring :, $$(COMPARE_BUILD)), )
$$(foreach part, $$(subst :, , $$(COMPARE_BUILD)), \
$$(if $$(filter PATCH=%, $$(part)), \
- $$(eval COMPARE_BUILD_PATCH=$$(strip $$(patsubst PATCH=%, %, $$(part)))) \
+ $$(eval COMPARE_BUILD_PATCH = $$(strip $$(patsubst PATCH=%, %, $$(part)))) \
) \
$$(if $$(filter CONF=%, $$(part)), \
- $$(eval COMPARE_BUILD_CONF=$$(strip $$(subst +, , $$(patsubst CONF=%, %, $$(part))))) \
+ $$(eval COMPARE_BUILD_CONF = $$(strip $$(subst +, , $$(patsubst CONF=%, %, $$(part))))) \
) \
$$(if $$(filter MAKE=%, $$(part)), \
- $$(eval COMPARE_BUILD_MAKE=$$(strip $$(subst +, , $$(patsubst MAKE=%, %, $$(part))))) \
+ $$(eval COMPARE_BUILD_MAKE = $$(strip $$(subst +, , $$(patsubst MAKE=%, %, $$(part))))) \
) \
$$(if $$(filter COMP_OPTS=%, $$(part)), \
- $$(eval COMPARE_BUILD_COMP_OPTS=$$(strip $$(subst +, , $$(patsubst COMP_OPTS=%, %, $$(part))))) \
+ $$(eval COMPARE_BUILD_COMP_OPTS = $$(strip $$(subst +, , $$(patsubst COMP_OPTS=%, %, $$(part))))) \
) \
$$(if $$(filter COMP_DIR=%, $$(part)), \
- $$(eval COMPARE_BUILD_COMP_DIR=$$(strip $$(subst +, , $$(patsubst COMP_DIR=%, %, $$(part))))) \
+ $$(eval COMPARE_BUILD_COMP_DIR = $$(strip $$(subst +, , $$(patsubst COMP_DIR=%, %, $$(part))))) \
) \
$$(if $$(filter FAIL=%, $$(part)), \
- $$(eval COMPARE_BUILD_FAIL=$$(strip $$(subst +, , $$(patsubst FAIL=%, %, $$(part))))) \
+ $$(eval COMPARE_BUILD_FAIL = $$(strip $$(subst +, , $$(patsubst FAIL=%, %, $$(part))))) \
) \
$$(if $$(filter NODRYRUN=%, $$(part)), \
- $$(eval COMPARE_BUILD_NODRYRUN=$$(strip $$(subst +, , $$(patsubst NODRYRUN=%, %, $$(part))))) \
+ $$(eval COMPARE_BUILD_NODRYRUN = $$(strip $$(subst +, , $$(patsubst NODRYRUN=%, %, $$(part))))) \
) \
)
else
# Separate handling for single field case, to allow for spaces in values.
ifneq ($$(filter PATCH=%, $$(COMPARE_BUILD)), )
- COMPARE_BUILD_PATCH=$$(strip $$(patsubst PATCH=%, %, $$(COMPARE_BUILD)))
+ COMPARE_BUILD_PATCH = $$(strip $$(patsubst PATCH=%, %, $$(COMPARE_BUILD)))
else ifneq ($$(filter CONF=%, $$(COMPARE_BUILD)), )
- COMPARE_BUILD_CONF=$$(strip $$(subst +, , $$(patsubst CONF=%, %, $$(COMPARE_BUILD))))
+ COMPARE_BUILD_CONF = $$(strip $$(subst +, , $$(patsubst CONF=%, %, $$(COMPARE_BUILD))))
else ifneq ($$(filter --%, $$(COMPARE_BUILD)), )
# Assume CONF if value begins with --
- COMPARE_BUILD_CONF=$$(strip $$(subst +, , $$(COMPARE_BUILD)))
+ COMPARE_BUILD_CONF = $$(strip $$(subst +, , $$(COMPARE_BUILD)))
else
# Otherwise assume patch file
- COMPARE_BUILD_PATCH=$$(strip $$(COMPARE_BUILD))
+ COMPARE_BUILD_PATCH = $$(strip $$(COMPARE_BUILD))
endif
endif
ifneq ($$(COMPARE_BUILD_PATCH), )
@@ -531,7 +531,7 @@ else # $(HAS_SPEC)=true
# used by build comparisons.
define WaitForJavacServerFinish
$(if $(JAVAC_SERVER_DIR), \
- sleep 5\
+ sleep 5 \
)
endef
else
@@ -544,7 +544,7 @@ else # $(HAS_SPEC)=true
##############################################################################
# Store the build times in this directory.
- BUILDTIMESDIR=$(OUTPUTDIR)/make-support/build-times
+ BUILDTIMESDIR = $(OUTPUTDIR)/make-support/build-times
# Record starting time for build of a sub repository.
define RecordStartTime
@@ -605,7 +605,7 @@ endif # HAS_SPEC
# $1: The option to look for
# $2: The variable to set to "true" if the option is found
define ParseLogOption
- ifneq ($$(findstring $1, $$(LOG)),)
+ ifneq ($$(findstring $1, $$(LOG)), )
override $2 := true
# First try to remove "," if it exists, otherwise just remove " "
LOG_STRIPPED := $$(subst $1,, $$(subst $$(COMMA)$$(strip $1),, $$(LOG)))
@@ -620,7 +620,7 @@ endef
# $1: The option to look for
# $2: The variable to set to the value of the option, if found
define ParseLogValue
- ifneq ($$(findstring $1=, $$(LOG)),)
+ ifneq ($$(findstring $1=, $$(LOG)), )
# Make words of out comma-separated list and find the one with opt=val
value := $$(strip $$(subst $$(strip $1)=,, $$(filter $$(strip $1)=%, $$(subst $$(COMMA), , $$(LOG)))))
override $2 := $$(value)
@@ -673,7 +673,7 @@ define ParseLogLevel
override LOG_LEVEL := $$(LOG)
- ifeq ($$(LOG_LEVEL),)
+ ifeq ($$(LOG_LEVEL), )
# Set LOG to "warn" as default if not set
override LOG_LEVEL := warn
endif
diff --git a/make/InterimImage.gmk b/make/InterimImage.gmk
index bb4b1fc6fd3..e046f060513 100644
--- a/make/InterimImage.gmk
+++ b/make/InterimImage.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -27,12 +27,13 @@ default: all
include $(SPEC)
include MakeBase.gmk
+
+include Execute.gmk
include Modules.gmk
################################################################################
-# Use this file inside the image as target for make rule
-JIMAGE_TARGET_FILE := bin/java$(EXECUTABLE_SUFFIX)
+INTERIM_JLINK_SUPPORT_DIR := $(SUPPORT_OUTPUTDIR)/interim-image-jlink
INTERIM_MODULES_LIST := $(call CommaList, $(INTERIM_IMAGE_MODULES))
@@ -42,17 +43,18 @@ JLINK_TOOL := $(JLINK) -J-Djlink.debug=true \
--module-path $(INTERIM_JMODS_DIR) \
--endian $(OPENJDK_BUILD_CPU_ENDIAN)
-$(INTERIM_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(JMODS) \
- $(call DependOnVariable, INTERIM_MODULES_LIST)
- $(call LogWarn, Creating interim jimage)
- $(RM) -r $(INTERIM_IMAGE_DIR)
- $(JLINK_TOOL) \
- --output $(INTERIM_IMAGE_DIR) \
- --disable-plugin generate-jli-classes \
- --add-modules $(INTERIM_MODULES_LIST)
- $(TOUCH) $@
-
-TARGETS += $(INTERIM_IMAGE_DIR)/$(JIMAGE_TARGET_FILE)
+$(eval $(call SetupExecute, jlink_interim_image, \
+ WARN := Creating interim jimage, \
+ DEPS := $(JMODS) $(call DependOnVariable, INTERIM_MODULES_LIST), \
+ OUTPUT_DIR := $(INTERIM_IMAGE_DIR), \
+ SUPPORT_DIR := $(INTERIM_JLINK_SUPPORT_DIR), \
+ PRE_COMMAND := $(RM) -r $(INTERIM_IMAGE_DIR), \
+ COMMAND := $(JLINK_TOOL) --output $(INTERIM_IMAGE_DIR) \
+ --disable-plugin generate-jli-classes \
+ --add-modules $(INTERIM_MODULES_LIST), \
+))
+
+TARGETS += $(jlink_interim_image)
################################################################################
diff --git a/make/JrtfsJar.gmk b/make/JrtfsJar.gmk
index 990c8a7e1ed..55e0c150b3b 100644
--- a/make/JrtfsJar.gmk
+++ b/make/JrtfsJar.gmk
@@ -67,7 +67,8 @@ $(eval $(call SetupJavaCompilation, BUILD_JRTFS, \
$(eval $(call SetupCopyFiles, COPY_JIMAGE_SERVICE_PROVIDER, \
SRC := $(TOPDIR)/src/java.base/share/classes, \
DEST := $(SUPPORT_OUTPUTDIR)/jrtfs_classes, \
- FILES := META-INF/services/java.nio.file.spi.FileSystemProvider))
+ FILES := META-INF/services/java.nio.file.spi.FileSystemProvider, \
+))
$(eval $(call SetupJarArchive, BUILD_JRTFS_JAR, \
DEPENDENCIES := $(BUILD_JRTFS) $(COPY_JIMAGE_SERVICE_PROVIDER), \
diff --git a/make/Main.gmk b/make/Main.gmk
index fbd394c1472..25dfba7d36c 100644
--- a/make/Main.gmk
+++ b/make/Main.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@
# Declare default target
default:
-ifeq ($(wildcard $(SPEC)),)
+ifeq ($(wildcard $(SPEC)), )
$(error Main.gmk needs SPEC set to a proper spec.gmk)
endif
@@ -278,6 +278,18 @@ $(eval $(call SetupTarget, eclipse-mixed-env, \
ARGS := --always-make, \
))
+$(eval $(call SetupTarget, hotspot-xcode-project, \
+ MAKEFILE := ide/xcode/hotspot/CreateXcodeProject, \
+ TARGET := build, \
+ DEPS := hotspot compile-commands-hotspot jdk-image, \
+))
+
+$(eval $(call SetupTarget, open-hotspot-xcode-project, \
+ MAKEFILE := ide/xcode/hotspot/CreateXcodeProject, \
+ TARGET := open, \
+ DEPS := hotspot-xcode-project, \
+))
+
ALL_TARGETS += $(HOTSPOT_VARIANT_TARGETS) $(HOTSPOT_VARIANT_GENSRC_TARGETS) \
$(HOTSPOT_VARIANT_LIBS_TARGETS) $(HOTSPOT_VARIANT_STATIC_LIBS_TARGETS)
@@ -556,6 +568,10 @@ $(eval $(call SetupTarget, update-build-docs, \
MAKEFILE := UpdateBuildDocs, \
))
+$(eval $(call SetupTarget, update-sleef-source, \
+ MAKEFILE := UpdateSleefSource, \
+))
+
$(eval $(call SetupTarget, update-x11wrappers, \
MAKEFILE := UpdateX11Wrappers, \
DEPS := java.base-copy buildtools-jdk, \
@@ -769,13 +785,13 @@ $(eval $(call SetupTarget, build-microbenchmark, \
$(eval $(call SetupTarget, test, \
MAKEFILE := RunTests, \
ARGS := TEST="$(TEST)", \
- DEPS := jdk-image test-image, \
+ DEPS := jdk-image test-image $(TEST_DEPS), \
))
$(eval $(call SetupTarget, exploded-test, \
MAKEFILE := RunTests, \
ARGS := TEST="$(TEST)" JDK_IMAGE_DIR=$(JDK_OUTPUTDIR), \
- DEPS := exploded-image test-image, \
+ DEPS := exploded-image test-image $(TEST_DEPS), \
))
ifeq ($(JCOV_ENABLED), true)
@@ -1094,8 +1110,8 @@ else
test-make-compile-commands: compile-commands
# Declare dependency for all generated test targets
- $(foreach t, $(filter-out test-make%, $(ALL_TEST_TARGETS)), $(eval $t: jdk-image test-image))
- $(foreach t, $(ALL_EXPLODED_TEST_TARGETS), $(eval $t: exploded-image test-image))
+ $(foreach t, $(filter-out test-make%, $(ALL_TEST_TARGETS)), $(eval $t: jdk-image test-image $(TEST_DEPS)))
+ $(foreach t, $(ALL_EXPLODED_TEST_TARGETS), $(eval $t: exploded-image test-image $(TEST_DEPS)))
interim-image: $(INTERIM_JMOD_TARGETS)
@@ -1402,7 +1418,7 @@ dist-clean: clean
($(CD) $(OUTPUTDIR) && \
$(RM) -r *spec.gmk $(CONFIGURESUPPORT_OUTPUTDIR) Makefile compare.sh ide \
configure.log* build.log*)
- $(if $(filter $(CONF_NAME),$(notdir $(OUTPUTDIR))), \
+ $(if $(filter $(CONF_NAME), $(notdir $(OUTPUTDIR))), \
if test "x`$(LS) $(OUTPUTDIR)`" != x; then \
$(ECHO) "Warning: Not removing non-empty configuration directory for '$(CONF_NAME)'" ; \
else \
diff --git a/make/MainSupport.gmk b/make/MainSupport.gmk
index 8c575423005..f1027a9b888 100644
--- a/make/MainSupport.gmk
+++ b/make/MainSupport.gmk
@@ -175,7 +175,7 @@ define DeclareRecipesForPhaseAndModule
$$(foreach d, $$($1_$2_TOPDIRS), \
$$(eval $1 += $2-$$($1_TARGET_SUFFIX)-$$(notdir $$d)))
endif
- ifeq ($(NO_RECIPES),)
+ ifeq ($(NO_RECIPES), )
$$(eval $$(call DeclareRecipeForModuleMakefile,$1,$2))
endif
$1 += $2-$$($1_TARGET_SUFFIX)
@@ -197,8 +197,8 @@ endef
# $1_MODULES : All modules that had rules generated
# $1_TARGETS : All targets generated
define DeclareRecipesForPhase
- $(foreach i,2 3 4 5 6 7 8, $(if $(strip $($i)),$(strip $1)_$(strip $($i)))$(NEWLINE))
- $(if $(9),$(error Internal makefile error: Too many arguments to \
+ $(foreach i, 2 3 4 5 6 7 8, $(if $(strip $($i)),$(strip $1)_$(strip $($i)))$(NEWLINE))
+ $(if $(9), $(error Internal makefile error: Too many arguments to \
DeclareRecipesForPhase, please update MakeHelper.gmk))
$$(foreach m, $$($(strip $1)_CHECK_MODULES), \
diff --git a/make/RunTests.gmk b/make/RunTests.gmk
index b0291e4eff4..45494b859b7 100644
--- a/make/RunTests.gmk
+++ b/make/RunTests.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -104,7 +104,8 @@ ifneq ($(wildcard $(JTREG_FAILURE_HANDLER)), )
-observerDir:$(JTREG_FAILURE_HANDLER) \
-timeoutHandler:jdk.test.failurehandler.jtreg.GatherProcessInfoTimeoutHandler \
-observer:jdk.test.failurehandler.jtreg.GatherDiagnosticInfoObserver \
- -timeoutHandlerTimeout:$(JTREG_FAILURE_HANDLER_TIMEOUT)
+ -timeoutHandlerTimeout:$(JTREG_FAILURE_HANDLER_TIMEOUT) \
+ #
endif
GTEST_LAUNCHER_DIRS := $(patsubst %/gtestLauncher, %, \
@@ -263,6 +264,7 @@ jaxp_JTREG_PROBLEM_LIST += $(TOPDIR)/test/jaxp/ProblemList.txt
langtools_JTREG_PROBLEM_LIST += $(TOPDIR)/test/langtools/ProblemList.txt
hotspot_JTREG_PROBLEM_LIST += $(TOPDIR)/test/hotspot/jtreg/ProblemList.txt
lib-test_JTREG_PROBLEM_LIST += $(TOPDIR)/test/lib-test/ProblemList.txt
+docs_JTREG_PROBLEM_LIST += $(TOPDIR)/test/docs/ProblemList.txt
################################################################################
# Parse test selection
@@ -500,7 +502,7 @@ define SetupRunGtestTestBody
endif
ifneq ($$(GTEST_REPEAT), )
- $1_GTEST_REPEAT :=--gtest_repeat=$$(GTEST_REPEAT)
+ $1_GTEST_REPEAT := --gtest_repeat=$$(GTEST_REPEAT)
endif
run-test-$1: pre-run-test
@@ -738,6 +740,11 @@ define SetupRunJtregTestBody
# Only the problem list for the current test root should be used.
$1_JTREG_PROBLEM_LIST := $$(filter $$($1_TEST_ROOT)%, $$($1_JTREG_PROBLEM_LIST))
+ # Pass along the path to the tidy html checker
+ ifneq ($$(TIDY), )
+ $1_JTREG_BASIC_OPTIONS += -Dtidy=$$(TIDY)
+ endif
+
ifneq ($(TEST_JOBS), 0)
$$(eval $$(call SetJtregValue,$1,JTREG_JOBS,$$(TEST_JOBS)))
else
@@ -748,8 +755,6 @@ define SetupRunJtregTestBody
# we may end up with a lot of JVM's
$1_JTREG_MAX_RAM_PERCENTAGE := $$(shell $(AWK) 'BEGIN { print 25 / $$($1_JTREG_JOBS); }')
- JTREG_TIMEOUT_FACTOR ?= 4
-
JTREG_VERBOSE ?= fail,error,summary
JTREG_RETAIN ?= fail,error
JTREG_TEST_THREAD_FACTORY ?=
@@ -837,6 +842,24 @@ define SetupRunJtregTestBody
$1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$($1_JTREG_PROBLEM_LIST))
endif
+ JTREG_ALL_OPTIONS := $$(JTREG_JAVA_OPTIONS) $$(JTREG_VM_OPTIONS)
+
+ JTREG_AUTO_PROBLEM_LISTS :=
+ JTREG_AUTO_TIMEOUT_FACTOR := 4
+
+ ifneq ($$(findstring -Xcomp, $$(JTREG_ALL_OPTIONS)), )
+ JTREG_AUTO_PROBLEM_LISTS += ProblemList-Xcomp.txt
+ JTREG_AUTO_TIMEOUT_FACTOR := 10
+ endif
+
+ ifneq ($$(findstring -XX:+UseZGC, $$(JTREG_ALL_OPTIONS)), )
+ ifneq ($$(findstring -XX:-ZGenerational, $$(JTREG_ALL_OPTIONS)), )
+ JTREG_AUTO_PROBLEM_LISTS += ProblemList-zgc.txt
+ else
+ JTREG_AUTO_PROBLEM_LISTS += ProblemList-generational-zgc.txt
+ endif
+ endif
+
ifneq ($$(JTREG_EXTRA_PROBLEM_LISTS), )
# Accept both absolute paths as well as relative to the current test root.
$1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$(wildcard \
@@ -851,6 +874,8 @@ define SetupRunJtregTestBody
$1_JTREG_BASIC_OPTIONS += -e:TEST_IMAGE_DIR=$(TEST_IMAGE_DIR)
+ $1_JTREG_BASIC_OPTIONS += -e:DOCS_JDK_IMAGE_DIR=$$(DOCS_JDK_IMAGE_DIR)
+
ifneq ($$(JTREG_FAILURE_HANDLER_OPTIONS), )
$1_JTREG_LAUNCHER_OPTIONS += -Djava.library.path="$(JTREG_FAILURE_HANDLER_DIR)"
endif
@@ -868,6 +893,18 @@ define SetupRunJtregTestBody
$$(eval $$(call SetupRunJtregTestCustom, $1))
+ # SetupRunJtregTestCustom might also adjust JTREG_AUTO_ variables
+ # so set the final results after setting values from custom setup
+ ifneq ($$(JTREG_AUTO_PROBLEM_LISTS), )
+ # Accept both absolute paths as well as relative to the current test root.
+ $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$(wildcard \
+ $$(JTREG_AUTO_PROBLEM_LISTS) \
+ $$(addprefix $$($1_TEST_ROOT)/, $$(JTREG_AUTO_PROBLEM_LISTS)) \
+ ))
+ endif
+
+ JTREG_TIMEOUT_FACTOR ?= $$(JTREG_AUTO_TIMEOUT_FACTOR)
+
clean-outputdirs-$1:
$$(RM) -r $$($1_TEST_SUPPORT_DIR)
$$(RM) -r $$($1_TEST_RESULTS_DIR)
diff --git a/make/RunTestsPrebuilt.gmk b/make/RunTestsPrebuilt.gmk
index eea325184f3..ce5d254ccc4 100644
--- a/make/RunTestsPrebuilt.gmk
+++ b/make/RunTestsPrebuilt.gmk
@@ -34,7 +34,7 @@ ifneq ($(findstring :, $(MAKE)), )
endif
# Locate this Makefile
-ifeq ($(filter /%, $(lastword $(MAKEFILE_LIST))),)
+ifeq ($(filter /%, $(lastword $(MAKEFILE_LIST))), )
makefile_path := $(CURDIR)/$(strip $(lastword $(MAKEFILE_LIST)))
else
makefile_path := $(lastword $(MAKEFILE_LIST))
@@ -67,7 +67,7 @@ define SetupVariable
ifneq ($$(findstring $$(LOG), info debug trace), )
$$(info Prebuilt variable $1=$2 (default value))
endif
- $1:=$2
+ $1 := $2
endif
else
ifneq ($$(findstring $$(LOG), info debug trace), )
@@ -163,7 +163,7 @@ else ifeq ($(UNAME_OS), MINGW64)
OPENJDK_TARGET_OS_TYPE := windows
OPENJDK_TARGET_OS_ENV := windows.msys2
else
- OPENJDK_TARGET_OS_TYPE:=unix
+ OPENJDK_TARGET_OS_TYPE := unix
ifeq ($(UNAME_OS), Linux)
OPENJDK_TARGET_OS := linux
else ifeq ($(UNAME_OS), Darwin)
diff --git a/make/RunTestsPrebuiltSpec.gmk b/make/RunTestsPrebuiltSpec.gmk
index 170a2c25553..6447da8cb6b 100644
--- a/make/RunTestsPrebuiltSpec.gmk
+++ b/make/RunTestsPrebuiltSpec.gmk
@@ -70,9 +70,9 @@ BUILD_JAVA_FLAGS := $(JAVA_FLAGS_BIG)
################################################################################
# Hard-coded values copied from spec.gmk.in.
-X:=
-SPACE:=$(X) $(X)
-COMMA:=,
+X :=
+SPACE := $(X) $(X)
+COMMA := ,
MAKE_ARGS = $(MAKE_LOG_FLAGS) -r -R -I $(TOPDIR)/make/common SPEC=$(SPEC) \
MAKE_LOG_FLAGS="$(MAKE_LOG_FLAGS)" LOG_LEVEL=$(LOG_LEVEL)
BASH_ARGS := -o pipefail -e
diff --git a/make/SourceRevision.gmk b/make/SourceRevision.gmk
index 63bbe5b62fb..79c438987f7 100644
--- a/make/SourceRevision.gmk
+++ b/make/SourceRevision.gmk
@@ -64,7 +64,7 @@ ifeq ($(USE_SCM), true)
# Verify that the entire forest is consistent
$(foreach repo, $(call FindAllReposRel), \
- $(if $(wildcard $(TOPDIR)/$(repo)/$(SCM_DIR)),, \
+ $(if $(wildcard $(TOPDIR)/$(repo)/$(SCM_DIR)), , \
$(error Inconsistent revision control: $(repo) is missing $(SCM_DIR) directory)) \
)
@@ -72,7 +72,7 @@ ifeq ($(USE_SCM), true)
MakeFilenameFromRepo = \
$(strip $(subst .,top, $(subst /,-, $1)))
- ################################################################################
+ ##############################################################################
# SetupGetRevisionForRepo defines a make rule for creating a file containing
# the name of the repository and the output of the scm command for that
# repository.
diff --git a/make/StaticLibsImage.gmk b/make/StaticLibsImage.gmk
index 84e97b13b29..6a85701a788 100644
--- a/make/StaticLibsImage.gmk
+++ b/make/StaticLibsImage.gmk
@@ -41,9 +41,9 @@ ALL_MODULES = $(call FindAllModules)
TARGETS :=
ifneq ($(filter static-libs-image, $(MAKECMDGOALS)), )
- IMAGE_DEST_DIR=$(STATIC_LIBS_IMAGE_DIR)/lib
+ IMAGE_DEST_DIR = $(STATIC_LIBS_IMAGE_DIR)/lib
else ifneq ($(filter static-libs-graal-image, $(MAKECMDGOALS)), )
- IMAGE_DEST_DIR=$(STATIC_LIBS_GRAAL_IMAGE_DIR)/lib
+ IMAGE_DEST_DIR = $(STATIC_LIBS_GRAAL_IMAGE_DIR)/lib
endif
# Copy JDK static libs to the image.
diff --git a/make/TestImage.gmk b/make/TestImage.gmk
index f6d680fb690..e503f1cea2c 100644
--- a/make/TestImage.gmk
+++ b/make/TestImage.gmk
@@ -31,7 +31,7 @@ include MakeBase.gmk
# Hook to include the corresponding custom file, if present.
$(eval $(call IncludeCustomExtension, TestImage-pre.gmk))
-############################################################################
+################################################################################
BUILD_INFO_PROPERTIES := $(TEST_IMAGE_DIR)/build-info.properties
diff --git a/make/ToolsHotspot.gmk b/make/ToolsHotspot.gmk
index 17963de7839..df779d961fd 100644
--- a/make/ToolsHotspot.gmk
+++ b/make/ToolsHotspot.gmk
@@ -42,6 +42,6 @@ BUILD_TOOLS_HOTSPOT := $(call SetupJavaCompilationCompileTarget, \
TOOL_JFR_GEN := $(JAVA_SMALL) -cp $(HOTSPOT_TOOLS_OUTPUTDIR) \
build.tools.jfr.GenerateJfrFiles
-##########################################################################################
+################################################################################
endif # _TOOLS_HOTSPOT_GMK
diff --git a/make/ToolsJdk.gmk b/make/ToolsJdk.gmk
index e7cc3fc8711..402c6841191 100644
--- a/make/ToolsJdk.gmk
+++ b/make/ToolsJdk.gmk
@@ -128,14 +128,14 @@ TOOL_PUBLICSUFFIXLIST = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_clas
TOOL_FIXUPPANDOC = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
build.tools.fixuppandoc.Main
-##########################################################################################
+################################################################################
# Executable javascript filter for man page generation using pandoc.
PANDOC_TROFF_MANPAGE_FILTER := $(BUILDTOOLS_OUTPUTDIR)/manpages/pandoc-troff-manpage-filter
PANDOC_HTML_MANPAGE_FILTER := $(BUILDTOOLS_OUTPUTDIR)/manpages/pandoc-html-manpage-filter
-##########################################################################################
+################################################################################
# Hook to include the corresponding custom post file, if present.
$(eval $(call IncludeCustomExtension, ToolsJdk-post.gmk))
diff --git a/make/UpdateSleefSource.gmk b/make/UpdateSleefSource.gmk
new file mode 100644
index 00000000000..37a28abcb85
--- /dev/null
+++ b/make/UpdateSleefSource.gmk
@@ -0,0 +1,153 @@
+#
+# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+################################################################################
+
+default: all
+
+include $(SPEC)
+include MakeBase.gmk
+
+include CopyFiles.gmk
+include Execute.gmk
+
+################################################################################
+# This file is responsible for updating the generated sleef source code files
+# that are checked in to the JDK repo, and that are actually used when building.
+# This target needs to be re-run every time the source code of libsleef is
+# updated from upstream.
+################################################################################
+
+ifneq ($(COMPILE_TYPE), cross)
+ $(error Only cross-compilation of libsleef is currently supported)
+endif
+
+ifeq ($(CMAKE), )
+ $(error CMake not found. Please install cmake and rerun configure)
+endif
+
+ifneq ($(OPENJDK_BUILD_OS), linux)
+ $(error This target is only supported on linux)
+endif
+
+SLEEF_SUPPORT_DIR := $(MAKESUPPORT_OUTPUTDIR)/sleef
+SLEEF_SOURCE_BASE_DIR := $(TOPDIR)/src/jdk.incubator.vector/linux/native/libsleef
+SLEEF_SOURCE_DIR := $(SLEEF_SOURCE_BASE_DIR)/upstream
+SLEEF_TARGET_DIR := $(SLEEF_SOURCE_BASE_DIR)/generated
+SLEEF_NATIVE_BUILD_DIR := $(SLEEF_SUPPORT_DIR)/native
+SLEEF_CROSS_BUILD_DIR := $(SLEEF_SUPPORT_DIR)/cross
+
+ifeq ($(OPENJDK_TARGET_CPU), aarch64)
+ CROSS_COMPILATION_FILENAMES := sleefinline_advsimd.h sleefinline_sve.h
+ EXTRA_CROSS_OPTIONS := -DSLEEF_ENFORCE_SVE=TRUE
+else ifeq ($(OPENJDK_TARGET_CPU), riscv64)
+ CROSS_COMPILATION_FILENAMES := sleefinline_rvvm1.h
+ EXTRA_CROSS_OPTIONS := -DSLEEF_ENFORCE_RVVM1=TRUE
+else
+ $(error Unsupported platform)
+endif
+CROSS_COMPILATION_SRC_FILES := $(addprefix $(SLEEF_CROSS_BUILD_DIR)/include/, \
+ $(CROSS_COMPILATION_FILENAMES))
+
+ifeq ($(TOOLCHAIN_TYPE), clang)
+ SLEEF_TOOLCHAIN_TYPE := llvm
+else
+ SLEEF_TOOLCHAIN_TYPE := $(TOOLCHAIN_TYPE)
+endif
+
+SLEEF_CMAKE_FILE := toolchains/$(OPENJDK_TARGET_CPU)-$(SLEEF_TOOLCHAIN_TYPE).cmake
+
+# We need to run CMake twice, first using it to configure the build, and then
+# to actually build; and we need to do this twice, once for a native build
+# and once for the cross-compilation build.
+
+$(eval $(call SetupExecute, sleef_native_config, \
+ INFO := Configuring native sleef build, \
+ OUTPUT_DIR := $(SLEEF_NATIVE_BUILD_DIR), \
+ COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) -S . -B \
+ $(SLEEF_NATIVE_BUILD_DIR), \
+))
+
+TARGETS := $(sleef_native_config)
+
+$(eval $(call SetupExecute, sleef_native_build, \
+ INFO := Building native sleef, \
+ DEPS := $(sleef_native_config), \
+ OUTPUT_DIR := $(SLEEF_NATIVE_BUILD_DIR), \
+ COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) --build \
+ $(SLEEF_NATIVE_BUILD_DIR) -j, \
+))
+
+TARGETS := $(sleef_native_build)
+
+$(eval $(call SetupExecute, sleef_cross_config, \
+ INFO := Configuring cross-compiling sleef build, \
+ DEPS := $(sleef_native_build), \
+ OUTPUT_DIR := $(SLEEF_CROSS_BUILD_DIR), \
+ COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) -S . -B \
+ $(SLEEF_CROSS_BUILD_DIR) \
+ -DCMAKE_C_COMPILER=$(CC) \
+ -DCMAKE_TOOLCHAIN_FILE=$(SLEEF_CMAKE_FILE) \
+ -DNATIVE_BUILD_DIR=$(SLEEF_NATIVE_BUILD_DIR) \
+ -DSLEEF_BUILD_INLINE_HEADERS=TRUE \
+ $(EXTRA_CROSS_OPTIONS), \
+))
+
+TARGETS := $(sleef_cross_config)
+
+$(eval $(call SetupExecute, sleef_cross_build, \
+ INFO := Building cross-compiling sleef, \
+ DEPS := $(sleef_cross_config), \
+ OUTPUT_DIR := $(SLEEF_NATIVE_BUILD_DIR), \
+ COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) --build \
+ $(SLEEF_CROSS_BUILD_DIR) -j, \
+))
+
+TARGETS := $(sleef_cross_build)
+
+$(CROSS_COMPILATION_SRC_FILES): $(sleef_cross_build)
+
+# Finally, copy the generated files (and one needed static file) into our
+# target directory.
+
+$(eval $(call SetupCopyFiles, copy_static_sleef_source, \
+ FILES := $(SLEEF_SOURCE_DIR)/src/common/misc.h, \
+ DEST := $(SLEEF_TARGET_DIR), \
+))
+
+TARGETS := $(copy_static_sleef_source)
+
+$(eval $(call SetupCopyFiles, copy_generated_sleef_source, \
+ FILES := $(CROSS_COMPILATION_SRC_FILES), \
+ DEST := $(SLEEF_TARGET_DIR), \
+))
+
+TARGETS := $(copy_generated_sleef_source)
+
+################################################################################
+
+all: $(TARGETS)
+
+.PHONY: all default
diff --git a/make/ZipSecurity.gmk b/make/ZipSecurity.gmk
index 00b552fae0a..373ba13ecc6 100644
--- a/make/ZipSecurity.gmk
+++ b/make/ZipSecurity.gmk
@@ -29,11 +29,11 @@ include $(SPEC)
include MakeBase.gmk
include JavaCompilation.gmk
-##########################################################################################
+################################################################################
#
# sec-bin.zip is used by builds where the corresponding sources are not available
#
-$(eval $(call SetupZipArchive,BUILD_SEC_BIN_ZIP, \
+$(eval $(call SetupZipArchive, BUILD_SEC_BIN_ZIP, \
SRC := $(JDK_OUTPUTDIR), \
INCLUDES := \
modules/java.base/javax/crypto \
@@ -60,20 +60,22 @@ $(eval $(call SetupZipArchive,BUILD_SEC_BIN_ZIP, \
modules/java.security.jgss/sun/security/krb5/internal/util, \
INCLUDE_FILES := modules/java.security.jgss/sun/security/jgss/spi/GSSContextSpi.class, \
EXCLUDES := modules/java.security.jgss/sun/security/krb5/internal/tools, \
- ZIP := $(IMAGES_OUTPUTDIR)/sec-bin.zip))
+ ZIP := $(IMAGES_OUTPUTDIR)/sec-bin.zip, \
+))
TARGETS += $(IMAGES_OUTPUTDIR)/sec-bin.zip
-##########################################################################################
+################################################################################
#
# Windows specific binary security packages.
#
ifeq ($(call isTargetOs, windows), true)
# sec-windows-bin.zip is used by builds where the corresponding sources are not available
- $(eval $(call SetupZipArchive,BUILD_SEC_WINDOWS_BIN_ZIP, \
+ $(eval $(call SetupZipArchive, BUILD_SEC_WINDOWS_BIN_ZIP, \
SRC := $(JDK_OUTPUTDIR), \
INCLUDES := modules/java.security.jgss/sun/security/krb5/internal/tools, \
- ZIP := $(IMAGES_OUTPUTDIR)/sec-windows-bin.zip))
+ ZIP := $(IMAGES_OUTPUTDIR)/sec-windows-bin.zip, \
+ ))
TARGETS += $(IMAGES_OUTPUTDIR)/sec-windows-bin.zip
@@ -84,18 +86,19 @@ ifeq ($(call isTargetOs, windows), true)
JGSS_ZIP_NAME = jgss-windows-i586-bin.zip
endif
- $(eval $(call SetupZipArchive,BUILD_JGSS_BIN_ZIP, \
+ $(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.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)))
+ ZIP := $(IMAGES_OUTPUTDIR)/$(JGSS_ZIP_NAME), \
+ ))
TARGETS += $(IMAGES_OUTPUTDIR)/$(JGSS_ZIP_NAME)
endif
-##########################################################################################
+################################################################################
all: $(TARGETS)
diff --git a/make/autoconf/Makefile.template b/make/autoconf/Makefile.template
index 4cb5057c05c..ee33d0dfb9e 100644
--- a/make/autoconf/Makefile.template
+++ b/make/autoconf/Makefile.template
@@ -23,5 +23,5 @@
# This Makefile was generated by configure @DATE_WHEN_CONFIGURED@
# GENERATED FILE, DO NOT EDIT
-SPEC:=@OUTPUTDIR@/spec.gmk
+SPEC := @OUTPUTDIR@/spec.gmk
include @WORKSPACE_ROOT@/Makefile
diff --git a/make/autoconf/basic.m4 b/make/autoconf/basic.m4
index 91d7a550108..585575240ea 100644
--- a/make/autoconf/basic.m4
+++ b/make/autoconf/basic.m4
@@ -26,7 +26,7 @@
m4_include([basic_tools.m4])
m4_include([basic_windows.m4])
-###############################################################################
+################################################################################
AC_DEFUN_ONCE([BASIC_INIT],
[
# Save the original command line. This is passed to us by the wrapper configure script.
@@ -46,7 +46,7 @@ AC_DEFUN_ONCE([BASIC_INIT],
AC_MSG_NOTICE([Configuration created at $DATE_WHEN_CONFIGURED.])
])
-###############################################################################
+################################################################################
# Check that there are no unprocessed overridden variables left.
# If so, they are an incorrect argument and we will exit with an error.
AC_DEFUN([BASIC_CHECK_LEFTOVER_OVERRIDDEN],
@@ -58,7 +58,7 @@ AC_DEFUN([BASIC_CHECK_LEFTOVER_OVERRIDDEN],
fi
])
-###############################################################################
+################################################################################
# Setup basic configuration paths, and platform-specific stuff related to PATHs.
# Make sure to only use tools set up in BASIC_SETUP_FUNDAMENTAL_TOOLS.
AC_DEFUN_ONCE([BASIC_SETUP_PATHS],
@@ -102,7 +102,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_PATHS],
AUTOCONF_DIR=$TOPDIR/make/autoconf
])
-###############################################################################
+################################################################################
# Setup what kind of build environment type we have (CI or local developer)
AC_DEFUN_ONCE([BASIC_SETUP_BUILD_ENV],
[
@@ -141,7 +141,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_BUILD_ENV],
AC_SUBST(LOCALE_USED)
])
-###############################################################################
+################################################################################
# Evaluates platform specific overrides for devkit variables.
# $1: Name of variable
AC_DEFUN([BASIC_EVAL_DEVKIT_VARIABLE],
@@ -151,7 +151,7 @@ AC_DEFUN([BASIC_EVAL_DEVKIT_VARIABLE],
fi
])
-###############################################################################
+################################################################################
# Evaluates platform specific overrides for build devkit variables.
# $1: Name of variable
AC_DEFUN([BASIC_EVAL_BUILD_DEVKIT_VARIABLE],
@@ -161,7 +161,7 @@ AC_DEFUN([BASIC_EVAL_BUILD_DEVKIT_VARIABLE],
fi
])
-###############################################################################
+################################################################################
AC_DEFUN([BASIC_SETUP_XCODE_SYSROOT],
[
AC_MSG_CHECKING([for sdk name])
@@ -246,7 +246,7 @@ AC_DEFUN([BASIC_SETUP_XCODE_SYSROOT],
fi
])
-###############################################################################
+################################################################################
AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT],
[
AC_ARG_WITH([devkit], [AS_HELP_STRING([--with-devkit],
@@ -380,7 +380,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT],
AC_MSG_RESULT([$EXTRA_PATH])
])
-###############################################################################
+################################################################################
AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR],
[
@@ -477,7 +477,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR],
AC_CONFIG_FILES([$OUTPUTDIR/Makefile:$AUTOCONF_DIR/Makefile.template])
])
-###############################################################################
+################################################################################
# Check if build directory is on local disk. If not possible to determine,
# we prefer to claim it's local.
# Argument 1: directory to test
@@ -514,7 +514,7 @@ AC_DEFUN([BASIC_CHECK_DIR_ON_LOCAL_DISK],
fi
])
-###############################################################################
+################################################################################
# Check that source files have basic read permissions set. This might
# not be the case in cygwin in certain conditions.
AC_DEFUN_ONCE([BASIC_CHECK_SRC_PERMS],
@@ -529,7 +529,7 @@ AC_DEFUN_ONCE([BASIC_CHECK_SRC_PERMS],
fi
])
-###############################################################################
+################################################################################
AC_DEFUN_ONCE([BASIC_TEST_USABILITY_ISSUES],
[
AC_MSG_CHECKING([if build directory is on local disk])
@@ -572,7 +572,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEFAULT_MAKE_TARGET],
AC_SUBST(DEFAULT_MAKE_TARGET)
])
-###############################################################################
+################################################################################
# Setup the default value for LOG=
#
AC_DEFUN_ONCE([BASIC_SETUP_DEFAULT_LOG],
@@ -591,7 +591,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEFAULT_LOG],
AC_SUBST(DEFAULT_LOG)
])
-###############################################################################
+################################################################################
# Code to run after AC_OUTPUT
AC_DEFUN_ONCE([BASIC_POST_CONFIG_OUTPUT],
[
diff --git a/make/autoconf/basic_tools.m4 b/make/autoconf/basic_tools.m4
index 0c084561f2e..eceb0ae6cc4 100644
--- a/make/autoconf/basic_tools.m4
+++ b/make/autoconf/basic_tools.m4
@@ -23,12 +23,12 @@
# questions.
#
-###############################################################################
+################################################################################
# It is recommended to use exactly this version of pandoc, especially for
# re-generating checked in html files
RECOMMENDED_PANDOC_VERSION=2.19.2
-###############################################################################
+################################################################################
# Setup the most fundamental tools, used for setting up build platform and
# path handling.
AC_DEFUN_ONCE([BASIC_SETUP_FUNDAMENTAL_TOOLS],
@@ -59,7 +59,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_FUNDAMENTAL_TOOLS],
UTIL_LOOKUP_PROGS(CMD, cmd.exe, $PATH:/cygdrive/c/windows/system32:/mnt/c/windows/system32:/c/windows/system32)
])
-###############################################################################
+################################################################################
# Setup further tools that should be resolved early but after setting up
# build platform and path handling.
AC_DEFUN_ONCE([BASIC_SETUP_TOOLS],
@@ -99,6 +99,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_TOOLS],
UTIL_REQUIRE_SPECIAL(FGREP, [AC_PROG_FGREP])
# Optional tools, we can do without them
+ UTIL_LOOKUP_PROGS(CMAKE, cmake)
UTIL_LOOKUP_PROGS(DF, df)
UTIL_LOOKUP_PROGS(GIT, git)
UTIL_LOOKUP_PROGS(NICE, nice)
@@ -116,7 +117,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_TOOLS],
RM="$RM -f"
])
-###############################################################################
+################################################################################
# Check if we have found a usable version of make
# $1: the path to a potential make binary (or empty)
# $2: the description on how we found this
@@ -129,7 +130,7 @@ AC_DEFUN([BASIC_CHECK_MAKE_VERSION],
if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
MAKE_VERSION_EXPR="-e 4\."
MAKE_REQUIRED_VERSION="4.0"
- else
+ else
MAKE_VERSION_EXPR="-e 3\.8[[12]] -e 4\."
MAKE_REQUIRED_VERSION="3.81"
fi
@@ -176,7 +177,7 @@ AC_DEFUN([BASIC_CHECK_MAKE_VERSION],
fi
])
-###############################################################################
+################################################################################
AC_DEFUN([BASIC_CHECK_MAKE_OUTPUT_SYNC],
[
# Check if make supports the output sync option and if so, setup using it.
@@ -201,7 +202,7 @@ AC_DEFUN([BASIC_CHECK_MAKE_OUTPUT_SYNC],
AC_SUBST(OUTPUT_SYNC)
])
-###############################################################################
+################################################################################
# Goes looking for a usable version of GNU make.
AC_DEFUN([BASIC_CHECK_GNU_MAKE],
[
@@ -249,7 +250,7 @@ AC_DEFUN([BASIC_CHECK_GNU_MAKE],
BASIC_CHECK_MAKE_OUTPUT_SYNC
])
-###############################################################################
+################################################################################
AC_DEFUN([BASIC_CHECK_FIND_DELETE],
[
# Test if find supports -delete
@@ -278,7 +279,7 @@ AC_DEFUN([BASIC_CHECK_FIND_DELETE],
AC_SUBST(FIND_DELETE)
])
-###############################################################################
+################################################################################
AC_DEFUN([BASIC_CHECK_TAR],
[
# Test which kind of tar was found
@@ -316,7 +317,7 @@ AC_DEFUN([BASIC_CHECK_TAR],
AC_SUBST(TAR_SUPPORTS_TRANSFORM)
])
-###############################################################################
+################################################################################
AC_DEFUN([BASIC_CHECK_GREP],
[
# Test that grep supports -Fx with a list of pattern which includes null pattern.
@@ -340,7 +341,7 @@ AC_DEFUN([BASIC_CHECK_GREP],
fi
])
-###############################################################################
+################################################################################
AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS],
[
BASIC_CHECK_GNU_MAKE
@@ -412,7 +413,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS],
fi
])
-###############################################################################
+################################################################################
# Check for support for specific options in bash
AC_DEFUN_ONCE([BASIC_CHECK_BASH_OPTIONS],
[
diff --git a/make/autoconf/boot-jdk.m4 b/make/autoconf/boot-jdk.m4
index 8d272c28ad5..d729012ad6a 100644
--- a/make/autoconf/boot-jdk.m4
+++ b/make/autoconf/boot-jdk.m4
@@ -23,7 +23,7 @@
# questions.
#
-########################################################################
+################################################################################
# This file handles detection of the Boot JDK. The Boot JDK detection
# process has been developed as a response to solve a complex real-world
# problem. Initially, it was simple, but it has grown as platform after
@@ -49,7 +49,7 @@
# JDK, and if one is found, check if it is acceptable. If not, we print
# our reasons for rejecting it (useful when debugging non-working
# configure situations) and continue checking the next one.
-########################################################################
+################################################################################
# Execute the check given as argument, and verify the result
# If the Boot JDK was previously found, do nothing
@@ -322,7 +322,7 @@ AC_DEFUN([BOOTJDK_SETUP_CLASSPATH],
AC_SUBST(CLASSPATH)
])
-###############################################################################
+################################################################################
#
# We need a Boot JDK to bootstrap the build.
#
@@ -602,11 +602,12 @@ AC_DEFUN([BOOTJDK_SETUP_BUILD_JDK],
BUILD_JDK_FOUND="no"
if test "x$with_build_jdk" != "x"; then
BOOTJDK_CHECK_BUILD_JDK([
- if test "x$with_build_jdk" != x; then
- BUILD_JDK=$with_build_jdk
- BUILD_JDK_FOUND=maybe
- AC_MSG_NOTICE([Found potential Build JDK using configure arguments])
- fi])
+ if test "x$with_build_jdk" != x; then
+ BUILD_JDK=$with_build_jdk
+ BUILD_JDK_FOUND=maybe
+ AC_MSG_NOTICE([Found potential Build JDK using configure arguments])
+ fi
+ ])
EXTERNAL_BUILDJDK=true
else
if test "x$COMPILE_TYPE" = "xcross"; then
diff --git a/make/autoconf/bootcycle-spec.gmk.template b/make/autoconf/bootcycle-spec.gmk.template
index d46621fd891..a476fe8a27e 100644
--- a/make/autoconf/bootcycle-spec.gmk.template
+++ b/make/autoconf/bootcycle-spec.gmk.template
@@ -34,10 +34,10 @@ include @SPEC@
BOOT_JDK := $(JDK_IMAGE_DIR)
# The bootcycle build has a different output directory
-OLD_OUTPUTDIR:=@OUTPUTDIR@
-OUTPUTDIR:=$(OLD_OUTPUTDIR)/bootcycle-build
+OLD_OUTPUTDIR := @OUTPUTDIR@
+OUTPUTDIR := $(OLD_OUTPUTDIR)/bootcycle-build
# No spaces in patsubst to avoid leading space in variable
-JAVAC_SERVER_DIR:=$(patsubst $(OLD_OUTPUTDIR)%,$(OUTPUTDIR)%,$(JAVAC_SERVER_DIR))
+JAVAC_SERVER_DIR := $(patsubst $(OLD_OUTPUTDIR)%,$(OUTPUTDIR)%,$(JAVAC_SERVER_DIR))
JAVA_CMD := $(FIXPATH) $(BOOT_JDK)/bin/java
JAVAC_CMD := $(FIXPATH) $(BOOT_JDK)/bin/javac
@@ -48,4 +48,3 @@ JAVA_FLAGS_BIG := @BOOTCYCLE_JVM_ARGS_BIG@
# By filtering out those JVM args, the bootcycle JVM will use its default
# settings for CDS.
JAVA_FLAGS := $(filter-out -XX:SharedArchiveFile% -Xshare%, $(JAVA_FLAGS))
-
diff --git a/make/autoconf/compare.sh.template b/make/autoconf/compare.sh.template
index ad53a44dc0e..bcb5608855a 100644
--- a/make/autoconf/compare.sh.template
+++ b/make/autoconf/compare.sh.template
@@ -26,7 +26,7 @@
# the root of the build directory.
-##########################################################################################
+################################################################################
# Substitutions from autoconf
export LEGACY_BUILD_DIR=@OPENJDK_TARGET_OS@-@OPENJDK_TARGET_CPU_LEGACY@
diff --git a/make/autoconf/configure.ac b/make/autoconf/configure.ac
index 6afa36ac18d..21bf61a3fa1 100644
--- a/make/autoconf/configure.ac
+++ b/make/autoconf/configure.ac
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -23,11 +23,11 @@
# questions.
#
-###############################################################################
+################################################################################
#
# Includes and boilerplate
#
-###############################################################################
+################################################################################
AC_PREREQ([2.69])
@@ -63,14 +63,14 @@ m4_include([platform.m4])
m4_include([source-dirs.m4])
m4_include([toolchain.m4])
-###############################################################################
+################################################################################
#
# Initialization / Boot-strapping
#
# The bootstrapping process needs to solve the "chicken or the egg" problem,
# thus it jumps back and forth, each time gaining something needed later on.
#
-###############################################################################
+################################################################################
# If we are requested to print additional help, do that and then exit.
# This must be the very first call.
@@ -128,51 +128,51 @@ PLATFORM_SETUP_OPENJDK_BUILD_OS_VERSION
BASIC_SETUP_DEFAULT_MAKE_TARGET
BASIC_SETUP_DEFAULT_LOG
-###############################################################################
+################################################################################
#
# Determine OpenJDK variants and version numbers.
#
-###############################################################################
+################################################################################
# We need build & target for this.
JDKOPT_SETUP_JMOD_OPTIONS
JDKOPT_SETUP_JLINK_OPTIONS
JDKVER_SETUP_JDK_VERSION_NUMBERS
-###############################################################################
+################################################################################
#
# Setup BootJDK, used to bootstrap the build.
#
-###############################################################################
+################################################################################
BOOTJDK_SETUP_BOOT_JDK
BOOTJDK_SETUP_BUILD_JDK
BOOTJDK_SETUP_DOCS_REFERENCE_JDK
-###############################################################################
+################################################################################
#
# Determine JDK specific build time options.
#
-###############################################################################
+################################################################################
JDKOPT_SETUP_REPRODUCIBLE_BUILD
JDKOPT_SETUP_JDK_OPTIONS
-###############################################################################
+################################################################################
#
# Configure the sources to use. We can add or override individual directories.
#
-###############################################################################
+################################################################################
SRCDIRS_SETUP_DIRS
SRCDIRS_SETUP_IMPORT_MODULES
-###############################################################################
+################################################################################
#
# Setup the toolchain (compilers etc), i.e. tools used to compile and process
# native code.
#
-###############################################################################
+################################################################################
# See if we are doing a complete static build or not
JDKOPT_SETUP_STATIC_BUILD
@@ -202,6 +202,7 @@ FLAGS_POST_TOOLCHAIN
LIB_TESTS_SETUP_JTREG
LIB_TESTS_SETUP_JMH
LIB_TESTS_SETUP_JIB
+LIB_TESTS_SETUP_TIDY
# Now we can test some aspects on the target using configure macros.
PLATFORM_SETUP_OPENJDK_TARGET_BITS
@@ -227,31 +228,31 @@ JDKOPT_SETUP_LEAK_SANITIZER
# This needs to go before 'LIB_DETERMINE_DEPENDENCIES'
JDKOPT_SETUP_FALLBACK_LINKER
-###############################################################################
+################################################################################
#
# Check dependencies for external and internal libraries.
#
-###############################################################################
+################################################################################
LIB_DETERMINE_DEPENDENCIES
LIB_SETUP_LIBRARIES
-###############################################################################
+################################################################################
#
# Setup hotspot and JVM features (needs toolchain).
#
-###############################################################################
+################################################################################
JVM_FEATURES_PARSE_OPTIONS
JVM_FEATURES_SETUP
HOTSPOT_SETUP_MISC
-###############################################################################
+################################################################################
#
# We need to do some final tweaking, when everything else is done.
#
-###############################################################################
+################################################################################
LIB_TESTS_ENABLE_DISABLE_FAILURE_HANDLER
LIB_TESTS_ENABLE_DISABLE_JTREG_TEST_THREAD_FACTORY
@@ -263,12 +264,12 @@ JDKOPT_ENABLE_DISABLE_CDS_ARCHIVE
JDKOPT_ENABLE_DISABLE_COMPATIBLE_CDS_ALIGNMENT
JDKOPT_SETUP_MACOSX_SIGNING
-###############################################################################
+################################################################################
#
# Configure parts of the build that only affect the build performance,
# not the result.
#
-###############################################################################
+################################################################################
BPERF_SETUP_BUILD_CORES
BPERF_SETUP_BUILD_MEMORY
@@ -288,11 +289,11 @@ BPERF_SETUP_PRECOMPILED_HEADERS
# Setup use of ccache, if available
BPERF_SETUP_CCACHE
-###############################################################################
+################################################################################
#
# And now the finish...
#
-###############################################################################
+################################################################################
# Check for some common pitfalls
BASIC_TEST_USABILITY_ISSUES
@@ -313,9 +314,11 @@ AC_OUTPUT
# After AC_OUTPUT, we need to do final work
CUSTOM_CONFIG_OUTPUT_GENERATED_HOOK
-BASIC_POST_CONFIG_OUTPUT
# Finally output some useful information to the user
HELP_PRINT_SUMMARY_AND_WARNINGS
CUSTOM_SUMMARY_AND_WARNINGS_HOOK
HELP_REPEAT_WARNINGS
+
+# All output is done. Do the post-config output management.
+BASIC_POST_CONFIG_OUTPUT
diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4
index da63a6dba06..bd8f2ec9a7f 100644
--- a/make/autoconf/flags-cflags.m4
+++ b/make/autoconf/flags-cflags.m4
@@ -235,14 +235,16 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS],
CFLAGS_WARNINGS_ARE_ERRORS="-Werror"
# Additional warnings that are not activated by -Wall and -Wextra
- WARNINGS_ENABLE_ADDITIONAL="-Wpointer-arith -Wsign-compare \
- -Wunused-function -Wundef -Wunused-value -Wreturn-type \
- -Wtrampolines"
+ WARNINGS_ENABLE_ADDITIONAL="-Wpointer-arith -Wreturn-type -Wsign-compare \
+ -Wtrampolines -Wundef -Wunused-const-variable=1 -Wunused-function \
+ -Wunused-result -Wunused-value"
WARNINGS_ENABLE_ADDITIONAL_CXX="-Woverloaded-virtual -Wreorder"
WARNINGS_ENABLE_ALL_CFLAGS="-Wall -Wextra -Wformat=2 $WARNINGS_ENABLE_ADDITIONAL"
WARNINGS_ENABLE_ALL_CXXFLAGS="$WARNINGS_ENABLE_ALL_CFLAGS $WARNINGS_ENABLE_ADDITIONAL_CXX"
- DISABLED_WARNINGS="unused-parameter unused"
+ # These warnings will never be turned on, since they generate too many
+ # false positives.
+ DISABLED_WARNINGS="unused-parameter"
# gcc10/11 on ppc generate lots of abi warnings about layout of aggregates containing vectors
if test "x$OPENJDK_TARGET_CPU_ARCH" = "xppc"; then
DISABLED_WARNINGS="$DISABLED_WARNINGS psabi"
@@ -259,7 +261,9 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS],
-Wunused-function -Wundef -Wunused-value -Woverloaded-virtual"
WARNINGS_ENABLE_ALL="-Wall -Wextra -Wformat=2 $WARNINGS_ENABLE_ADDITIONAL"
- DISABLED_WARNINGS="unknown-warning-option unused-parameter unused"
+ # These warnings will never be turned on, since they generate too many
+ # false positives.
+ DISABLED_WARNINGS="unknown-warning-option unused-parameter"
;;
esac
AC_SUBST(DISABLE_WARNING_PREFIX)
@@ -476,7 +480,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
# Always enable optional macros for VM.
ALWAYS_CFLAGS_JVM="-D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS"
- ###############################################################################
+ ##############################################################################
# Adjust flags according to debug level.
# Setup debug/release defines
@@ -510,7 +514,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
ALWAYS_DEFINES_JVM="$ALWAYS_DEFINES -DNOMINMAX"
fi
- ###############################################################################
+ ##############################################################################
#
#
# CFLAGS BASIC
@@ -932,15 +936,13 @@ AC_DEFUN_ONCE([FLAGS_SETUP_BRANCH_PROTECTION],
if test "x$OPENJDK_TARGET_CPU" = xaarch64; then
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
- FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${BRANCH_PROTECTION_FLAG}],
+ FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$BRANCH_PROTECTION_FLAG],
IF_TRUE: [BRANCH_PROTECTION_AVAILABLE=true])
fi
fi
- BRANCH_PROTECTION_CFLAGS=""
UTIL_ARG_ENABLE(NAME: branch-protection, DEFAULT: false,
- RESULT: USE_BRANCH_PROTECTION, AVAILABLE: $BRANCH_PROTECTION_AVAILABLE,
+ RESULT: BRANCH_PROTECTION_ENABLED, AVAILABLE: $BRANCH_PROTECTION_AVAILABLE,
DESC: [enable branch protection when compiling C/C++],
- IF_ENABLED: [ BRANCH_PROTECTION_CFLAGS=${BRANCH_PROTECTION_FLAG}])
- AC_SUBST(BRANCH_PROTECTION_CFLAGS)
+ IF_ENABLED: [BRANCH_PROTECTION_CFLAGS=$BRANCH_PROTECTION_FLAG])
])
diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4
index a2d0d4e606a..8183a0af7d0 100644
--- a/make/autoconf/flags-ldflags.m4
+++ b/make/autoconf/flags-ldflags.m4
@@ -71,7 +71,9 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
LDFLAGS_CXX_PARTIAL_LINKING="$MACHINE_FLAG -r"
if test "x$OPENJDK_TARGET_OS" = xlinux; then
+ # Clang needs the lld linker to work correctly
BASIC_LDFLAGS="-fuse-ld=lld -Wl,--exclude-libs,ALL"
+ UTIL_REQUIRE_PROGS(LLD, lld)
fi
if test "x$OPENJDK_TARGET_OS" = xaix; then
BASIC_LDFLAGS="-Wl,-b64 -Wl,-brtl -Wl,-bnorwexec -Wl,-bnolibpath -Wl,-bnoexpall \
@@ -166,9 +168,9 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_CPU_DEP],
# MIPS ABI does not support GNU hash style
if test "x${OPENJDK_$1_CPU}" = xmips ||
- test "x${OPENJDK_$1_CPU}" = xmipsel ||
- test "x${OPENJDK_$1_CPU}" = xmips64 ||
- test "x${OPENJDK_$1_CPU}" = xmips64el; then
+ test "x${OPENJDK_$1_CPU}" = xmipsel ||
+ test "x${OPENJDK_$1_CPU}" = xmips64 ||
+ test "x${OPENJDK_$1_CPU}" = xmips64el; then
$1_CPU_LDFLAGS="${$1_CPU_LDFLAGS} -Wl,--hash-style=sysv"
else
$1_CPU_LDFLAGS="${$1_CPU_LDFLAGS} -Wl,--hash-style=gnu"
diff --git a/make/autoconf/flags-other.m4 b/make/autoconf/flags-other.m4
index 8d4d405b076..f0fa82489df 100644
--- a/make/autoconf/flags-other.m4
+++ b/make/autoconf/flags-other.m4
@@ -150,5 +150,9 @@ AC_DEFUN([FLAGS_SETUP_ASFLAGS_CPU_DEP],
$2JVM_ASFLAGS="${$2JVM_ASFLAGS} $ARM_ARCH_TYPE_ASFLAGS $ARM_FLOAT_TYPE_ASFLAGS"
fi
+ if test "x$BRANCH_PROTECTION_ENABLED" = "xtrue"; then
+ $2JVM_ASFLAGS="${$2JVM_ASFLAGS} $BRANCH_PROTECTION_FLAG"
+ fi
+
AC_SUBST($2JVM_ASFLAGS)
])
diff --git a/make/autoconf/hotspot.m4 b/make/autoconf/hotspot.m4
index adbf538fd7d..a95ed1fbacd 100644
--- a/make/autoconf/hotspot.m4
+++ b/make/autoconf/hotspot.m4
@@ -26,7 +26,7 @@
# All valid JVM variants
VALID_JVM_VARIANTS="server client minimal core zero custom"
-###############################################################################
+################################################################################
# Check if the specified JVM variant should be built. To be used in shell if
# constructs, like this:
# if HOTSPOT_CHECK_JVM_VARIANT(server); then
@@ -38,7 +38,7 @@ VALID_JVM_VARIANTS="server client minimal core zero custom"
AC_DEFUN([HOTSPOT_CHECK_JVM_VARIANT],
[ [ [[ " $JVM_VARIANTS " =~ " $1 " ]] ] ])
-###############################################################################
+################################################################################
# Check which variants of the JVM that we want to build. Available variants are:
# server: normal interpreter, and a tiered C1/C2 compiler
# client: normal interpreter, and C1 (no C2 compiler)
@@ -102,7 +102,7 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_VARIANTS],
AC_SUBST(JVM_VARIANT_MAIN)
])
-###############################################################################
+################################################################################
# Misc hotspot setup that does not fit elsewhere.
#
AC_DEFUN_ONCE([HOTSPOT_SETUP_MISC],
diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4
index 76e95127f73..11c55c78930 100644
--- a/make/autoconf/jdk-options.m4
+++ b/make/autoconf/jdk-options.m4
@@ -23,7 +23,7 @@
# questions.
#
-###############################################################################
+################################################################################
# Set the debug level
# release: no debug information, all optimizations, no asserts.
# optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'.
@@ -81,7 +81,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL],
AC_SUBST(DEBUG_LEVEL)
])
-###############################################################################
+################################################################################
#
# Should we build only OpenJDK even if closed sources are present?
#
@@ -235,8 +235,8 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS],
else
HOTSPOT_OVERRIDE_LIBPATH=${with_jni_libpath}
if test "x$OPENJDK_TARGET_OS" != "xlinux" &&
- test "x$OPENJDK_TARGET_OS" != "xbsd" &&
- test "x$OPENJDK_TARGET_OS" != "xaix"; then
+ test "x$OPENJDK_TARGET_OS" != "xbsd" &&
+ test "x$OPENJDK_TARGET_OS" != "xaix"; then
AC_MSG_RESULT([fail])
AC_MSG_ERROR([Overriding JNI library path is supported only on Linux, BSD and AIX.])
fi
@@ -246,7 +246,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS],
])
-###############################################################################
+################################################################################
AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS],
[
@@ -410,7 +410,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_CODE_COVERAGE],
AC_SUBST(JCOV_FILTERS)
])
-###############################################################################
+################################################################################
#
# AddressSanitizer
#
@@ -421,8 +421,8 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_ADDRESS_SANITIZER],
CHECK_AVAILABLE: [
AC_MSG_CHECKING([if AddressSanitizer (asan) is available])
if test "x$TOOLCHAIN_TYPE" = "xgcc" ||
- test "x$TOOLCHAIN_TYPE" = "xclang" ||
- test "x$TOOLCHAIN_TYPE" = "xmicrosoft"; then
+ test "x$TOOLCHAIN_TYPE" = "xclang" ||
+ test "x$TOOLCHAIN_TYPE" = "xmicrosoft"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
@@ -431,7 +431,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_ADDRESS_SANITIZER],
],
IF_ENABLED: [
if test "x$TOOLCHAIN_TYPE" = "xgcc" ||
- test "x$TOOLCHAIN_TYPE" = "xclang"; then
+ test "x$TOOLCHAIN_TYPE" = "xclang"; then
# ASan is simply incompatible with gcc -Wstringop-truncation. See
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85650
# It's harmless to be suppressed in clang as well.
@@ -467,7 +467,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_ADDRESS_SANITIZER],
AC_SUBST(ASAN_ENABLED)
])
-###############################################################################
+################################################################################
#
# LeakSanitizer
#
@@ -500,7 +500,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_LEAK_SANITIZER],
AC_SUBST(LSAN_ENABLED)
])
-###############################################################################
+################################################################################
#
# UndefinedBehaviorSanitizer
#
@@ -707,9 +707,8 @@ AC_DEFUN([JDKOPT_ALLOW_ABSOLUTE_PATHS_IN_OUTPUT],
[
AC_ARG_ENABLE([absolute-paths-in-output],
[AS_HELP_STRING([--disable-absolute-paths-in-output],
- [Set to disable to prevent any absolute paths from the build to end up in
- any of the build output. @<:@disabled in release builds, otherwise enabled@:>@])
- ])
+ [Set to disable to prevent any absolute paths from the build to end up in
+ any of the build output. @<:@disabled in release builds, otherwise enabled@:>@])])
AC_MSG_CHECKING([if absolute paths should be allowed in the build output])
if test "x$enable_absolute_paths_in_output" = "xno"; then
diff --git a/make/autoconf/jdk-version.m4 b/make/autoconf/jdk-version.m4
index 7c9ecad7779..297a6e83b5c 100644
--- a/make/autoconf/jdk-version.m4
+++ b/make/autoconf/jdk-version.m4
@@ -23,7 +23,7 @@
# questions.
#
-###############################################################################
+################################################################################
#
# Setup version numbers
#
@@ -93,7 +93,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS],
UTIL_ARG_WITH(NAME: jdk-rc-name, TYPE: string,
DEFAULT: $PRODUCT_NAME $JDK_RC_PLATFORM_NAME,
DESC: [Set JDK RC name. This is used for FileDescription and ProductName
- properties of MS Windows binaries.],
+ properties of MS Windows binaries.],
DEFAULT_DESC: [from branding.conf],
CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE])
AC_SUBST(JDK_RC_NAME)
@@ -105,7 +105,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS],
RESULT: COMPANY_NAME,
DEFAULT: $COMPANY_NAME,
DESC: [Set vendor name. Among others, used to set the 'java.vendor'
- and 'java.vm.vendor' system properties.],
+ and 'java.vm.vendor' system properties.],
DEFAULT_DESC: [from branding.conf],
CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE])
AC_SUBST(COMPANY_NAME)
diff --git a/make/autoconf/jvm-features.m4 b/make/autoconf/jvm-features.m4
index bdf92d701b9..9695644bafe 100644
--- a/make/autoconf/jvm-features.m4
+++ b/make/autoconf/jvm-features.m4
@@ -23,7 +23,7 @@
# questions.
#
-###############################################################################
+################################################################################
# Terminology used in this file:
#
# Valid features == All possible features that the JVM knows about.
@@ -36,7 +36,7 @@
#
# All valid features are considered available, unless listed as unavailable.
# All available features will be turned on as default, unless listed in a filter.
-###############################################################################
+################################################################################
# We need these as m4 defines to be able to loop over them using m4 later on.
@@ -78,7 +78,7 @@ m4_define(jvm_feature_desc_vm_structs, [export JVM structures to the Serviceabli
m4_define(jvm_feature_desc_zero, [support building variant 'zero'])
m4_define(jvm_feature_desc_zgc, [include the Z garbage collector])
-###############################################################################
+################################################################################
# Parse command line options for JVM feature selection. After this function
# has run $JVM_FEATURES_ENABLED, $JVM_FEATURES_DISABLED and $JVM_FEATURES_VALID
# can be used.
@@ -199,7 +199,7 @@ AC_DEFUN_ONCE([JVM_FEATURES_PARSE_OPTIONS],
AC_SUBST(VALID_JVM_FEATURES)
])
-###############################################################################
+################################################################################
# Helper function for the JVM_FEATURES_CHECK_* suite.
# The code in the code block should assign 'false' to the variable AVAILABLE
# if the feature is not available, and this function will handle everything
@@ -225,7 +225,7 @@ AC_DEFUN([JVM_FEATURES_CHECK_AVAILABILITY],
fi
])
-###############################################################################
+################################################################################
# Check if the feature 'cds' is available on this platform.
#
AC_DEFUN_ONCE([JVM_FEATURES_CHECK_CDS],
@@ -241,7 +241,7 @@ AC_DEFUN_ONCE([JVM_FEATURES_CHECK_CDS],
])
])
-###############################################################################
+################################################################################
# Check if the feature 'dtrace' is available on this platform.
#
AC_DEFUN_ONCE([JVM_FEATURES_CHECK_DTRACE],
@@ -270,7 +270,7 @@ AC_DEFUN_ONCE([JVM_FEATURES_CHECK_DTRACE],
])
])
-###############################################################################
+################################################################################
# Check if the feature 'jvmci' is available on this platform.
#
AC_DEFUN_ONCE([JVM_FEATURES_CHECK_JVMCI],
@@ -290,7 +290,7 @@ AC_DEFUN_ONCE([JVM_FEATURES_CHECK_JVMCI],
])
])
-###############################################################################
+################################################################################
# Check if the feature 'shenandoahgc' is available on this platform.
#
AC_DEFUN_ONCE([JVM_FEATURES_CHECK_SHENANDOAHGC],
@@ -309,7 +309,7 @@ AC_DEFUN_ONCE([JVM_FEATURES_CHECK_SHENANDOAHGC],
])
])
-###############################################################################
+################################################################################
# Check if the feature 'zgc' is available on this platform.
#
AC_DEFUN_ONCE([JVM_FEATURES_CHECK_ZGC],
@@ -365,7 +365,7 @@ AC_DEFUN_ONCE([JVM_FEATURES_CHECK_ZGC],
])
])
-###############################################################################
+################################################################################
# Setup JVM_FEATURES_PLATFORM_UNAVAILABLE and JVM_FEATURES_PLATFORM_FILTER
# to contain those features that are unavailable, or should be off by default,
# for this platform, regardless of JVM variant.
@@ -383,7 +383,7 @@ AC_DEFUN_ONCE([JVM_FEATURES_PREPARE_PLATFORM],
])
-###############################################################################
+################################################################################
# Setup JVM_FEATURES_VARIANT_UNAVAILABLE and JVM_FEATURES_VARIANT_FILTER
# to contain those features that are unavailable, or should be off by default,
# for this particular JVM variant.
@@ -431,7 +431,7 @@ AC_DEFUN([JVM_FEATURES_PREPARE_VARIANT],
fi
])
-###############################################################################
+################################################################################
# Calculate the actual set of active JVM features for this JVM variant. Store
# the result in JVM_FEATURES_ACTIVE.
#
@@ -479,7 +479,23 @@ AC_DEFUN([JVM_FEATURES_CALCULATE_ACTIVE],
$JVM_FEATURES_ENABLED, $JVM_FEATURES_DISABLED)
])
-###############################################################################
+################################################################################
+# Filter the unsupported feature combinations.
+# This is called after JVM_FEATURES_ACTIVE are fully populated.
+#
+AC_DEFUN([JVM_FEATURES_FILTER_UNSUPPORTED],
+[
+ # G1 late barrier expansion in C2 is not implemented for some platforms.
+ # Choose not to support G1 in this configuration.
+ if JVM_FEATURES_IS_ACTIVE(compiler2); then
+ if test "x$OPENJDK_TARGET_CPU" = "xx86"; then
+ AC_MSG_NOTICE([G1 cannot be used with C2 on this platform, disabling G1])
+ UTIL_GET_NON_MATCHING_VALUES(JVM_FEATURES_ACTIVE, $JVM_FEATURES_ACTIVE, "g1gc")
+ fi
+ fi
+])
+
+################################################################################
# Helper function for JVM_FEATURES_VERIFY. Check if the specified JVM
# feature is active. To be used in shell if constructs, like this:
# 'if JVM_FEATURES_IS_ACTIVE(jvmti); then'
@@ -489,7 +505,7 @@ AC_DEFUN([JVM_FEATURES_CALCULATE_ACTIVE],
AC_DEFUN([JVM_FEATURES_IS_ACTIVE],
[ [ [[ " $JVM_FEATURES_ACTIVE " =~ ' '$1' ' ]] ] ])
-###############################################################################
+################################################################################
# Verify that the resulting set of features is consistent and legal.
#
# arg 1: JVM variant
@@ -527,7 +543,7 @@ AC_DEFUN([JVM_FEATURES_VERIFY],
fi
])
-###############################################################################
+################################################################################
# Set up all JVM features for each enabled JVM variant. Requires that
# JVM_FEATURES_PARSE_OPTIONS has been called.
#
@@ -554,6 +570,9 @@ AC_DEFUN_ONCE([JVM_FEATURES_SETUP],
# The result is stored in JVM_FEATURES_ACTIVE.
JVM_FEATURES_CALCULATE_ACTIVE($variant)
+ # Filter unsupported feature combinations from JVM_FEATURES_ACTIVE.
+ JVM_FEATURES_FILTER_UNSUPPORTED
+
# Verify consistency for JVM_FEATURES_ACTIVE.
JVM_FEATURES_VERIFY($variant)
diff --git a/make/autoconf/lib-alsa.m4 b/make/autoconf/lib-alsa.m4
index 19a91f94809..8d0fb324cd0 100644
--- a/make/autoconf/lib-alsa.m4
+++ b/make/autoconf/lib-alsa.m4
@@ -70,6 +70,25 @@ AC_DEFUN_ONCE([LIB_SETUP_ALSA],
PKG_CHECK_MODULES(ALSA, alsa, [ALSA_FOUND=yes], [ALSA_FOUND=no])
fi
fi
+ if test "x$ALSA_FOUND" = xno; then
+ # If we have sysroot set, and no explicit library location is set,
+ # look at known locations in sysroot.
+ if test "x$SYSROOT" != "x" && test "x${with_alsa_lib}" == x; then
+ if test -f "$SYSROOT/usr/lib64/libasound.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
+ ALSA_LIBS="-L$SYSROOT/usr/lib64 -lasound"
+ ALSA_FOUND=yes
+ elif test -f "$SYSROOT/usr/lib/libasound.so"; then
+ ALSA_LIBS="-L$SYSROOT/usr/lib -lasound"
+ ALSA_FOUND=yes
+ elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libasound.so"; then
+ ALSA_LIBS="-L$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI -lasound"
+ ALSA_FOUND=yes
+ elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libasound.so"; then
+ ALSA_LIBS="-L$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI -lasound"
+ ALSA_FOUND=yes
+ fi
+ fi
+ fi
if test "x$ALSA_FOUND" = xno; then
AC_CHECK_HEADERS([alsa/asoundlib.h],
[
diff --git a/make/autoconf/lib-bundled.m4 b/make/autoconf/lib-bundled.m4
index 3e0217ac6bd..6987250e906 100644
--- a/make/autoconf/lib-bundled.m4
+++ b/make/autoconf/lib-bundled.m4
@@ -119,7 +119,7 @@ AC_DEFUN_ONCE([LIB_SETUP_GIFLIB],
AC_DEFUN_ONCE([LIB_SETUP_LIBPNG],
[
AC_ARG_WITH(libpng, [AS_HELP_STRING([--with-libpng],
- [use libpng from build system or OpenJDK source (system, bundled) @<:@bundled@:>@])])
+ [use libpng from build system or OpenJDK source (system, bundled) @<:@bundled@:>@])])
PKG_CHECK_MODULES(PNG, libpng, [LIBPNG_FOUND=yes], [LIBPNG_FOUND=no])
AC_MSG_CHECKING([for which libpng to use])
diff --git a/make/autoconf/lib-freetype.m4 b/make/autoconf/lib-freetype.m4
index 6a710934247..9171b7bfc2a 100644
--- a/make/autoconf/lib-freetype.m4
+++ b/make/autoconf/lib-freetype.m4
@@ -73,11 +73,11 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE],
[
AC_ARG_WITH(freetype, [AS_HELP_STRING([--with-freetype],
[specify whether to use 'system' or 'bundled' freetype.
- The selected option applies to both build time and run time.
- The default behaviour can be platform dependent.
- If using 'system' and either the include files or libraries cannot be
- located automatically, then additionally specify both using
- --with-freetype-include and --with-freetype-lib.])])
+ The selected option applies to both build time and run time.
+ The default behaviour can be platform dependent.
+ If using 'system' and either the include files or libraries cannot be
+ located automatically, then additionally specify both using
+ --with-freetype-include and --with-freetype-lib.])])
AC_ARG_WITH(freetype-include, [AS_HELP_STRING([--with-freetype-include],
[specify directory for the freetype include files])])
AC_ARG_WITH(freetype-lib, [AS_HELP_STRING([--with-freetype-lib],
@@ -95,8 +95,10 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE],
FREETYPE_CFLAGS=
FREETYPE_LIBS=
- if (test "x$with_freetype_include" = "x" && test "x$with_freetype_lib" != "x") || \
- (test "x$with_freetype_include" != "x" && test "x$with_freetype_lib" = "x"); then
+ if (test "x$with_freetype_include" = "x" && \
+ test "x$with_freetype_lib" != "x") || \
+ (test "x$with_freetype_include" != "x" && \
+ test "x$with_freetype_lib" = "x"); then
AC_MSG_ERROR([Must specify both or neither of --with-freetype-include and --with-freetype-lib])
fi
@@ -126,8 +128,8 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE],
fi
if test "x$FREETYPE_TO_USE" = "xsystem" && \
- (test "x$OPENJDK_TARGET_OS" = "xwindows" || \
- test "x$OPENJDK_TARGET_OS" = "xmacosx"); then
+ (test "x$OPENJDK_TARGET_OS" = "xwindows" || \
+ test "x$OPENJDK_TARGET_OS" = "xmacosx"); then
AC_MSG_ERROR([Only bundled freetype can be specified on Mac and Windows])
fi
diff --git a/make/autoconf/lib-hsdis.m4 b/make/autoconf/lib-hsdis.m4
index 9b9f24d0da1..bd78768d03e 100644
--- a/make/autoconf/lib-hsdis.m4
+++ b/make/autoconf/lib-hsdis.m4
@@ -163,8 +163,8 @@ AC_DEFUN([LIB_BUILD_BINUTILS],
# We don't know the version, not checking for libsframe.a
if test -e $BINUTILS_INSTALL_DIR/lib/libbfd.a && \
- test -e $BINUTILS_INSTALL_DIR/lib/libopcodes.a && \
- test -e $BINUTILS_INSTALL_DIR/lib/libiberty.a; then
+ test -e $BINUTILS_INSTALL_DIR/lib/libopcodes.a && \
+ test -e $BINUTILS_INSTALL_DIR/lib/libiberty.a; then
AC_MSG_NOTICE([Found binutils binaries in binutils install directory -- not building])
else
# On Windows, we cannot build with the normal Microsoft CL, but must instead use
@@ -267,8 +267,10 @@ AC_DEFUN([LIB_SETUP_HSDIS_BINUTILS],
elif test "x$BINUTILS_INSTALL_DIR" != x; then
disasm_header="\"$BINUTILS_INSTALL_DIR/include/dis-asm.h\""
if test -e $BINUTILS_INSTALL_DIR/lib/libbfd.a && \
- test -e $BINUTILS_INSTALL_DIR/lib/libopcodes.a && \
- (test -e $BINUTILS_INSTALL_DIR/lib/libiberty.a || test -e $BINUTILS_INSTALL_DIR/lib64/libiberty.a || test -e $BINUTILS_INSTALL_DIR/lib32/libiberty.a); then
+ test -e $BINUTILS_INSTALL_DIR/lib/libopcodes.a && \
+ (test -e $BINUTILS_INSTALL_DIR/lib/libiberty.a || \
+ test -e $BINUTILS_INSTALL_DIR/lib64/libiberty.a || \
+ test -e $BINUTILS_INSTALL_DIR/lib32/libiberty.a); then
HSDIS_CFLAGS="-DLIBARCH_$OPENJDK_TARGET_CPU_LEGACY_LIB -I$BINUTILS_INSTALL_DIR/include"
# libiberty ignores --libdir and may be installed in $BINUTILS_INSTALL_DIR/lib, $BINUTILS_INSTALL_DIR/lib32
diff --git a/make/autoconf/lib-tests.m4 b/make/autoconf/lib-tests.m4
index 955b8c9ba83..afb94030808 100644
--- a/make/autoconf/lib-tests.m4
+++ b/make/autoconf/lib-tests.m4
@@ -31,7 +31,7 @@
JTREG_MINIMUM_VERSION=7.4
GTEST_MINIMUM_VERSION=1.14.0
-###############################################################################
+################################################################################
#
# Setup and check for gtest framework source files
#
@@ -74,7 +74,7 @@ AC_DEFUN_ONCE([LIB_TESTS_SETUP_GTEST],
AC_SUBST(GTEST_FRAMEWORK_SRC)
])
-###############################################################################
+################################################################################
#
# Setup and check the Java Microbenchmark Harness
#
@@ -308,6 +308,32 @@ AC_DEFUN_ONCE([LIB_TESTS_SETUP_JIB],
AC_SUBST(JIB_HOME)
])
+# Setup the tidy html checker
+AC_DEFUN_ONCE([LIB_TESTS_SETUP_TIDY],
+[
+ UTIL_LOOKUP_PROGS(TIDY, tidy)
+
+ if test "x$TIDY" != x; then
+ AC_MSG_CHECKING([if tidy is working properly])
+ tidy_output=`$TIDY --version 2>&1`
+ if ! $ECHO "$tidy_output" | $GREP -q "HTML Tidy" 2>&1 > /dev/null; then
+ AC_MSG_RESULT([no])
+ AC_MSG_NOTICE([$TIDY is not a valid tidy executable and will be ignored. Output from --version: $tidy_output])
+ TIDY=
+ elif ! $ECHO "$tidy_output" | $GREP -q "version" 2>&1 > /dev/null; then
+ AC_MSG_RESULT([no])
+ AC_MSG_NOTICE([$TIDY is missing a proper version number and will be ignored. Output from --version: $tidy_output])
+ TIDY=
+ else
+ AC_MSG_RESULT([yes])
+ AC_MSG_CHECKING([for tidy version])
+ tidy_version=`$ECHO $tidy_output | $SED -e 's/.*version //g'`
+ AC_MSG_RESULT([$tidy_version])
+ fi
+ fi
+ AC_SUBST(TIDY)
+])
+
################################################################################
#
# Check if building of the jtreg failure handler should be enabled.
diff --git a/make/autoconf/lib-x11.m4 b/make/autoconf/lib-x11.m4
index b1902a432a1..6849b4a26c7 100644
--- a/make/autoconf/lib-x11.m4
+++ b/make/autoconf/lib-x11.m4
@@ -71,9 +71,9 @@ AC_DEFUN_ONCE([LIB_SETUP_X11],
elif test -f "$SYSROOT/usr/lib/libX11.so"; then
x_libraries="$SYSROOT/usr/lib"
elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so"; then
- x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so"
+ x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI"
elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so"; then
- x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so"
+ x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI"
fi
fi
fi
diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4
index e29ef2221a6..b68fef7bbba 100644
--- a/make/autoconf/libraries.m4
+++ b/make/autoconf/libraries.m4
@@ -99,12 +99,12 @@ AC_DEFUN([LIB_SETUP_JVM_LIBS],
if HOTSPOT_CHECK_JVM_VARIANT(zero); then
if test "x$OPENJDK_$1_OS" = xlinux &&
(test "x$OPENJDK_$1_CPU" = xarm ||
- test "x$OPENJDK_$1_CPU" = xm68k ||
- test "x$OPENJDK_$1_CPU" = xmips ||
- test "x$OPENJDK_$1_CPU" = xmipsel ||
- test "x$OPENJDK_$1_CPU" = xppc ||
- test "x$OPENJDK_$1_CPU" = xsh ||
- test "x$OPENJDK_$1_CPU" = xriscv32); then
+ test "x$OPENJDK_$1_CPU" = xm68k ||
+ test "x$OPENJDK_$1_CPU" = xmips ||
+ test "x$OPENJDK_$1_CPU" = xmipsel ||
+ test "x$OPENJDK_$1_CPU" = xppc ||
+ test "x$OPENJDK_$1_CPU" = xsh ||
+ test "x$OPENJDK_$1_CPU" = xriscv32); then
BASIC_JVM_LIBS_$1="$BASIC_JVM_LIBS_$1 -latomic"
fi
fi
diff --git a/make/autoconf/platform.m4 b/make/autoconf/platform.m4
index df610cc489b..9ca808c4c17 100644
--- a/make/autoconf/platform.m4
+++ b/make/autoconf/platform.m4
@@ -390,7 +390,7 @@ AC_DEFUN([PLATFORM_EXTRACT_TARGET_AND_BUILD],
AC_DEFUN([PLATFORM_SETUP_TARGET_CPU_BITS],
[
AC_ARG_WITH(target-bits, [AS_HELP_STRING([--with-target-bits],
- [build 32-bit or 64-bit binaries (for platforms that support it), e.g. --with-target-bits=32 @<:@guessed@:>@])])
+ [build 32-bit or 64-bit binaries (for platforms that support it), e.g. --with-target-bits=32 @<:@guessed@:>@])])
# We have three types of compiles:
# native == normal compilation, target system == build system
@@ -665,7 +665,7 @@ AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_BUILD_AND_TARGET],
AC_DEFUN([PLATFORM_CHECK_DEPRECATION],
[
AC_ARG_ENABLE(deprecated-ports, [AS_HELP_STRING([--enable-deprecated-ports@<:@=yes/no@:>@],
- [Suppress the error when configuring for a deprecated port @<:@no@:>@])])
+ [Suppress the error when configuring for a deprecated port @<:@no@:>@])])
if test "x$OPENJDK_TARGET_OS" = xwindows && test "x$OPENJDK_TARGET_CPU" = xx86; then
if test "x$enable_deprecated_ports" = "xyes"; then
AC_MSG_WARN([The Windows 32-bit x86 port is deprecated and may be removed in a future release.])
@@ -678,7 +678,7 @@ AC_DEFUN([PLATFORM_CHECK_DEPRECATION],
AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_BUILD_OS_VERSION],
[
- ###############################################################################
+ ##############################################################################
# Note that this is the build platform OS version!
@@ -693,7 +693,7 @@ AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_BUILD_OS_VERSION],
AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_TARGET_BITS],
[
- ###############################################################################
+ ##############################################################################
#
# Now we check if libjvm.so will use 32 or 64 bit pointers for the C/C++ code.
# (The JVM can use 32 or 64 bit Java pointers but that decision
@@ -739,7 +739,7 @@ AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_TARGET_BITS],
AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_TARGET_ENDIANNESS],
[
- ###############################################################################
+ ##############################################################################
#
# Is the target little or big endian?
#
diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template
index 79a541dc78c..a5f4143c888 100644
--- a/make/autoconf/spec.gmk.template
+++ b/make/autoconf/spec.gmk.template
@@ -272,7 +272,7 @@ VERSION_CFLAGS = \
-DVERSION_CLASSFILE_MINOR=$(VERSION_CLASSFILE_MINOR) \
#
-ifneq ($(COMPANY_NAME),)
+ifneq ($(COMPANY_NAME), )
# COMPANY_NAME is set to "N/A" in make/conf/branding.conf by default,
# but can be customized with the '--with-vendor-name' configure option.
# Only export "VENDOR" to the build if COMPANY_NAME contains a real value.
@@ -288,13 +288,13 @@ endif
# Only export VENDOR_URL, VENDOR_URL_BUG and VENDOR_VM_URL_BUG to the build if
# they are not empty. Otherwise, default values which are defined in the sources
# will be used.
-ifneq ($(VENDOR_URL),)
+ifneq ($(VENDOR_URL), )
VERSION_CFLAGS += -DVENDOR_URL='"$(VENDOR_URL)"'
endif
-ifneq ($(VENDOR_URL_BUG),)
+ifneq ($(VENDOR_URL_BUG), )
VERSION_CFLAGS += -DVENDOR_URL_BUG='"$(VENDOR_URL_BUG)"'
endif
-ifneq ($(VENDOR_URL_VM_BUG),)
+ifneq ($(VENDOR_URL_VM_BUG), )
VERSION_CFLAGS += -DVENDOR_URL_VM_BUG='"$(VENDOR_URL_VM_BUG)"'
endif
@@ -429,7 +429,6 @@ ENABLE_LIBFFI_BUNDLING := @ENABLE_LIBFFI_BUNDLING@
LIBFFI_LIB_FILE := @LIBFFI_LIB_FILE@
FILE_MACRO_CFLAGS := @FILE_MACRO_CFLAGS@
REPRODUCIBLE_CFLAGS := @REPRODUCIBLE_CFLAGS@
-BRANCH_PROTECTION_CFLAGS := @BRANCH_PROTECTION_CFLAGS@
STATIC_LIBS_CFLAGS := @STATIC_LIBS_CFLAGS@
@@ -719,6 +718,7 @@ CCACHE := @CCACHE@
# CD is going away, but remains to cater for legacy makefiles.
CD := cd
CHMOD := @CHMOD@
+CMAKE := @CMAKE@
CODESIGN := @CODESIGN@
CP := @CP@
CUT := @CUT@
@@ -743,6 +743,7 @@ MKDIR := @MKDIR@
MV := @MV@
NICE := @NICE@
PANDOC := @PANDOC@
+TIDY := @TIDY@
PATCH := @PATCH@
PRINTF := @PRINTF@
READLINK := @READLINK@
@@ -804,11 +805,7 @@ UCRT_DLL_DIR := @UCRT_DLL_DIR@
ENABLE_PANDOC := @ENABLE_PANDOC@
PANDOC_MARKDOWN_FLAG := @PANDOC_MARKDOWN_FLAG@
-####################################################
-#
# Libraries
-#
-
USE_EXTERNAL_LCMS := @USE_EXTERNAL_LCMS@
LCMS_CFLAGS := @LCMS_CFLAGS@
LCMS_LIBS := @LCMS_LIBS@
@@ -821,11 +818,7 @@ USE_EXTERNAL_LIBPNG := @USE_EXTERNAL_LIBPNG@
PNG_LIBS := @PNG_LIBS@
PNG_CFLAGS := @PNG_CFLAGS@
-####################################################
-#
# Misc
-#
-
INCLUDE_SA := @INCLUDE_SA@
INCLUDE_JVMCI := @INCLUDE_JVMCI@
INCLUDE_COMPILER2 := @INCLUDE_COMPILER2@
diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4
index 57064df1ed7..d84ae447e54 100644
--- a/make/autoconf/toolchain.m4
+++ b/make/autoconf/toolchain.m4
@@ -23,14 +23,14 @@
# questions.
#
-########################################################################
+################################################################################
# This file is responsible for detecting, verifying and setting up the
# toolchain, i.e. the compiler, linker and related utilities. It will setup
# proper paths to the binaries, but it will not setup any flags.
#
# The binaries used is determined by the toolchain type, which is the family of
# compilers and related tools that are used.
-########################################################################
+################################################################################
m4_include([toolchain_microsoft.m4])
@@ -307,7 +307,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION],
[
# Restore old path, except for the microsoft toolchain, which requires the
# toolchain path to remain in place. Otherwise the compiler will not work in
- # some siutations in later configure checks.
+ # some situations in later configure checks.
if test "x$TOOLCHAIN_TYPE" != "xmicrosoft"; then
PATH="$OLD_PATH"
fi
@@ -316,10 +316,6 @@ AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION],
# This is necessary since AC_PROG_CC defaults CFLAGS to "-g -O2"
CFLAGS="$ORG_CFLAGS"
CXXFLAGS="$ORG_CXXFLAGS"
-
- # filter out some unwanted additions autoconf may add to CXX; we saw this on macOS with autoconf 2.72
- UTIL_GET_NON_MATCHING_VALUES(cxx_filtered, $CXX, -std=c++11 -std=gnu++11)
- CXX="$cxx_filtered"
])
# Check if a compiler is of the toolchain type we expect, and save the version
@@ -358,6 +354,11 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_COMPILER_VERSION],
# Copyright (C) 2013 Free Software Foundation, Inc.
# This is free software; see the source for copying conditions. There is NO
# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ # or look like
+ # gcc (GCC) 10.2.1 20200825 (Alibaba 10.2.1-3.8 2.32)
+ # Copyright (C) 2020 Free Software Foundation, Inc.
+ # This is free software; see the source for copying conditions. There is NO
+ # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
COMPILER_VERSION_OUTPUT=`$COMPILER --version 2>&1`
# Check that this is likely to be GCC.
$ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "Free Software Foundation" > /dev/null
@@ -371,7 +372,8 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_COMPILER_VERSION],
COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT | \
$SED -e 's/ *Copyright .*//'`
COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \
- $SED -e 's/^.* \(@<:@1-9@:>@<:@0-9@:>@*\.@<:@0-9.@:>@*\)@<:@^0-9.@:>@.*$/\1/'`
+ $AWK -F ')' '{print [$]2}' | \
+ $AWK '{print [$]1}'`
elif test "x$TOOLCHAIN_TYPE" = xclang; then
# clang --version output typically looks like
# Apple clang version 15.0.0 (clang-1500.3.9.4)
@@ -678,6 +680,9 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_EXTRA],
test_metal=`$METAL --version 2>&1`
if test $? -ne 0; then
AC_MSG_RESULT([no])
+ AC_MSG_NOTICE([A full XCode is required to build the JDK (not only command line tools)])
+ AC_MSG_NOTICE([If you have XCode installed, you might need to reset the Xcode active developer directory])
+ AC_MSG_NOTICE([using 'sudo xcode-select -r'])
AC_MSG_ERROR([XCode tool 'metal' neither found in path nor with xcrun])
else
AC_MSG_RESULT([yes, will be using '$METAL'])
diff --git a/make/autoconf/toolchain_microsoft.m4 b/make/autoconf/toolchain_microsoft.m4
index 51bba487192..387e3717718 100644
--- a/make/autoconf/toolchain_microsoft.m4
+++ b/make/autoconf/toolchain_microsoft.m4
@@ -161,7 +161,7 @@ AC_DEFUN([TOOLCHAIN_FIND_VISUAL_STUDIO_BAT_FILE],
# version, pass -vcvars_ver= argument to vcvarsall.bat.
AC_ARG_WITH(msvc-toolset-version, [AS_HELP_STRING([--with-msvc-toolset-version],
[specific MSVC toolset version to use, passed as -vcvars_ver argument to
- pass to vcvarsall.bat (Windows only)])])
+ pass to vcvarsall.bat (Windows only)])])
TARGET_CPU="$1"
VS_VERSION="$2"
diff --git a/make/autoconf/util.m4 b/make/autoconf/util.m4
index 3fae951224e..5a6142d5092 100644
--- a/make/autoconf/util.m4
+++ b/make/autoconf/util.m4
@@ -26,6 +26,70 @@
m4_include([util_paths.m4])
###############################################################################
+# Overwrite the existing version of AC_PROG_CC with our own custom variant.
+# Unlike the regular AC_PROG_CC, the compiler list must always be passed.
+AC_DEFUN([AC_PROG_CC],
+[
+ AC_LANG_PUSH(C)
+ AC_ARG_VAR([CC], [C compiler command])
+ AC_ARG_VAR([CFLAGS], [C compiler flags])
+
+ _AC_ARG_VAR_LDFLAGS()
+ _AC_ARG_VAR_LIBS()
+ _AC_ARG_VAR_CPPFLAGS()
+
+ AC_CHECK_TOOLS(CC, [$1])
+
+ test -z "$CC" && AC_MSG_FAILURE([no acceptable C compiler found in \$PATH])
+
+ # Provide some information about the compiler.
+ _AS_ECHO_LOG([checking for _AC_LANG compiler version])
+ set X $ac_compile
+ ac_compiler=$[2]
+ for ac_option in --version -v -V -qversion -version; do
+ _AC_DO_LIMIT([$ac_compiler $ac_option >&AS_MESSAGE_LOG_FD])
+ done
+
+ m4_expand_once([_AC_COMPILER_EXEEXT])
+ m4_expand_once([_AC_COMPILER_OBJEXT])
+
+ _AC_PROG_CC_G
+
+ AC_LANG_POP(C)
+])
+
+###############################################################################
+# Overwrite the existing version of AC_PROG_CXX with our own custom variant.
+# Unlike the regular AC_PROG_CXX, the compiler list must always be passed.
+AC_DEFUN([AC_PROG_CXX],
+[
+ AC_LANG_PUSH(C++)
+ AC_ARG_VAR([CXX], [C++ compiler command])
+ AC_ARG_VAR([CXXFLAGS], [C++ compiler flags])
+
+ _AC_ARG_VAR_LDFLAGS()
+ _AC_ARG_VAR_LIBS()
+ _AC_ARG_VAR_CPPFLAGS()
+
+ AC_CHECK_TOOLS(CXX, [$1])
+
+ # Provide some information about the compiler.
+ _AS_ECHO_LOG([checking for _AC_LANG compiler version])
+ set X $ac_compile
+ ac_compiler=$[2]
+ for ac_option in --version -v -V -qversion; do
+ _AC_DO_LIMIT([$ac_compiler $ac_option >&AS_MESSAGE_LOG_FD])
+ done
+
+ m4_expand_once([_AC_COMPILER_EXEEXT])
+ m4_expand_once([_AC_COMPILER_OBJEXT])
+
+ _AC_PROG_CXX_G
+
+ AC_LANG_POP(C++)
+])
+
+################################################################################
# Create a function/macro that takes a series of named arguments. The call is
# similar to AC_DEFUN, but the setup of the function looks like this:
# UTIL_DEFUN_NAMED([MYFUNC], [FOO *BAR], [$@], [
@@ -100,7 +164,7 @@ AC_DEFUN([UTIL_DEFUN_NAMED],
])
])
-###############################################################################
+################################################################################
# Assert that a programmatic condition holds. If not, exit with an error message.
# Check that a shell expression gives return code 0
#
@@ -121,7 +185,7 @@ AC_DEFUN([UTIL_ASSERT_SHELL_TEST],
])
-###############################################################################
+################################################################################
# Assert that a programmatic condition holds. If not, exit with an error message.
# Check that two strings are equal.
#
@@ -137,7 +201,7 @@ AC_DEFUN([UTIL_ASSERT_STRING_EQUALS],
$3)
])
-###############################################################################
+################################################################################
# Assert that a programmatic condition holds. If not, exit with an error message.
# Check that two strings not are equal.
#
@@ -153,7 +217,7 @@ AC_DEFUN([UTIL_ASSERT_STRING_NOT_EQUALS],
$3)
])
-###############################################################################
+################################################################################
# Assert that a programmatic condition holds. If not, exit with an error message.
# Check that the given expression evaluates to the string 'true'
#
@@ -165,7 +229,7 @@ AC_DEFUN([UTIL_ASSERT_TRUE],
UTIL_ASSERT_STRING_EQUALS($1, true, $3)
])
-###############################################################################
+################################################################################
# Assert that a programmatic condition holds. If not, exit with an error message.
# Check that the given expression does not evaluate to the string 'true'
#
@@ -177,7 +241,7 @@ AC_DEFUN([UTIL_ASSERT_NOT_TRUE],
UTIL_ASSERT_STRING_NOT_EQUALS($1, true, $3)
])
-###############################################################################
+################################################################################
# Check if a list of space-separated words are selected only from a list of
# space-separated legal words. Typical use is to see if a user-specified
# set of words is selected from a set of legal words.
@@ -204,7 +268,7 @@ AC_DEFUN([UTIL_GET_NON_MATCHING_VALUES],
fi
])
-###############################################################################
+################################################################################
# Check if a list of space-separated words contains any word(s) from a list of
# space-separated illegal words. Typical use is to see if a user-specified
# set of words contains any from a set of illegal words.
@@ -231,7 +295,7 @@ AC_DEFUN([UTIL_GET_MATCHING_VALUES],
fi
])
-###############################################################################
+################################################################################
# Converts an ISO-8601 date/time string to a unix epoch timestamp. If no
# suitable conversion method was found, an empty string is returned.
#
@@ -259,7 +323,7 @@ AC_DEFUN([UTIL_GET_EPOCH_TIMESTAMP],
$1=$timestamp
])
-###############################################################################
+################################################################################
# Sort a space-separated list, and remove duplicates.
#
# Sets the specified variable to the resulting list.
@@ -273,7 +337,7 @@ AC_DEFUN([UTIL_SORT_LIST],
$1=${result//$'\n'/ }
])
-###############################################################################
+################################################################################
# Test if $1 is a valid argument to $3 (often is $JAVA passed as $3)
# If so, then append $1 to $2 \
# Also set JVM_ARG_OK to true/false depending on outcome.
@@ -294,7 +358,7 @@ AC_DEFUN([UTIL_ADD_JVM_ARG_IF_OK],
fi
])
-###############################################################################
+################################################################################
# Register a --with argument but mark it as deprecated
# $1: The name of the with argument to deprecate, not including --with-
AC_DEFUN([UTIL_DEPRECATED_ARG_WITH],
@@ -304,7 +368,7 @@ AC_DEFUN([UTIL_DEPRECATED_ARG_WITH],
[AC_MSG_WARN([Option --with-$1 is deprecated and will be ignored.])])
])
-###############################################################################
+################################################################################
# Register a --enable argument but mark it as deprecated
# $1: The name of the with argument to deprecate, not including --enable-
AC_DEFUN([UTIL_DEPRECATED_ARG_ENABLE],
@@ -314,7 +378,7 @@ AC_DEFUN([UTIL_DEPRECATED_ARG_ENABLE],
[AC_MSG_WARN([Option --enable-$1 is deprecated and will be ignored.])])
])
-###############################################################################
+################################################################################
# Register an --enable-* argument as an alias for another argument.
# $1: The name of the enable argument for the new alias, not including --enable-
# $2: The full name of the argument of which to make this an alias, including
@@ -329,7 +393,7 @@ AC_DEFUN([UTIL_ALIASED_ARG_ENABLE],
])
])
-###############################################################################
+################################################################################
# Creates a command-line option using the --enable-* pattern. Will return a
# value of 'true' or 'false' in the RESULT variable, depending on whether the
# option was enabled or not by the user. The option can not be turned on if it
@@ -471,7 +535,7 @@ UTIL_DEFUN_NAMED([UTIL_ARG_ENABLE],
fi
])
-###############################################################################
+################################################################################
# Helper functions for ARG_WITH, to validate different types of argument
# Dispatcher to call the correct UTIL_CHECK_TYPE_* function depending on the ARG_TYPE
@@ -575,7 +639,7 @@ AC_DEFUN([UTIL_CHECK_TYPE_features],
ARG_RESULT=$($ECHO $feature_list)
])
-###############################################################################
+################################################################################
# Creates a command-line option using the --with-* pattern. Will return a
# string in the RESULT variable with the option provided by the user, or the
# empty string if the --with-* option was not given. The option can not be given
@@ -810,7 +874,7 @@ UTIL_DEFUN_NAMED([UTIL_ARG_WITH],
fi
])
-###############################################################################
+################################################################################
# Helper functions for CHECK_VALUE in ARG_WITH.
AC_DEFUN([UTIL_CHECK_STRING_NON_EMPTY],
[
diff --git a/make/autoconf/util_paths.m4 b/make/autoconf/util_paths.m4
index 8b2c776397b..d9277b7eb9c 100644
--- a/make/autoconf/util_paths.m4
+++ b/make/autoconf/util_paths.m4
@@ -23,7 +23,7 @@
# questions.
#
-###############################################################################
+################################################################################
# Appends a string to a path variable, only adding the : when needed.
AC_DEFUN([UTIL_APPEND_TO_PATH],
[
@@ -36,7 +36,7 @@ AC_DEFUN([UTIL_APPEND_TO_PATH],
fi
])
-###############################################################################
+################################################################################
# Prepends a string to a path variable, only adding the : when needed.
AC_DEFUN([UTIL_PREPEND_TO_PATH],
[
@@ -49,7 +49,7 @@ AC_DEFUN([UTIL_PREPEND_TO_PATH],
fi
])
-###############################################################################
+################################################################################
# This will make sure the given variable points to a full and proper
# path. This means:
# 1) There will be no spaces in the path. On unix platforms,
@@ -118,7 +118,7 @@ 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],
@@ -136,7 +136,7 @@ AC_DEFUN([UTIL_FIXUP_WIN_LONG_PATH],
])
-###############################################################################
+################################################################################
# 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.
# Returns "windows" or "unix" in $RESULT.
@@ -170,7 +170,7 @@ AC_DEFUN([UTIL_CHECK_WINENV_EXEC_TYPE],
fi
])
-###############################################################################
+################################################################################
# This will make sure the given variable points to a executable
# with a full and proper path. This means:
# 1) There will be no spaces in the path. On unix platforms,
@@ -289,7 +289,7 @@ AC_DEFUN([UTIL_FIXUP_EXECUTABLE],
fi
])
-###############################################################################
+################################################################################
# Setup a tool for the given variable. If correctly specified by the user,
# use that value, otherwise search for the tool using the supplied code snippet.
# $1: variable to set
@@ -369,7 +369,7 @@ AC_DEFUN([UTIL_SETUP_TOOL],
fi
])
-###############################################################################
+################################################################################
# Locate a tool using proper methods.
# $1: variable to set
# $2: executable name (or list of names) to look for
@@ -436,7 +436,7 @@ AC_DEFUN([UTIL_LOOKUP_PROGS],
])
])
-###############################################################################
+################################################################################
# Call UTIL_SETUP_TOOL with AC_CHECK_TOOLS to locate the tool. This will look
# first for cross-compilation tools.
# $1: variable to set
@@ -452,7 +452,7 @@ AC_DEFUN([UTIL_LOOKUP_TOOLCHAIN_PROGS],
fi
])
-###############################################################################
+################################################################################
# Test that variable $1 denoting a program is not empty. If empty, exit with an error.
# $1: variable to check
AC_DEFUN([UTIL_CHECK_NONEMPTY],
@@ -462,7 +462,7 @@ AC_DEFUN([UTIL_CHECK_NONEMPTY],
fi
])
-###############################################################################
+################################################################################
# Like UTIL_LOOKUP_PROGS but fails if no tool was found.
# $1: variable to set
# $2: executable name (or list of names) to look for
@@ -473,7 +473,7 @@ AC_DEFUN([UTIL_REQUIRE_PROGS],
UTIL_CHECK_NONEMPTY($1)
])
-###############################################################################
+################################################################################
# Like UTIL_LOOKUP_PROGS but fails if no tool was found.
# $1: variable to set
# $2: executable name (or list of names) to look for
@@ -485,7 +485,7 @@ AC_DEFUN([UTIL_REQUIRE_TOOLCHAIN_PROGS],
])
-###############################################################################
+################################################################################
# Like UTIL_SETUP_TOOL but fails if no tool was found.
# $1: variable to set
# $2: autoconf macro to call to look for the special tool
@@ -497,7 +497,7 @@ AC_DEFUN([UTIL_REQUIRE_SPECIAL],
# unix tools. No further processing needed.
])
-###############################################################################
+################################################################################
# Add FIXPATH prefix to variable. Normally this is done by UTIL_LOOKUP_PROGS
# or UTIL_FIXUP_EXECUTABLE, but in some circumstances this has to be done
# explicitly, such as when the command in question does not exist yet.
@@ -510,7 +510,7 @@ AC_DEFUN([UTIL_ADD_FIXPATH],
fi
])
-###############################################################################
+################################################################################
AC_DEFUN([UTIL_REMOVE_SYMBOLIC_LINKS],
[
if test "x$OPENJDK_BUILD_OS" != xwindows; then
diff --git a/make/common/CopyFiles.gmk b/make/common/CopyFiles.gmk
index ac2ef69b4b1..4ed6c5906c7 100644
--- a/make/common/CopyFiles.gmk
+++ b/make/common/CopyFiles.gmk
@@ -23,7 +23,7 @@
# questions.
#
-ifeq (,$(_MAKEBASE_GMK))
+ifeq ($(_MAKEBASE_GMK), )
$(error You must include MakeBase.gmk prior to including CopyFiles.gmk)
endif
diff --git a/make/common/Execute.gmk b/make/common/Execute.gmk
index 126e5066c49..abafe77a3c4 100644
--- a/make/common/Execute.gmk
+++ b/make/common/Execute.gmk
@@ -23,7 +23,7 @@
# questions.
#
-ifeq (,$(_MAKEBASE_GMK))
+ifeq ($(_MAKEBASE_GMK), )
$(error You must include MakeBase.gmk prior to including Execute.gmk)
endif
diff --git a/make/common/FileUtils.gmk b/make/common/FileUtils.gmk
index 114f3adefbe..d3cc4872ebb 100644
--- a/make/common/FileUtils.gmk
+++ b/make/common/FileUtils.gmk
@@ -23,7 +23,7 @@
# questions.
#
-ifeq (,$(_MAKEBASE_GMK))
+ifeq ($(_MAKEBASE_GMK), )
$(error You must include MakeBase.gmk prior to including FileUtils.gmk)
endif
@@ -136,6 +136,7 @@ ifeq ($(call isTargetOs, macosx), true)
$(CP) -fRP '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)'; \
fi
if [ -n "`$(XATTR) -ls '$(call DecodeSpace, $@)'`" ]; then \
+ $(CHMOD) -h u+w '$(call DecodeSpace, $@)'; \
$(XATTR) -cs '$(call DecodeSpace, $@)'; \
fi
endef
@@ -188,6 +189,11 @@ else
endef
endif
+define copy-and-chmod-executable
+ $(install-file)
+ $(CHMOD) a+rx $@
+endef
+
################################################################################
# Recursive wildcard function. Walks down directories recursively and matches
@@ -281,7 +287,7 @@ CacheFindFiles = \
#
# $1 - Directories to start search in
FillFindCache = \
- $(eval CacheFindFiles_NEW_DIRS := $$(filter-out $$(addsuffix /%,\
+ $(eval CacheFindFiles_NEW_DIRS := $$(filter-out $$(addsuffix /%, \
$$(CacheFindFiles_CACHED_DIRS)) $$(CacheFindFiles_CACHED_DIRS), $1)) \
$(if $(CacheFindFiles_NEW_DIRS), \
$(eval CacheFindFiles_CACHED_DIRS += $$(patsubst %/,%,$$(CacheFindFiles_NEW_DIRS))) \
diff --git a/make/common/FindTests.gmk b/make/common/FindTests.gmk
index b12630349c0..db9cfe774de 100644
--- a/make/common/FindTests.gmk
+++ b/make/common/FindTests.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -43,7 +43,7 @@ $(eval $(call IncludeCustomExtension, common/FindTests.gmk))
TEST_BASEDIRS += $(TOPDIR)/test $(TOPDIR)
# JTREG_TESTROOTS might have been set by a custom extension
-JTREG_TESTROOTS += $(addprefix $(TOPDIR)/test/, hotspot/jtreg jdk langtools jaxp lib-test)
+JTREG_TESTROOTS += $(addprefix $(TOPDIR)/test/, hotspot/jtreg jdk langtools jaxp lib-test docs)
# Extract the names of the Jtreg group files from the TEST.ROOT files. The
# TEST.ROOT files being properties files can be interpreted as makefiles so
@@ -56,7 +56,7 @@ $(foreach root, $(JTREG_TESTROOTS), \
$(eval include $(root)/TEST.ROOT) \
$(eval $(root)_JTREG_GROUP_FILES := $$(addprefix $(root)/, $$(groups))) \
$(eval JTREG_GROUP_FILES += $$($(root)_JTREG_GROUP_FILES)) \
- ) \
+ ) \
)
# Cache the expensive to calculate test names in a generated makefile.
diff --git a/make/common/JarArchive.gmk b/make/common/JarArchive.gmk
index 25b42186666..68e9eaca32c 100644
--- a/make/common/JarArchive.gmk
+++ b/make/common/JarArchive.gmk
@@ -26,13 +26,13 @@
ifndef _JAR_ARCHIVE_GMK
_JAR_ARCHIVE_GMK := 1
-ifeq (,$(_MAKEBASE_GMK))
+ifeq ($(_MAKEBASE_GMK), )
$(error You must include MakeBase.gmk prior to including JarArchive.gmk)
endif
include MakeIO.gmk
-FALSE_FIND_PATTERN:=-name FILE_NAME_THAT_DOESNT_EXIST
+FALSE_FIND_PATTERN := -name FILE_NAME_THAT_DOESNT_EXIST
# Setup make rules for creating a jar archive.
#
@@ -40,81 +40,81 @@ FALSE_FIND_PATTERN:=-name FILE_NAME_THAT_DOESNT_EXIST
# and the targets generated are listed in a variable by that name.
#
# Remaining parameters are named arguments. These include:
-# DEPENDENCIES:=List of dependencies for the jar target. If left empty,
+# DEPENDENCIES List of dependencies for the jar target. If left empty,
# dependencies are calculated automatically from the source files found.
# For this to work, the source files must exist when the makefile is
# parsed.
-# SRCS:=List of directories in where to find files to add to archive
-# BIN:=Directory where to store build control files
-# SUFFIXES:=File suffixes to include in jar
-# INCLUDES:=List of directories/packages in SRCS that should be included
-# EXCLUDES:=List of directories/packages in SRCS that should be excluded
-# EXCLUDE_FILES:=List of files in SRCS that should be excluded
-# EXTRA_FILES:=List of files in SRCS that should be included regardless of suffix match.
-# JAR:=Jar file to create
-# MANIFEST:=Optional manifest file template.
-# JARMAIN:=Optional main class to add to manifest
-# JARINDEX:=true means generate the index in the jar file.
-# SKIP_METAINF:=Set to prevent contents of an META-INF directory to be automatically
+# SRCS List of directories in where to find files to add to archive
+# BIN Directory where to store build control files
+# SUFFIXES File suffixes to include in jar
+# INCLUDES List of directories/packages in SRCS that should be included
+# EXCLUDES List of directories/packages in SRCS that should be excluded
+# EXCLUDE_FILES List of files in SRCS that should be excluded
+# EXTRA_FILES List of files in SRCS that should be included regardless of suffix match.
+# JAR Jar file to create
+# MANIFEST Optional manifest file template.
+# JARMAIN Optional main class to add to manifest
+# JARINDEX true means generate the index in the jar file.
+# SKIP_METAINF Set to prevent contents of an META-INF directory to be automatically
# added to the archive.
-# EXTRA_MANIFEST_ATTR:=Extra attribute to add to manifest.
+# EXTRA_MANIFEST_ATTR Extra attribute to add to manifest.
# CHECK_COMPRESS_JAR Check the COMPRESS_JAR variable
-# JAR_CMD:=Optionally override the jar command to use when creating the archive.
+# JAR_CMD Optionally override the jar command to use when creating the archive.
SetupJarArchive = $(NamedParamsMacroTemplate)
define SetupJarArchiveBody
- $1_JARMAIN:=$(strip $$($1_JARMAIN))
- $1_JARNAME:=$$(notdir $$($1_JAR))
+ $1_JARMAIN := $(strip $$($1_JARMAIN))
+ $1_JARNAME := $$(notdir $$($1_JAR))
$1_JAR_OUTPUT_DIR := $$(patsubst %/, %, $$(dir $$($1_JAR)))
$$(call SetIfEmpty, $1_BIN, $$($1_JAR_OUTPUT_DIR))
- $1_MANIFEST_FILE:=$$($1_BIN)/_the.$$($1_JARNAME)_manifest
- $1_DELETESS_FILE:=$$($1_BIN)/_the.$$($1_JARNAME)_deletess
- $1_DELETES_FILE:=$$($1_BIN)/_the.$$($1_JARNAME)_deletes
+ $1_MANIFEST_FILE := $$($1_BIN)/_the.$$($1_JARNAME)_manifest
+ $1_DELETESS_FILE := $$($1_BIN)/_the.$$($1_JARNAME)_deletess
+ $1_DELETES_FILE := $$($1_BIN)/_the.$$($1_JARNAME)_deletes
$$(call SetIfEmpty, $1_JAR_CMD, $$(JAR))
- ifeq (,$$($1_SUFFIXES))
+ ifeq ($$($1_SUFFIXES), )
# No suffix was set, default to classes.
- $1_SUFFIXES:=.class
+ $1_SUFFIXES := .class
endif
# Convert suffixes to a find expression
- $1_FIND_PATTERNS:=$(FALSE_FIND_PATTERN) $$(patsubst %,$(SPACE)-o$(SPACE)-name$(SPACE)$(DQUOTE)*%$(DQUOTE),$$($1_SUFFIXES))
+ $1_FIND_PATTERNS := $(FALSE_FIND_PATTERN) $$(patsubst %,$(SPACE)-o$(SPACE)-name$(SPACE)$(DQUOTE)*%$(DQUOTE),$$($1_SUFFIXES))
# On windows, a lot of includes/excludes risk making the command line too long, so
# writing the grep patterns to files.
# Grep returns 1 if nothing is matched. Do not fail the build for this.
- ifneq (,$$($1_INCLUDES))
- $1_GREP_INCLUDE_PATTERNS:=$$(call EscapeDollar, \
+ ifneq ($$($1_INCLUDES), )
+ $1_GREP_INCLUDE_PATTERNS := $$(call EscapeDollar, \
$$(foreach src,$$($1_SRCS), $$(addprefix $$(src)/,$$($1_INCLUDES))))
# If there are a lot of include patterns, output to file to shorten command lines
- ifeq ($$(word 20,$$($1_GREP_INCLUDE_PATTERNS)),)
- $1_GREP_INCLUDES:=| ( $(GREP) $$(patsubst %,$(SPACE)-e$(SPACE)$(DQUOTE)%$(DQUOTE),$$($1_GREP_INCLUDE_PATTERNS)) \
+ ifeq ($$(word 20, $$($1_GREP_INCLUDE_PATTERNS)), )
+ $1_GREP_INCLUDES := | ( $(GREP) $$(patsubst %,$(SPACE)-e$(SPACE)$(DQUOTE)%$(DQUOTE),$$($1_GREP_INCLUDE_PATTERNS)) \
|| test "$$$$?" = "1" )
else
$1_GREP_INCLUDE_OUTPUT = \
- $$(eval $$(call ListPathsSafely,$1_GREP_INCLUDE_PATTERNS, \
+ $$(eval $$(call ListPathsSafely, $1_GREP_INCLUDE_PATTERNS, \
$$($1_BIN)/_the.$$($1_JARNAME)_include))
- $1_GREP_INCLUDES:=| ( $(GREP) -f $$($1_BIN)/_the.$$($1_JARNAME)_include \
+ $1_GREP_INCLUDES := | ( $(GREP) -f $$($1_BIN)/_the.$$($1_JARNAME)_include \
|| test "$$$$?" = "1" )
endif
endif
- ifneq (,$$($1_EXCLUDES)$$($1_EXCLUDE_FILES))
- $1_GREP_EXCLUDE_PATTERNS:=$$(call EscapeDollar, \
- $$(foreach src,$$($1_SRCS),$$(addprefix $$(src)/, \
+ ifneq ($$($1_EXCLUDES)$$($1_EXCLUDE_FILES), )
+ $1_GREP_EXCLUDE_PATTERNS := $$(call EscapeDollar, \
+ $$(foreach src, $$($1_SRCS), $$(addprefix $$(src)/, \
$$($1_EXCLUDES) $$($1_EXCLUDE_FILES))))
# If there are a lot of include patterns, output to file to shorten command lines
- ifeq ($$(word 20,$$($1_GREP_EXCLUDE_PATTERNS)),)
- $1_GREP_EXCLUDES:=| ( $(GREP) -v $$(patsubst %,$(SPACE)-e$(SPACE)$(DQUOTE)%$(DQUOTE),$$($1_GREP_EXCLUDE_PATTERNS)) \
+ ifeq ($$(word 20, $$($1_GREP_EXCLUDE_PATTERNS)), )
+ $1_GREP_EXCLUDES := | ( $(GREP) -v $$(patsubst %,$(SPACE)-e$(SPACE)$(DQUOTE)%$(DQUOTE),$$($1_GREP_EXCLUDE_PATTERNS)) \
|| test "$$$$?" = "1" )
else
$1_GREP_EXCLUDE_OUTPUT = \
- $$(eval $$(call ListPathsSafely,$1_GREP_EXCLUDE_PATTERNS, \
+ $$(eval $$(call ListPathsSafely, $1_GREP_EXCLUDE_PATTERNS, \
$$($1_BIN)/_the.$$($1_JARNAME)_exclude))
- $1_GREP_EXCLUDES:=| ( $(GREP) -v -f $$($1_BIN)/_the.$$($1_JARNAME)_exclude \
+ $1_GREP_EXCLUDES := | ( $(GREP) -v -f $$($1_BIN)/_the.$$($1_JARNAME)_exclude \
|| test "$$$$?" = "1" )
endif
endif
# Check if this jar needs to have its index generated.
- ifneq (,$$($1_JARINDEX))
+ ifneq ($$($1_JARINDEX), )
$1_JARINDEX = (cd $$(dir $$@) && $$($1_JAR_CMD) -i $$(notdir $$@))
else
$1_JARINDEX = true
@@ -127,19 +127,19 @@ define SetupJarArchiveBody
# Add all source roots to the find cache since we are likely going to run find
# on these more than once. The cache will only be updated if necessary.
$$(call FillFindCache, $$($1_FIND_LIST))
- $1_DEPENDENCIES:=$$(filter $$(addprefix %,$$($1_SUFFIXES)), \
- $$(call FindFiles,$$($1_SRCS)))
- ifneq (,$$($1_GREP_INCLUDE_PATTERNS))
- $1_DEPENDENCIES:=$$(filter $$(addsuffix %,$$($1_GREP_INCLUDE_PATTERNS)),$$($1_DEPENDENCIES))
+ $1_DEPENDENCIES := $$(filter $$(addprefix %, $$($1_SUFFIXES)), \
+ $$(call FindFiles, $$($1_SRCS)))
+ ifneq ($$($1_GREP_INCLUDE_PATTERNS), )
+ $1_DEPENDENCIES := $$(filter $$(addsuffix %, $$($1_GREP_INCLUDE_PATTERNS)), $$($1_DEPENDENCIES))
endif
- ifneq (,$$($1_GREP_EXCLUDE_PATTERNS))
- $1_DEPENDENCIES:=$$(filter-out $$(addsuffix %,$$($1_GREP_EXCLUDE_PATTERNS)),$$($1_DEPENDENCIES))
+ ifneq ($$($1_GREP_EXCLUDE_PATTERNS), )
+ $1_DEPENDENCIES := $$(filter-out $$(addsuffix %, $$($1_GREP_EXCLUDE_PATTERNS)), $$($1_DEPENDENCIES))
endif
# Look for EXTRA_FILES in all SRCS dirs and as absolute paths.
- $1_DEPENDENCIES+=$$(wildcard $$(foreach src, $$($1_SRCS), \
+ $1_DEPENDENCIES += $$(wildcard $$(foreach src, $$($1_SRCS), \
$$(addprefix $$(src)/, $$($1_EXTRA_FILES))) $$($1_EXTRA_FILES))
- ifeq (,$$($1_SKIP_METAINF))
- $1_DEPENDENCIES+=$$(call FindFiles,$$(wildcard $$(addsuffix /META-INF,$$($1_SRCS))))
+ ifeq ($$($1_SKIP_METAINF), )
+ $1_DEPENDENCIES += $$(call FindFiles, $$(wildcard $$(addsuffix /META-INF, $$($1_SRCS))))
endif
endif
# The dependency list should never be empty
@@ -156,23 +156,23 @@ define SetupJarArchiveBody
# into -C lines.
# The EXTRA_FILES_RESOLVED variable must be set in the macro so that it's evaluated
# in the recipe when the files are guaranteed to exist.
- $1_CAPTURE_EXTRA_FILES=\
- $$(eval $1_EXTRA_FILES_RESOLVED:=$$(call DoubleDollar, \
+ $1_CAPTURE_EXTRA_FILES = \
+ $$(eval $1_EXTRA_FILES_RESOLVED := $$(call DoubleDollar, \
$$(wildcard $$(foreach src, $$($1_SRCS), \
$$(addprefix $$(src)/, $$($1_EXTRA_FILES))) $$($1_EXTRA_FILES)))) \
$$(if $$($1_EXTRA_FILES_RESOLVED), \
- $$(eval $$(call ListPathsSafely,$1_EXTRA_FILES_RESOLVED, \
+ $$(eval $$(call ListPathsSafely, $1_EXTRA_FILES_RESOLVED, \
$$($1_BIN)/_the.$$($1_JARNAME)_contents.extra)) \
- $(SED) $$(foreach src,$$($1_SRCS), -e 's|$$(src)/|-C $$(src) |g') \
+ $(SED) $$(foreach src, $$($1_SRCS), -e 's|$$(src)/|-C $$(src) |g') \
$$($1_BIN)/_the.$$($1_JARNAME)_contents.extra \
>> $$($1_BIN)/_the.$$($1_JARNAME)_contents $$(NEWLINE))
# The capture contents macro finds all files (matching the patterns, typically
# .class and .prp) that are newer than the jar-file, ie the new content to be put into the jar.
# NOTICE: please leave the parentheses space separated otherwise the AIX build will break!
- $1_CAPTURE_CONTENTS=\
+ $1_CAPTURE_CONTENTS = \
$(RM) $$($1_BIN)/_the.$$($1_JARNAME)_contents $$(NEWLINE) \
- $$(foreach src,$$($1_SRCS), \
+ $$(foreach src, $$($1_SRCS), \
$(FIND) $$(src) -type f -a \( $$($1_FIND_PATTERNS) \) -a -newer $$@ $$($1_GREP_INCLUDES) \
$$($1_GREP_EXCLUDES) | $(SED) 's|$$(src)/|-C $$(src) |g' \
>> $$($1_BIN)/_the.$$($1_JARNAME)_contents $$(NEWLINE)) \
@@ -180,19 +180,19 @@ define SetupJarArchiveBody
# The capture metainf macro finds all files below the META-INF directory that are newer than the jar-file.
# Find returns non zero if the META-INF dir does not exist, ignore this.
- ifeq (,$$($1_SKIP_METAINF))
- $1_CAPTURE_METAINF =$$(foreach src,$$($1_SRCS), \
+ ifeq ($$($1_SKIP_METAINF), )
+ $1_CAPTURE_METAINF = $$(foreach src, $$($1_SRCS), \
( ( $(FIND) $$(src)/META-INF -type f -a -newer $$@ 2> /dev/null || true ) \
| $(SED) 's|$$(src)/|-C $$(src) |g' >> \
$$($1_BIN)/_the.$$($1_JARNAME)_contents ) $$(NEWLINE) )
endif
# The capture deletes macro finds all deleted files and concatenates them. The resulting file
# tells us what to remove from the jar-file.
- $1_CAPTURE_DELETES=$$(foreach src,$$($1_SRCS),($(FIND) $$(src) -name _the.package.deleted -newer $$@ \
+ $1_CAPTURE_DELETES = $$(foreach src, $$($1_SRCS), ($(FIND) $$(src) -name _the.package.deleted -newer $$@ \
-exec $(SED) 's|$$(src)||g' \{\} >> $$($1_DELETES_FILE) \;) $$(NEWLINE))
# The update contents macro updates the jar file with the previously capture contents.
# Use 'wc -w' to see if the contents file is empty.
- $1_UPDATE_CONTENTS=\
+ $1_UPDATE_CONTENTS = \
if [ "`$(WC) -l $$($1_BIN)/_the.$$($1_JARNAME)_contents | $(AWK) '{ print $$$$1 }'`" -gt "0" ]; then \
$(ECHO) " updating" `$(WC) -l $$($1_BIN)/_the.$$($1_JARNAME)_contents | $(AWK) '{ print $$$$1 }'` files && \
$(SORT) $$($1_BIN)/_the.$$($1_JARNAME)_contents > $$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted && \
@@ -200,27 +200,27 @@ define SetupJarArchiveBody
fi $$(NEWLINE)
# The s-variants of the above macros are used when the jar is created from scratch.
# NOTICE: please leave the parentheses space separated otherwise the AIX build will break!
- $1_SCAPTURE_CONTENTS=\
+ $1_SCAPTURE_CONTENTS = \
$(RM) $$($1_BIN)/_the.$$($1_JARNAME)_contents $$(NEWLINE) \
- $$(foreach src,$$($1_SRCS), \
+ $$(foreach src, $$($1_SRCS), \
$(FIND) $$(src) -type f -a \( $$($1_FIND_PATTERNS) \) $$($1_GREP_INCLUDES) \
$$($1_GREP_EXCLUDES) | $(SED) 's|$$(src)/|-C $$(src) |g' \
>> $$($1_BIN)/_the.$$($1_JARNAME)_contents $$(NEWLINE)) \
$$($1_CAPTURE_EXTRA_FILES)
# Find returns non zero if the META-INF dir does not exist, ignore this.
- ifeq (,$$($1_SKIP_METAINF))
- $1_SCAPTURE_METAINF=$$(foreach src,$$($1_SRCS), \
+ ifeq ($$($1_SKIP_METAINF), )
+ $1_SCAPTURE_METAINF = $$(foreach src, $$($1_SRCS), \
( ( $(FIND) $$(src)/META-INF -type f 2> /dev/null || true ) \
| $(SED) 's|$$(src)/|-C $$(src) |g' >> \
$$($1_BIN)/_the.$$($1_JARNAME)_contents) $$(NEWLINE) )
endif
- $1_SUPDATE_CONTENTS=\
+ $1_SUPDATE_CONTENTS = \
$(SORT) $$($1_BIN)/_the.$$($1_JARNAME)_contents > $$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted && \
$$($1_JAR_CMD) --update $$($1_JAR_OPTIONS) --file $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted $$(NEWLINE)
# Use a slightly shorter name for logging, but with enough path to identify this jar.
- $1_NAME:=$$(subst $$(OUTPUTDIR)/,,$$($1_JAR))
+ $1_NAME := $$(subst $$(OUTPUTDIR)/,,$$($1_JAR))
# If reproducible build and the boot jdk jar supports --date option
# then specify the --date using SOURCE_DATE in ISO-8601
@@ -228,7 +228,7 @@ define SetupJarArchiveBody
ifeq ($$(BOOT_JDK_JAR_SUPPORTS_DATE), true)
$1_JAR_OPTIONS += --date $(SOURCE_DATE_ISO_8601)
endif
- ifneq (,$$($1_CHECK_COMPRESS_JAR))
+ ifneq ($$($1_CHECK_COMPRESS_JAR), )
ifneq ($(COMPRESS_JARS), true)
$1_JAR_OPTIONS += --no-compress
endif
diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk
index 1503c86aff1..59ea23d359b 100644
--- a/make/common/JavaCompilation.gmk
+++ b/make/common/JavaCompilation.gmk
@@ -26,7 +26,7 @@
ifndef _JAVA_COMPILATION_GMK
_JAVA_COMPILATION_GMK := 1
-ifeq (,$(_MAKEBASE_GMK))
+ifeq ($(_MAKEBASE_GMK), )
$(error You must include MakeBase.gmk prior to including JavaCompilation.gmk)
endif
@@ -57,9 +57,9 @@ TARGET_RELEASE_NEWJDK_UPGRADED := $(TARGET_RELEASE_NEWJDK) \
define add_file_to_copy
# param 1 = BUILD_MYPACKAGE
# parma 2 = The source file to copy.
- $2_TARGET:=$2
+ $2_TARGET := $2
# Remove the source prefix.
- $$(foreach i,$$($1_SRC),$$(eval $$(call remove_string,$$i,$2_TARGET)))
+ $$(foreach i, $$($1_SRC), $$(eval $$(call remove_string,$$i,$2_TARGET)))
# To allow for automatic overrides, do not create a rule for a target file that
# already has one
ifneq ($$($1_COPY_$$($2_TARGET)), 1)
@@ -98,9 +98,9 @@ endef
define add_file_to_clean
# param 1 = BUILD_MYPACKAGE
# parma 2 = The source file to copy and clean.
- $2_TARGET:=$2
+ $2_TARGET := $2
# Remove the source prefix.
- $$(foreach i,$$($1_SRC),$$(eval $$(call remove_string,$$i,$2_TARGET)))
+ $$(foreach i, $$($1_SRC), $$(eval $$(call remove_string,$$i,$2_TARGET)))
# Now we can setup the dependency that will trigger the copying.
# To allow for automatic overrides, do not create a rule for a target file that
# already has one
@@ -138,44 +138,44 @@ endef
# The target for public API digest is returned in $1_API_TARGET.
#
# Remaining parameters are named arguments. These include:
-# SMALL_JAVA:=set to false to run javac as a "big" java app
-# COMPILER:=bootjdk or interim, the latter is default
-# TARGET_RELEASE:=javac flags to set the targeted jdk release (-source/-target or --release)
+# SMALL_JAVA set to false to run javac as a "big" java app
+# COMPILER bootjdk or interim, the latter is default
+# TARGET_RELEASE javac flags to set the targeted jdk release (-source/-target or --release)
# Defaults to $(TARGET_RELEASE_NEWJDK).
-# JAVAC_FLAGS:=javac flags to append to the default ones.
-# JAVA_FLAGS:=flags to be appended to the java launching the compiler
-# DISABLED_WARNINGS:=list of Xlint warnings that should be disabled
-# SRC:=one or more directories to search for sources. The order of the source roots
+# JAVAC_FLAGS javac flags to append to the default ones.
+# JAVA_FLAGS flags to be appended to the java launching the compiler
+# DISABLED_WARNINGS list of Xlint warnings that should be disabled
+# SRC one or more directories to search for sources. The order of the source roots
# is significant. The first found file of a certain name has priority.
-# BIN:=store classes here
-# MODULE:=Name of module being compiled. If set, classes are put in BIN/MODULE.
-# CLASSPATH:=a list of additional entries to set as classpath to javac
-# INCLUDES:=myapp.foo means will only compile java files in myapp.foo or any of its sub-packages.
-# EXCLUDES:=myapp.foo means will do not compile java files in myapp.foo or any of its sub-packages.
-# COPY:=.prp means copy all prp files to the corresponding package in BIN.
-# COPY_FILES:=myapp/foo/setting.txt means copy this file over to the package myapp/foo
-# CLEAN:=.properties means copy and clean all properties file to the corresponding package in BIN.
-# CLEAN_FILES:=myapp/foo/setting.txt means clean this file over to the package myapp/foo
-# SRCZIP:=Create a src.zip based on the found sources and copied files.
-# INCLUDE_FILES:="com/sun/SolarisFoobar.java" means only compile this file!
-# EXCLUDE_FILES:="com/sun/SolarisFoobar.java" means do not compile this particular file!
+# BIN store classes here
+# MODULE Name of module being compiled. If set, classes are put in BIN/MODULE.
+# CLASSPATH a list of additional entries to set as classpath to javac
+# INCLUDES myapp.foo means will only compile java files in myapp.foo or any of its sub-packages.
+# EXCLUDES myapp.foo means will do not compile java files in myapp.foo or any of its sub-packages.
+# COPY .prp means copy all prp files to the corresponding package in BIN.
+# COPY_FILES myapp/foo/setting.txt means copy this file over to the package myapp/foo
+# CLEAN .properties means copy and clean all properties file to the corresponding package in BIN.
+# CLEAN_FILES myapp/foo/setting.txt means clean this file over to the package myapp/foo
+# SRCZIP Create a src.zip based on the found sources and copied files.
+# INCLUDE_FILES "com/sun/SolarisFoobar.java" means only compile this file!
+# EXCLUDE_FILES "com/sun/SolarisFoobar.java" means do not compile this particular file!
# "SolarisFoobar.java" means do not compile SolarisFoobar, wherever it is found.
-# EXTRA_FILES:=List of extra source files to include in compilation. Can be used to
+# EXTRA_FILES List of extra source files to include in compilation. Can be used to
# specify files that need to be generated by other rules first.
-# HEADERS:=path to directory where all generated c-headers are written.
-# DEPENDS:=Extra dependency
-# KEEP_DUPS:=Do not remove duplicate file names from different source roots.
-# FAIL_NO_SRC:=Set to false to not fail the build if no source files are found,
+# HEADERS path to directory where all generated c-headers are written.
+# DEPENDS Extra dependency
+# KEEP_DUPS Do not remove duplicate file names from different source roots.
+# FAIL_NO_SRC Set to false to not fail the build if no source files are found,
# default is true.
-# CREATE_API_DIGEST:=Set to true to use a javac plugin to generate a public API
+# CREATE_API_DIGEST Set to true to use a javac plugin to generate a public API
# hash which can be used for down stream dependencies to only rebuild
# when the API changes.
-# KEEP_ALL_TRANSLATIONS:=Set to true to skip translation filtering
+# KEEP_ALL_TRANSLATIONS Set to true to skip translation filtering
SetupJavaCompilation = $(NamedParamsMacroTemplate)
define SetupJavaCompilationBody
# Verify arguments
- ifeq ($$($1_BIN),)
+ ifeq ($$($1_BIN), )
$$(error Must specify BIN (in $1))
endif
@@ -255,9 +255,9 @@ define SetupJavaCompilationBody
$1_JAVAC := $$(INTERIM_LANGTOOLS_ARGS) -m jdk.compiler.interim/com.sun.tools.javac.Main
ifeq ($$($1_SMALL_JAVA), true)
- $1_JAVAC_CMD := $$(JAVA_SMALL) $$($1_JAVA_FLAGS) $$($1_JAVAC)
+ $1_JAVAC_CMD := $$(JAVA_SMALL) $$($1_JAVA_FLAGS) $$($1_JAVAC)
else
- $1_JAVAC_CMD := $$(JAVA) $$($1_JAVA_FLAGS) $$($1_JAVAC)
+ $1_JAVAC_CMD := $$(JAVA) $$($1_JAVA_FLAGS) $$($1_JAVAC)
endif
endif
@@ -282,8 +282,26 @@ define SetupJavaCompilationBody
$1_FLAGS += -Xlint:$$(call CommaList, $$(addprefix -, $$($1_DISABLED_WARNINGS)))
endif
- ifneq ($$($1_CLASSPATH), )
- $1_FLAGS += -cp $$(call PathList, $$($1_CLASSPATH))
+ $1_AUGMENTED_CLASSPATH := $$($1_CLASSPATH)
+ $1_API_TARGET := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1_pubapi
+ $1_API_INTERNAL := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1_internalapi
+
+ ifeq ($$($1_CREATE_API_DIGEST), true)
+ $1_API_DIGEST_FLAGS := \
+ -Xplugin:"depend $$($1_API_TARGET)" \
+ "-XDinternalAPIPath=$$($1_API_INTERNAL)" \
+ "-XDLOG_LEVEL=$(LOG_LEVEL)" \
+ #
+
+ $1_EXTRA_DEPS := $$(BUILDTOOLS_OUTPUTDIR)/depend/_the.COMPILE_DEPEND_batch
+ # including the compilation output on the classpath, so that incremental
+ # compilations in unnamed module can refer to other classes from the same
+ # source root, which are not being recompiled in this compilation:
+ $1_AUGMENTED_CLASSPATH += $$(BUILDTOOLS_OUTPUTDIR)/depend $$($1_BIN)
+ endif
+
+ ifneq ($$($1_AUGMENTED_CLASSPATH), )
+ $1_FLAGS += -cp $$(call PathList, $$($1_AUGMENTED_CLASSPATH))
endif
# Make sure the dirs exist, or that one of the EXTRA_FILES, that may not
@@ -295,7 +313,7 @@ define SetupJavaCompilationBody
) \
) \
)
- $$(call MakeDir,$$($1_BIN))
+ $$(call MakeDir, $$($1_BIN))
# Order src files according to the order of the src dirs. Correct ordering is
# needed for correct overriding between different source roots.
$1_ALL_SRC_RAW := $$(call FindFiles, $$($1_SRC))
@@ -351,72 +369,69 @@ define SetupJavaCompilationBody
endif
else
# All files below META-INF are always copied.
- $1_ALL_COPIES := $$(filter $$(addsuffix /META-INF%,$$($1_SRC)),$$($1_ALL_SRCS))
+ $1_ALL_COPIES := $$(filter $$(addsuffix /META-INF%, $$($1_SRC)), $$($1_ALL_SRCS))
# Find all files to be copied from source to bin.
- ifneq (,$$($1_COPY)$$($1_COPY_FILES))
+ ifneq ($$($1_COPY)$$($1_COPY_FILES), )
# Search for all files to be copied.
- $1_ALL_COPIES += $$(filter $$(addprefix %,$$($1_COPY)),$$($1_ALL_SRCS))
+ $1_ALL_COPIES += $$(filter $$(addprefix %, $$($1_COPY)), $$($1_ALL_SRCS))
# Copy these explicitly
$1_ALL_COPIES += $$($1_COPY_FILES)
endif
# Copy must also respect filters.
- ifneq (,$$($1_INCLUDE_PATTERN))
- $1_ALL_COPIES := $$(filter $$($1_INCLUDE_PATTERN),$$($1_ALL_COPIES))
+ ifneq ($$($1_INCLUDE_PATTERN), )
+ $1_ALL_COPIES := $$(filter $$($1_INCLUDE_PATTERN), $$($1_ALL_COPIES))
endif
- ifneq (,$$($1_EXCLUDE_PATTERN))
- $1_ALL_COPIES := $$(filter-out $$($1_EXCLUDE_PATTERN),$$($1_ALL_COPIES))
+ ifneq ($$($1_EXCLUDE_PATTERN), )
+ $1_ALL_COPIES := $$(filter-out $$($1_EXCLUDE_PATTERN), $$($1_ALL_COPIES))
endif
# Filter out any excluded translations
ifneq ($$($1_KEEP_ALL_TRANSLATIONS), true)
$1_ALL_COPIES := $$(call FilterExcludedTranslations, $$($1_ALL_COPIES), .properties)
endif
- ifneq (,$$($1_ALL_COPIES))
+ ifneq ($$($1_ALL_COPIES), )
# Yep, there are files to be copied!
- $1_ALL_COPY_TARGETS:=
- $$(foreach i,$$($1_ALL_COPIES),$$(eval $$(call add_file_to_copy,$1,$$i)))
+ $1_ALL_COPY_TARGETS :=
+ $$(foreach i, $$($1_ALL_COPIES), $$(eval $$(call add_file_to_copy,$1,$$i)))
# Now we can depend on $$($1_ALL_COPY_TARGETS) to copy all files!
endif
# Find all property files to be copied and cleaned from source to bin.
- ifneq (,$$($1_CLEAN)$$($1_CLEAN_FILES))
+ ifneq ($$($1_CLEAN)$$($1_CLEAN_FILES), )
# Search for all files to be copied.
- $1_ALL_CLEANS := $$(filter $$(addprefix %,$$($1_CLEAN)),$$($1_ALL_SRCS))
+ $1_ALL_CLEANS := $$(filter $$(addprefix %, $$($1_CLEAN)), $$($1_ALL_SRCS))
# Clean these explicitly
$1_ALL_CLEANS += $$($1_CLEAN_FILES)
# Copy and clean must also respect filters.
- ifneq (,$$($1_INCLUDE_PATTERN))
- $1_ALL_CLEANS := $$(filter $$($1_INCLUDE_PATTERN),$$($1_ALL_CLEANS))
+ ifneq ($$($1_INCLUDE_PATTERN), )
+ $1_ALL_CLEANS := $$(filter $$($1_INCLUDE_PATTERN), $$($1_ALL_CLEANS))
endif
- ifneq (,$$($1_EXCLUDE_PATTERN))
- $1_ALL_CLEANS := $$(filter-out $$($1_EXCLUDE_PATTERN),$$($1_ALL_CLEANS))
+ ifneq ($$($1_EXCLUDE_PATTERN), )
+ $1_ALL_CLEANS := $$(filter-out $$($1_EXCLUDE_PATTERN), $$($1_ALL_CLEANS))
endif
# Filter out any excluded translations
ifneq ($$($1_KEEP_ALL_TRANSLATIONS), true)
$1_ALL_CLEANS := $$(call FilterExcludedTranslations, $$($1_ALL_CLEANS), .properties)
endif
- ifneq (,$$($1_ALL_CLEANS))
+ ifneq ($$($1_ALL_CLEANS), )
# Yep, there are files to be copied and cleaned!
- $1_ALL_COPY_CLEAN_TARGETS:=
- $$(foreach i,$$($1_ALL_CLEANS),$$(eval $$(call add_file_to_clean,$1,$$i)))
+ $1_ALL_COPY_CLEAN_TARGETS :=
+ $$(foreach i, $$($1_ALL_CLEANS), $$(eval $$(call add_file_to_clean,$1,$$i)))
# Now we can depend on $$($1_ALL_COPY_CLEAN_TARGETS) to copy all files!
endif
endif
# Create a sed expression to remove the source roots and to replace / with .
# and remove .java at the end.
- $1_REWRITE_INTO_CLASSES:=$$(foreach i,$$($1_SRC),-e 's|$$i/||g') -e 's|/|.|g' -e 's|.java$$$$||g'
+ $1_REWRITE_INTO_CLASSES := $$(foreach i, $$($1_SRC), -e 's|$$i/||g') -e 's|/|.|g' -e 's|.java$$$$||g'
$1_COMPILE_TARGET := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1_batch
$1_FILELIST := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1_batch.filelist
$1_MODFILELIST := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1_batch.modfiles
$1_MODFILELIST_FIXED := $$($1_MODFILELIST).fixed
- $1_API_TARGET := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1_pubapi
- $1_API_INTERNAL := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1_internalapi
-
# Put headers in a temp dir to filter out those that actually
# changed before copying them to the real header dir.
- ifneq (,$$($1_HEADERS))
+ ifneq ($$($1_HEADERS), )
$1_HEADERS_ARG := -h $$($1_HEADERS).$1.tmp
$$($1_HEADERS)/_the.$1_headers: $$($1_COMPILE_TARGET)
@@ -442,17 +457,6 @@ define SetupJavaCompilationBody
$1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, \
$$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1.vardeps)
- ifeq ($$($1_CREATE_API_DIGEST), true)
- $1_API_DIGEST_FLAGS := \
- -classpath $$(BUILDTOOLS_OUTPUTDIR)/depend \
- -Xplugin:"depend $$($1_API_TARGET)" \
- "-XDinternalAPIPath=$$($1_API_INTERNAL)" \
- "-XDLOG_LEVEL=$(LOG_LEVEL)" \
- #
-
- $1_EXTRA_DEPS := $$(BUILDTOOLS_OUTPUTDIR)/depend/_the.COMPILE_DEPEND_batch
- endif
-
# Create a file with all sources, to pass to javac in an @file.
# $$($1_VARDEPS_FILE) is used as dependency to track changes in set of
# list of files.
@@ -499,27 +503,27 @@ define SetupJavaCompilationBody
$$($1_HEADER_TARGETS)
# Check if a jar file was specified, then setup the rules for the jar.
- ifneq (,$$($1_JAR))
+ ifneq ($$($1_JAR), )
# If no suffixes was explicitly set for this jar file.
# Use class and the cleaned/copied properties file suffixes as the default
# for the types of files to be put into the jar.
- ifeq (,$$($1_SUFFIXES))
- $1_SUFFIXES:=.class $$($1_CLEAN) $$($1_COPY)
+ ifeq ($$($1_SUFFIXES), )
+ $1_SUFFIXES := .class $$($1_CLEAN) $$($1_COPY)
endif
$$(eval $$(call SetupJarArchive, ARCHIVE_$1, \
- DEPENDENCIES:=$$($1), \
- SRCS:=$$($1_BIN)$$($1_MODULE_SUBDIR), \
- SUFFIXES:=$$($1_SUFFIXES), \
- EXCLUDE:=$$($1_EXCLUDES), \
- INCLUDES:=$$($1_INCLUDES), \
- EXTRA_FILES:=$$($1_ALL_COPY_TARGETS) $$($1_ALL_COPY_CLEAN_TARGETS), \
- JAR:=$$($1_JAR), \
- JARMAIN:=$$($1_JARMAIN), \
- MANIFEST:=$$($1_MANIFEST), \
- EXTRA_MANIFEST_ATTR:=$$($1_EXTRA_MANIFEST_ATTR), \
- JARINDEX:=$$($1_JARINDEX), \
- HEADERS:=$$($1_HEADERS), \
+ DEPENDENCIES := $$($1), \
+ SRCS := $$($1_BIN)$$($1_MODULE_SUBDIR), \
+ SUFFIXES := $$($1_SUFFIXES), \
+ EXCLUDE := $$($1_EXCLUDES), \
+ INCLUDES := $$($1_INCLUDES), \
+ EXTRA_FILES := $$($1_ALL_COPY_TARGETS) $$($1_ALL_COPY_CLEAN_TARGETS), \
+ JAR := $$($1_JAR), \
+ JARMAIN := $$($1_JARMAIN), \
+ MANIFEST := $$($1_MANIFEST), \
+ EXTRA_MANIFEST_ATTR := $$($1_EXTRA_MANIFEST_ATTR), \
+ JARINDEX := $$($1_JARINDEX), \
+ HEADERS := $$($1_HEADERS), \
))
# Add jar to target list
@@ -527,13 +531,13 @@ define SetupJavaCompilationBody
endif
# Check if a srczip was specified, then setup the rules for the srczip.
- ifneq (,$$($1_SRCZIP))
+ ifneq ($$($1_SRCZIP), )
$$(eval $$(call SetupZipArchive, ZIP_ARCHIVE_$1, \
- SRC:=$$($1_SRC), \
- ZIP:=$$($1_SRCZIP), \
- INCLUDES:=$$($1_INCLUDES), \
- EXCLUDES:=$$($1_EXCLUDES), \
- EXCLUDE_FILES:=$$($1_EXCLUDE_FILES)))
+ SRC := $$($1_SRC), \
+ ZIP := $$($1_SRCZIP), \
+ INCLUDES := $$($1_INCLUDES), \
+ EXCLUDES := $$($1_EXCLUDES), \
+ EXCLUDE_FILES := $$($1_EXCLUDE_FILES)))
# Add zip to target list
$1 += $$($1_SRCZIP)
diff --git a/make/common/JdkNativeCompilation.gmk b/make/common/JdkNativeCompilation.gmk
index 846597ecee9..52b6dea6725 100644
--- a/make/common/JdkNativeCompilation.gmk
+++ b/make/common/JdkNativeCompilation.gmk
@@ -182,12 +182,12 @@ define AddJdkLibrary
$1_$2_NAME := $$(strip $$(lastword $$(subst :, , $3)))
$1_$2_MODULE := $$(strip $$(patsubst %$$($1_$2_NAME), %, $3))
- ifeq ($$(filter lib%, $$($1_$2_NAME)),)
+ ifeq ($$(filter lib%, $$($1_$2_NAME)), )
$$(error Library name $$($1_$2_NAME) missing lib prefix in $1)
endif
$1_$2_NAME := $$(strip $$(patsubst lib%, %, $$($1_$2_NAME)))
- ifeq ($$($1_$2_MODULE),)
+ ifeq ($$($1_$2_MODULE), )
$1_$2_MODULE := $$(MODULE)
else
$1_$2_MODULE := $$(strip $$(patsubst %:, %, $$($1_$2_MODULE)))
@@ -196,10 +196,10 @@ define AddJdkLibrary
# Determine if the library in question is static.
# Ideally, we should not hardcode these
ifeq ($(call isTargetOs, aix)+$$($1_$2_MODULE):$$($1_$2_NAME), true+java.base:jli)
- $1_$2_STATIC_LIBRARY := true
+ $1_$2_STATIC_LIBRARY := true
endif
ifeq ($$($1_$2_MODULE):$$($1_$2_NAME), gtest:gtest)
- $1_$2_STATIC_LIBRARY := true
+ $1_$2_STATIC_LIBRARY := true
endif
# Setup $1_$2_LIBPATH.
diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk
index 5af1967e54b..aec7396cd65 100644
--- a/make/common/MakeBase.gmk
+++ b/make/common/MakeBase.gmk
@@ -23,17 +23,17 @@
# questions.
#
-################################################################
+################################################################################
# MakeBase provides the core functionality needed and used by all makefiles. It
# should be included by all makefiles. MakeBase provides essential
# functionality for named parameter functions, variable dependency, tool
# execution, logging and fixpath functionality.
-################################################################
+################################################################################
ifndef _MAKEBASE_GMK
_MAKEBASE_GMK := 1
-ifeq ($(wildcard $(SPEC)),)
+ifeq ($(wildcard $(SPEC)), )
$(error MakeBase.gmk needs SPEC set to a proper spec.gmk)
endif
@@ -49,16 +49,16 @@ endif
# When calling macros, the spaces between arguments are
# often semantically important! Sometimes we need to subst
# spaces and commas, therefore we need the following macros.
-X:=
-SPACE:=$(X) $(X)
-COMMA:=,
-DOLLAR:=$$
-HASH:=\#
-LEFT_PAREN:=(
-RIGHT_PAREN:=)
-SQUOTE:='
+X :=
+SPACE := $(X) $(X)
+COMMA := ,
+DOLLAR := $$
+HASH := \#
+LEFT_PAREN := (
+RIGHT_PAREN := )
+SQUOTE := '
#'
-DQUOTE:="
+DQUOTE := "
#"
define NEWLINE
@@ -99,7 +99,7 @@ define SetupLogging
endif
endif
- ifneq ($$(findstring $$(LOG_LEVEL), debug trace),)
+ ifneq ($$(findstring $$(LOG_LEVEL), debug trace), )
SHELL := $$(SHELL) -x
endif
@@ -117,21 +117,21 @@ define SetupLogging
# The warn level can never be turned off
LogWarn = $$(info $(LOG_PREFIX)$$(strip $$1))
LOG_WARN :=
- ifneq ($$(findstring $$(LOG_LEVEL), info debug trace),)
+ ifneq ($$(findstring $$(LOG_LEVEL), info debug trace), )
LogInfo = $$(info $(LOG_PREFIX)$$(strip $$1))
LOG_INFO :=
else
LogInfo =
LOG_INFO := > /dev/null
endif
- ifneq ($$(findstring $$(LOG_LEVEL), debug trace),)
+ ifneq ($$(findstring $$(LOG_LEVEL), debug trace), )
LogDebug = $$(info $(LOG_PREFIX)$$(strip $$1))
LOG_DEBUG :=
else
LogDebug =
LOG_DEBUG := > /dev/null
endif
- ifneq ($$(findstring $$(LOG_LEVEL), trace),)
+ ifneq ($$(findstring $$(LOG_LEVEL), trace), )
LogTrace = $$(info $(LOG_PREFIX)$$(strip $$1))
LOG_TRACE :=
else
@@ -164,14 +164,14 @@ PARAM_SEQUENCE := $(call sequence, 2, $(MAX_PARAMS))
# BAR := some parameter value, \
# ))
define NamedParamsMacroTemplate
- $(if $($(MAX_PARAMS)),$(error Internal makefile error: \
+ $(if $($(MAX_PARAMS)), $(error Internal makefile error: \
Too many named arguments to macro, please update MAX_PARAMS in MakeBase.gmk))
# Iterate over 2 3 4... and evaluate the named parameters with $1_ as prefix
- $(foreach i,$(PARAM_SEQUENCE), $(if $(strip $($i)),\
+ $(foreach i, $(PARAM_SEQUENCE), $(if $(strip $($i)), \
$(strip $1)_$(strip $(call EscapeHash, $(call DoubleDollar, $($i))))$(NEWLINE)))
# Debug print all named parameter names and values
$(if $(findstring $(LOG_LEVEL), trace), \
- $(info $0 $(strip $1) $(foreach i,$(PARAM_SEQUENCE), \
+ $(info $0 $(strip $1) $(foreach i, $(PARAM_SEQUENCE), \
$(if $(strip $($i)),$(NEWLINE) $(strip [$i] $(if $(filter $(LOG_LEVEL), trace), \
$($i), $(wordlist 1, 20, $($(i))) $(if $(word 21, $($(i))), ...)))))))
@@ -246,8 +246,8 @@ DependOnVariableFileName = \
# Param 1 - Name of variable
DependOnVariableWriteFile = \
$(call MakeDir, $(dir $($1_filename))) \
- $(call WriteFile, $1_old:=$(call DoubleDollar,$(call EscapeHash,$($1))), \
- $($1_filename)) \
+ $(call WriteFile, $1_old := $(call DoubleDollar,$(call EscapeHash,$($1))), \
+ $($1_filename)) \
# Does the actual work with parameters stripped.
# If the file exists AND the contents is the same as the variable, do nothing
@@ -260,7 +260,7 @@ DependOnVariableHelper = \
$(eval $1_filename := $(call DependOnVariableFileName, $1, $2)) \
$(if $(wildcard $($1_filename)), \
$(eval include $($1_filename)) \
- $(if $(call equals, $(strip $($1)), $(strip $($1_old))),,\
+ $(if $(call equals, $(strip $($1)), $(strip $($1_old))),, \
$(if $(findstring $(LOG_LEVEL), trace), \
$(info NewVariable $1: >$(strip $($1))<) \
$(info OldVariable $1: >$(strip $($1_old))<) \
diff --git a/make/common/MakeIO.gmk b/make/common/MakeIO.gmk
index 865c5cae2e5..b7843817b5e 100644
--- a/make/common/MakeIO.gmk
+++ b/make/common/MakeIO.gmk
@@ -23,7 +23,7 @@
# questions.
#
-ifeq (,$(_MAKEBASE_GMK))
+ifeq ($(_MAKEBASE_GMK), )
$(error You must include MakeBase.gmk prior to including MakeIO.gmk)
endif
@@ -67,22 +67,22 @@ else # HAS_FILE_FUNCTION = false
$(eval compress_paths += \
$(strip $(shell $(CAT) $(TOPDIR)/make/common/support/ListPathsSafely-post-compress.incl)))
- decompress_paths=$(SED) -f $(TOPDIR)/make/common/support/ListPathsSafely-uncompress.sed \
+ decompress_paths = $(SED) -f $(TOPDIR)/make/common/support/ListPathsSafely-uncompress.sed \
-e 's|X99|\\n|g' \
-e 's|X98|$(OUTPUTDIR)|g' -e 's|X97|$(TOPDIR)|g' \
-e 's|X00|X|g'
ListPathsSafely_IfPrintf = \
- $(if $(word $3,$($(strip $1))), \
+ $(if $(word $3, $($(strip $1))), \
$(shell $(PRINTF) -- "$(strip $(call EscapeDollar, \
- $(call compress_paths, $(wordlist $3,$4,$($(strip $1))))))\n" \
+ $(call compress_paths, $(wordlist $3, $4, $($(strip $1))))))\n" \
| $(decompress_paths) >> $2))
# Param 1 - Name of variable containing paths/arguments to output
# Param 2 - File to print to
# Param 3 - Set to true to append to file instead of overwriting
define ListPathsSafely
- ifneq (,$$(word 30001,$$($$(strip $1))))
+ ifneq ($$(word 30001, $$($$(strip $1))), )
$$(error Cannot list safely more than 30000 paths. $1 has $$(words $$($$(strip $1))) paths!)
endif
$$(call MakeDir, $$(dir $2))
diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk
index fa885dacb6d..fd6b9b4ec10 100644
--- a/make/common/Modules.gmk
+++ b/make/common/Modules.gmk
@@ -177,8 +177,8 @@ $(MODULE_DEPS_MAKEFILE): $(MODULE_INFOS) \
$(call MakeTargetDir)
$(RM) $@
$(foreach m, $(MODULE_INFOS), \
- ( $(PRINTF) "DEPS_$(call GetModuleNameFromModuleInfo, $m) :=" && \
- $(AWK) -v MODULE=$(call GetModuleNameFromModuleInfo, $m) '\
+ ( $(PRINTF) "DEPS_$(call GetModuleNameFromModuleInfo, $m) := " && \
+ $(AWK) -v MODULE=$(call GetModuleNameFromModuleInfo, $m) ' \
BEGIN { if (MODULE != "java.base") printf(" java.base"); } \
/^ *requires/ { sub(/;/, ""); \
sub(/requires /, " "); \
@@ -191,8 +191,8 @@ $(MODULE_DEPS_MAKEFILE): $(MODULE_INFOS) \
gsub(/\r/, ""); \
printf(" %s", $$0) } \
END { printf("\n") }' $m && \
- $(PRINTF) "TRANSITIVE_MODULES_$(call GetModuleNameFromModuleInfo, $m) :=" && \
- $(AWK) -v MODULE=$(call GetModuleNameFromModuleInfo, $m) '\
+ $(PRINTF) "TRANSITIVE_MODULES_$(call GetModuleNameFromModuleInfo, $m) := " && \
+ $(AWK) -v MODULE=$(call GetModuleNameFromModuleInfo, $m) ' \
BEGIN { if (MODULE != "java.base") printf(" java.base"); } \
/^ *requires *transitive/ { \
sub(/;/, ""); \
@@ -221,7 +221,7 @@ FindTransitiveDepsForModule = \
$(foreach m, $(call FindDepsForModule, $1), \
$(call FindDepsForModule, $m) \
$(foreach n, $(call FindDepsForModule, $m), \
- $(call FindDepsForModule, $n))))
+ $(call FindDepsForModule, $n))))
# Find dependencies ("requires") transitively in 3 levels for a set of modules.
# Param 1: List of modules to find dependencies for.
@@ -240,7 +240,7 @@ FindTransitiveIndirectDepsForModule = \
$(foreach m, $(call FindIndirectExportsForModule, $1), \
$(call FindIndirectExportsForModule, $m) \
$(foreach n, $(call FindIndirectExportsForModule, $m), \
- $(call FindIndirectExportsForModule, $n))))
+ $(call FindIndirectExportsForModule, $n))))
# Finds indirect exported modules transitively in 3 levels for a set of modules.
# Param 1: List of modules to find indirect exported modules for.
diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk
index abd4f65f753..66d07df3b78 100644
--- a/make/common/NativeCompilation.gmk
+++ b/make/common/NativeCompilation.gmk
@@ -182,7 +182,7 @@ define SetupNativeCompilationBody
# Now call CreateCompiledNativeFile for each source file we are going to compile.
$$(foreach file, $$($1_SRCS), \
- $$(eval $$(call CreateCompiledNativeFile,$1_$$(notdir $$(file)),\
+ $$(eval $$(call CreateCompiledNativeFile,$1_$$(notdir $$(file)), \
FILE := $$(file), \
BASE := $1, \
)) \
@@ -222,7 +222,7 @@ define SetupNativeCompilationBody
ifeq ($(GENERATE_COMPILE_COMMANDS_ONLY), true)
# Override all targets (this is a hack)
- $1 := $$($1_ALL_OBJS_JSON)
+ $1 := $$($1_ALL_OBJS_JSON) $$($1_LDFLAGS_FILE)
endif
endef
@@ -292,6 +292,7 @@ define SetupBasicVariables
$1_TARGET := $$($1_OUTPUT_DIR)/$$($1_BASENAME)
$1_NOSUFFIX := $$($1_PREFIX)$$($1_NAME)
$1_SAFE_NAME := $$(strip $$(subst /,_, $1))
+ $1_UNIQUE_NAME = $$($1_TYPE)_$$(subst /,_,$$(patsubst $$(OUTPUTDIR)/%/,%,$$(dir $$($1_OBJECT_DIR))))_$$($1_NOSUFFIX)
endef
################################################################################
diff --git a/make/common/ProcessMarkdown.gmk b/make/common/ProcessMarkdown.gmk
index 125892504f9..960c4d66c30 100644
--- a/make/common/ProcessMarkdown.gmk
+++ b/make/common/ProcessMarkdown.gmk
@@ -22,7 +22,7 @@
# questions.
#
-ifeq (,$(_MAKEBASE_GMK))
+ifeq ($(_MAKEBASE_GMK), )
$(error You must include MakeBase.gmk prior to including ProcessMarkdown.gmk)
endif
@@ -92,7 +92,7 @@ define ProcessMarkdown
-t $$($1_FORMAT) --eol=lf --standalone \
$$($1_$2_CSS_OPTION) $$($1_$2_OPTIONS_FROM_SRC) $$($1_$2_OPTIONS) \
'$$($1_$2_PANDOC_INPUT)' -o '$$($1_$2_PANDOC_OUTPUT)')
- ifneq ($$(findstring $$(LOG_LEVEL), debug trace),)
+ ifneq ($$(findstring $$(LOG_LEVEL), debug trace), )
TOO_LONG_LINES=`$$(GREP) -E -e '^.{80}.+$$$$' $$<` || true ; \
if [ "x$$$$TOO_LONG_LINES" != x ]; then \
$$(ECHO) "Warning: Unsuitable markdown in $$<:" ; \
diff --git a/make/common/TestFilesCompilation.gmk b/make/common/TestFilesCompilation.gmk
index 8060a45fc68..e09e144fa06 100644
--- a/make/common/TestFilesCompilation.gmk
+++ b/make/common/TestFilesCompilation.gmk
@@ -26,7 +26,7 @@
ifndef _TEST_FILES_COMPILATION_GMK
_TEST_FILES_COMPILATION_GMK := 1
-ifeq (,$(_MAKEBASE_GMK))
+ifeq ($(_MAKEBASE_GMK), )
$(error You must include MakeBase.gmk prior to including TestFilesCompilation.gmk)
endif
@@ -95,7 +95,7 @@ define SetupTestFilesCompilationBody
TEST_CFLAGS := -I$(TOPDIR)/test/lib/native
# Setup a compilation for each and every one of them
- $$(foreach file, $$($1_FILTERED_FILE_LIST),\
+ $$(foreach file, $$($1_FILTERED_FILE_LIST), \
$$(eval name := $$(strip $$(basename $$(notdir $$(file))))) \
$$(eval unprefixed_name := $$(patsubst $$($1_PREFIX)%, %, $$(name))) \
$$(eval $$(call SetupJdkNativeCompilation, BUILD_TEST_$$(name), \
@@ -112,16 +112,19 @@ define SetupTestFilesCompilationBody
CXXFLAGS := $$(TEST_CFLAGS) $$($1_CFLAGS) $$($1_CFLAGS_$$(name)), \
LD_SET_ORIGIN := $$($1_LD_SET_ORIGIN), \
LDFLAGS := $$($1_LDFLAGS_$$(name)), \
- DISABLED_WARNINGS_gcc := format undef unused-function unused-value, \
- DISABLED_WARNINGS_clang := undef format-nonliteral \
- missing-field-initializers sometimes-uninitialized, \
+ DISABLED_WARNINGS_gcc := format undef unused-but-set-variable \
+ unused-const-variable unused-function unused-value \
+ unused-variable, \
+ DISABLED_WARNINGS_clang := format-nonliteral \
+ missing-field-initializers sometimes-uninitialized undef \
+ unused-but-set-variable unused-function unused-variable, \
DEFAULT_LIBCXX := false, \
JDK_LIBS := $$($1_JDK_LIBS_$$(name)), \
LIBS := $$($1_LIBS_$$(name)), \
DEFAULT_VERSIONINFO_RESOURCE := false, \
- OPTIMIZATION := $$(if $$($1_OPTIMIZATION_$$(name)),$$($1_OPTIMIZATION_$$(name)),LOW), \
+ OPTIMIZATION := $$(if $$($1_OPTIMIZATION_$$(name)), $$($1_OPTIMIZATION_$$(name)), LOW), \
COPY_DEBUG_SYMBOLS := $$($1_COPY_DEBUG_SYMBOLS), \
- STRIP_SYMBOLS := $$(if $$($1_STRIP_SYMBOLS_$$(name)),$$($1_STRIP_SYMBOLS_$$(name)),false), \
+ STRIP_SYMBOLS := $$(if $$($1_STRIP_SYMBOLS_$$(name)), $$($1_STRIP_SYMBOLS_$$(name)), false), \
BUILD_INFO_LOG_MACRO := LogInfo, \
)) \
$$(eval $1 += $$(BUILD_TEST_$$(name)) ) \
diff --git a/make/common/TextFileProcessing.gmk b/make/common/TextFileProcessing.gmk
index 1bb32242652..6746296df24 100644
--- a/make/common/TextFileProcessing.gmk
+++ b/make/common/TextFileProcessing.gmk
@@ -23,7 +23,7 @@
# questions.
#
-ifeq (,$(_MAKEBASE_GMK))
+ifeq ($(_MAKEBASE_GMK), )
$(error You must include MakeBase.gmk prior to including TextFileProcessing.gmk)
endif
@@ -80,47 +80,47 @@ endef
SetupTextFileProcessing = $(NamedParamsMacroTemplate)
define SetupTextFileProcessingBody
- ifneq ($$($1_SOURCE_FILES),)
- ifneq ($$($1_SOURCE_DIRS),)
+ ifneq ($$($1_SOURCE_FILES), )
+ ifneq ($$($1_SOURCE_DIRS), )
$$(error Cannot use both SOURCE_FILES and SOURCE_DIRS (in $1))
endif
- ifneq ($$($1_EXCLUDE_FILES)$$($1_INCLUDE_FILES),)
+ ifneq ($$($1_EXCLUDE_FILES)$$($1_INCLUDE_FILES), )
$$(error Cannot INCLUDE/EXCLUDE_FILES with SOURCE_FILES (in $1))
endif
else
- ifeq ($$($1_SOURCE_DIRS),)
+ ifeq ($$($1_SOURCE_DIRS), )
$$(error Must specify either SOURCE_FILES or SOURCE_DIRS (in $1))
endif
# Find all files in the source trees. Sort to remove duplicates.
$$(foreach src, $$($1_SOURCE_DIRS), $$(if $$(wildcard $$(src)), , \
$$(error SOURCE_DIRS contains missing directory $$(src) (in $1))))
- ifneq ($$($1_SOURCE_BASE_DIR),)
+ ifneq ($$($1_SOURCE_BASE_DIR), )
$$(foreach src, $$($1_SOURCE_DIRS), \
$$(if $$(findstring $$($1_SOURCE_BASE_DIR), $$(src)), , \
$$(error SOURCE_DIRS contains directory $$(src) outside \
SOURCE_BASE_DIR $$($1_SOURCE_BASE_DIR) (in $1))))
endif
$1_SOURCE_FILES := $$(sort $$(call FindFiles,$$($1_SOURCE_DIRS)))
- $1_EXCLUDE_FILES:=$$(foreach i,$$($1_SOURCE_DIRS),$$(addprefix $$i/,$$($1_EXCLUDE_FILES)))
- $1_INCLUDE_FILES:=$$(foreach i,$$($1_SOURCE_DIRS),$$(addprefix $$i/,$$($1_INCLUDE_FILES)))
- $1_SOURCE_FILES := $$(filter-out $$($1_EXCLUDE_FILES),$$($1_SOURCE_FILES))
- ifneq (,$$(strip $$($1_INCLUDE_FILES)))
- $1_SOURCE_FILES := $$(filter $$($1_INCLUDE_FILES),$$($1_SOURCE_FILES))
+ $1_EXCLUDE_FILES := $$(foreach i, $$($1_SOURCE_DIRS), $$(addprefix $$i/, $$($1_EXCLUDE_FILES)))
+ $1_INCLUDE_FILES := $$(foreach i, $$($1_SOURCE_DIRS), $$(addprefix $$i/, $$($1_INCLUDE_FILES)))
+ $1_SOURCE_FILES := $$(filter-out $$($1_EXCLUDE_FILES), $$($1_SOURCE_FILES))
+ ifneq ($$(strip $$($1_INCLUDE_FILES)), )
+ $1_SOURCE_FILES := $$(filter $$($1_INCLUDE_FILES), $$($1_SOURCE_FILES))
endif
- ifeq (,$$($1_SOURCE_FILES))
+ ifeq ($$($1_SOURCE_FILES), )
$$(info No sources found for $1 when looking inside the dirs $$($1_SRC))
endif
endif
- ifneq ($$($1_REPLACEMENTS),)
+ ifneq ($$($1_REPLACEMENTS), )
# We have a replacement request, prepare it for the recipe
- ifneq ($$(findstring /,$$($1_REPLACEMENTS)),)
+ ifneq ($$(findstring /, $$($1_REPLACEMENTS)), )
# Cannot use / as separator
- ifneq ($$(findstring @,$$($1_REPLACEMENTS)),)
+ ifneq ($$(findstring @, $$($1_REPLACEMENTS)), )
# Cannot use @ as separator
- ifneq ($$(findstring |,$$($1_REPLACEMENTS)),)
+ ifneq ($$(findstring |, $$($1_REPLACEMENTS)), )
# Cannot use | as separator
- ifneq ($$(findstring !,$$($1_REPLACEMENTS)),)
+ ifneq ($$(findstring !, $$($1_REPLACEMENTS)), )
# Cannot use ! as separator. Give up.
$$(error No suitable sed separator can be found for $1. Tested /, @, | and !)
else
@@ -161,7 +161,7 @@ define SetupTextFileProcessingBody
$1_REPLACEMENTS_COMMAND_LINE := $(CAT)
endif
- ifneq ($$($1_INCLUDES),)
+ ifneq ($$($1_INCLUDES), )
# We have a include request, prepare it for the recipe.
# Convert an INCLUDE like this PATTERN_1 => file1 ; PATTERN_2 => file2 ;
# into an awk script fragment like this:
@@ -190,7 +190,7 @@ define SetupTextFileProcessingBody
# Reset target list before populating it
$1 :=
- ifneq ($$($1_OUTPUT_FILE),)
+ ifneq ($$($1_OUTPUT_FILE), )
ifneq ($$(words $$($1_SOURCE_FILES)), 1)
$$(error Cannot use OUTPUT_FILE for more than one source file (in $1))
endif
@@ -199,12 +199,12 @@ define SetupTextFileProcessingBody
$$(eval $$(call SetupSingleTextFileForProcessing,$1, $$($1_SOURCE_FILES), \
$$(patsubst %/, %, $$(dir $$($1_OUTPUT_FILE))), $$(notdir $$($1_OUTPUT_FILE))))
else
- ifeq ($$($1_OUTPUT_DIR),)
+ ifeq ($$($1_OUTPUT_DIR), )
$$(error Neither OUTPUT_FILE nor OUTPUT_DIR was specified (in $1))
endif
# Now call add_native_source for each source file we are going to process.
- ifeq ($$($1_SOURCE_BASE_DIR),)
+ ifeq ($$($1_SOURCE_BASE_DIR), )
# With no base dir specified, put all files in target dir, flattening any
# hierarchies. Note that $1 is space sensitive and must disobey whitespace
# rules.
diff --git a/make/common/Utils.gmk b/make/common/Utils.gmk
index 7f1cbd61f38..26d05ed91be 100644
--- a/make/common/Utils.gmk
+++ b/make/common/Utils.gmk
@@ -23,7 +23,7 @@
# questions.
#
-ifeq (,$(_MAKEBASE_GMK))
+ifeq ($(_MAKEBASE_GMK), )
$(error You must include MakeBase.gmk prior to including Utils.gmk)
endif
@@ -36,7 +36,7 @@ endif
# String equals
equals = \
$(if $(strip $1)$(strip $2),$(strip \
- $(and $(findstring $(strip $1),$(strip $2)),\
+ $(and $(findstring $(strip $1),$(strip $2)), \
$(findstring $(strip $2),$(strip $1)))), \
true \
)
@@ -64,7 +64,7 @@ uppercase = \
# Param 2 - ending number
sequence = \
$(wordlist $1, $2, $(strip \
- $(eval SEQUENCE_COUNT :=) \
+ $(eval SEQUENCE_COUNT := ) \
$(call _sequence-do,$(strip $2))))
_sequence-do = \
@@ -225,7 +225,7 @@ uniq = \
# whitespace-separated words in $1 is a substring.
containing = \
$(strip \
- $(foreach v,$(strip $2),\
+ $(foreach v,$(strip $2), \
$(call uniq,$(foreach p,$(strip $1),$(if $(findstring $p,$v),$v)))))
# Returns all whitespace-separated words in $2 where none of the
@@ -242,7 +242,7 @@ dups = \
# $1 - List of prefixes
# $2 - List of elements to process
remove-prefixes = \
- $(strip $(if $1,$(patsubst $(firstword $1)%,%,\
+ $(strip $(if $1,$(patsubst $(firstword $1)%,%, \
$(call remove-prefixes,$(filter-out $(firstword $1),$1),$2)),$2))
################################################################################
@@ -270,11 +270,11 @@ Or = \
ifeq ($(IS_GNU_DATE), yes)
EpochToISO8601 = \
$(shell $(DATE) --utc --date="@$(strip $1)" \
- +"$(ISO_8601_FORMAT_STRING)" 2> /dev/null)
+ +"$(ISO_8601_FORMAT_STRING)" 2> /dev/null)
else
EpochToISO8601 = \
$(shell $(DATE) -u -j -f "%s" "$(strip $1)" \
- +"$(ISO_8601_FORMAT_STRING)" 2> /dev/null)
+ +"$(ISO_8601_FORMAT_STRING)" 2> /dev/null)
endif
################################################################################
diff --git a/make/common/ZipArchive.gmk b/make/common/ZipArchive.gmk
index 480f4c5effd..928bff9bd84 100644
--- a/make/common/ZipArchive.gmk
+++ b/make/common/ZipArchive.gmk
@@ -29,7 +29,7 @@ _ZIP_ARCHIVE_GMK := 1
# Depends on build tools for MakeZipReproducible
include ../ToolsJdk.gmk
-ifeq (,$(_MAKEBASE_GMK))
+ifeq ($(_MAKEBASE_GMK), )
$(error You must include MakeBase.gmk prior to including ZipArchive.gmk)
endif
@@ -65,9 +65,9 @@ define SetupZipArchiveBody
# To avoid running find over too large sets of files, which causes make to crash
# on some configurations (cygwin), use INCLUDES and INCLUDE_FILES to build a set
# of directories to run find in, if available.
- ifneq ($$($1_INCLUDES)$$($1_INCLUDE_FILES),)
- $1_FIND_LIST := $$(wildcard $$(foreach s,$$($1_SRC_SLASH), \
- $$(addprefix $$s,$$($1_INCLUDES) $$($1_INCLUDE_FILES))))
+ ifneq ($$($1_INCLUDES)$$($1_INCLUDE_FILES), )
+ $1_FIND_LIST := $$(wildcard $$(foreach s, $$($1_SRC_SLASH), \
+ $$(addprefix $$s, $$($1_INCLUDES) $$($1_INCLUDE_FILES))))
else
$1_FIND_LIST := $$($1_SRC_SLASH)
endif
@@ -76,38 +76,38 @@ define SetupZipArchiveBody
# If asked to, follow symlinks in this find since that is what zip does. To do
# this, we need to call ShellFindFiles directly.
ifeq ($$($1_FOLLOW_SYMLINKS), true)
- $1_ALL_SRCS := $$(call not-containing,_the.,$$(call ShellFindFiles,$$($1_FIND_LIST), , -L))
+ $1_ALL_SRCS := $$(call not-containing, _the., $$(call ShellFindFiles, $$($1_FIND_LIST), , -L))
else
- $1_ALL_SRCS := $$(call not-containing,_the.,$$(call FindFiles,$$($1_FIND_LIST)))
+ $1_ALL_SRCS := $$(call not-containing, _the., $$(call FindFiles, $$($1_FIND_LIST)))
endif
# Filter on suffixes if set
- ifneq ($$($1_SUFFIXES),)
+ ifneq ($$($1_SUFFIXES), )
$1_ALL_SRCS := $$(filter $$(addprefix %, $$($1_SUFFIXES)), $$($1_ALL_SRCS))
endif
- ifneq ($$($1_INCLUDES),)
- ifneq ($$($1_SUFFIXES),)
- $1_ZIP_INCLUDES := $$(foreach s,$$($1_SUFFIXES), \
- $$(addprefix -i$(SPACE)$(DQUOTE),$$(addsuffix /*$$s$(DQUOTE),$$($1_INCLUDES))))
+ ifneq ($$($1_INCLUDES), )
+ ifneq ($$($1_SUFFIXES), )
+ $1_ZIP_INCLUDES := $$(foreach s, $$($1_SUFFIXES), \
+ $$(addprefix -i$(SPACE)$(DQUOTE), $$(addsuffix /*$$s$(DQUOTE), $$($1_INCLUDES))))
else
- $1_ZIP_INCLUDES := $$(addprefix -i$(SPACE)$(DQUOTE),$$(addsuffix /*$(DQUOTE),$$($1_INCLUDES)))
+ $1_ZIP_INCLUDES := $$(addprefix -i$(SPACE)$(DQUOTE), $$(addsuffix /*$(DQUOTE), $$($1_INCLUDES)))
endif
else
- ifneq ($$($1_SUFFIXES),)
- $1_ZIP_INCLUDES := $$(foreach s,$$($1_SUFFIXES), \
- $$(addprefix -i$(SPACE)$(DQUOTE),*$$s$(DQUOTE)))
+ ifneq ($$($1_SUFFIXES), )
+ $1_ZIP_INCLUDES := $$(foreach s, $$($1_SUFFIXES), \
+ $$(addprefix -i$(SPACE)$(DQUOTE), *$$s$(DQUOTE)))
endif
endif
- ifneq ($$($1_INCLUDE_FILES),)
- $1_ZIP_INCLUDES += $$(addprefix -i$(SPACE),$$($1_INCLUDE_FILES))
+ ifneq ($$($1_INCLUDE_FILES), )
+ $1_ZIP_INCLUDES += $$(addprefix -i$(SPACE), $$($1_INCLUDE_FILES))
endif
- ifneq ($$($1_EXCLUDES),)
- $1_ZIP_EXCLUDES := $$(addprefix -x$(SPACE)$(DQUOTE),$$(addsuffix /*$(DQUOTE),$$($1_EXCLUDES)))
- $1_SRC_EXCLUDES := $$(foreach s,$$($1_SRC_SLASH),$$(addprefix $$s,$$(addsuffix /%,$$($1_EXCLUDES))))
- $1_ALL_SRCS := $$(filter-out $$($1_SRC_EXCLUDES),$$($1_ALL_SRCS))
+ ifneq ($$($1_EXCLUDES), )
+ $1_ZIP_EXCLUDES := $$(addprefix -x$(SPACE)$(DQUOTE), $$(addsuffix /*$(DQUOTE), $$($1_EXCLUDES)))
+ $1_SRC_EXCLUDES := $$(foreach s, $$($1_SRC_SLASH), $$(addprefix $$s, $$(addsuffix /%, $$($1_EXCLUDES))))
+ $1_ALL_SRCS := $$(filter-out $$($1_SRC_EXCLUDES), $$($1_ALL_SRCS))
endif
- ifneq ($$($1_EXCLUDE_FILES),)
+ ifneq ($$($1_EXCLUDE_FILES), )
$1_SRC_EXCLUDE_FILES := $$(addprefix %, $$($1_EXCLUDE_FILES)) $$($1_EXCLUDE_FILES)
$1_ALL_SRCS := $$(filter-out $$($1_SRC_EXCLUDE_FILES), $$($1_ALL_SRCS))
$$(foreach s, $$($1_SRC_SLASH), \
@@ -134,7 +134,7 @@ define SetupZipArchiveBody
endif
# Use a slightly shorter name for logging, but with enough path to identify this zip.
- $1_NAME:=$$(subst $$(OUTPUTDIR)/,,$$($1_ZIP))
+ $1_NAME := $$(subst $$(OUTPUTDIR)/,,$$($1_ZIP))
# Now $1_ALL_SRCS should contain all sources that are going to be put into the zip.
# I.e. the zip -i and -x options should match the filtering done in the makefile.
@@ -167,7 +167,7 @@ define SetupZipArchiveBody
) \
) \
)
- $$(foreach s,$$($1_SRC_SLASH), $$(call ExecuteWithLog, \
+ $$(foreach s, $$($1_SRC_SLASH), $$(call ExecuteWithLog, \
$$(SUPPORT_OUTPUTDIR)/zip/$$(patsubst $$(OUTPUTDIR)/%,%, $$@), \
(cd $$s && $(ZIPEXE) -qru $$($1_ZIP_OPTIONS) $$@ . \
$$($1_ZIP_INCLUDES) $$($1_ZIP_EXCLUDES) -x \*_the.\* \
diff --git a/make/common/modules/LauncherCommon.gmk b/make/common/modules/LauncherCommon.gmk
index fc7d721fb63..7c2cef58835 100644
--- a/make/common/modules/LauncherCommon.gmk
+++ b/make/common/modules/LauncherCommon.gmk
@@ -74,7 +74,7 @@ define SetupBuildLauncherBody
endif
ifneq ($$($1_MAIN_CLASS), )
- $1_JAVA_ARGS += -ms8m
+ $1_JAVA_ARGS += -Xms8m
$1_LAUNCHER_CLASS := -m $$($1_MAIN_MODULE)/$$($1_MAIN_CLASS)
endif
@@ -135,7 +135,8 @@ define SetupBuildLauncherBody
$$($1_CFLAGS), \
CFLAGS_windows := $$($1_CFLAGS_windows), \
EXTRA_HEADER_DIRS := java.base:libjvm, \
- DISABLED_WARNINGS_gcc := unused-function, \
+ DISABLED_WARNINGS_gcc := unused-function unused-variable, \
+ DISABLED_WARNINGS_clang := unused-function, \
LDFLAGS := $$($1_LDFLAGS), \
LDFLAGS_linux := $$(call SET_EXECUTABLE_ORIGIN,/../lib), \
LDFLAGS_macosx := $$(call SET_EXECUTABLE_ORIGIN,/../lib), \
diff --git a/make/common/native/CompileFile.gmk b/make/common/native/CompileFile.gmk
index a9384fb0cf5..0c67a337acf 100644
--- a/make/common/native/CompileFile.gmk
+++ b/make/common/native/CompileFile.gmk
@@ -41,10 +41,10 @@
define WriteCompileCommandsFragment
$(call LogInfo, Creating compile commands fragment for $(notdir $3))
$(call MakeDir, $(dir $1))
- $(call WriteFile,{ \
+ $(call WriteFile, { \
"directory": "$(strip $(call FixPath, $2))"$(COMMA) \
"file": "$(strip $(call FixPath, $3))"$(COMMA) \
- "command": "$(strip $(subst $(DQUOTE),\$(DQUOTE),$(subst \,\\,\
+ "command": "$(strip $(subst $(DQUOTE),\$(DQUOTE),$(subst \,\\, \
$(subst $(FIXPATH),,$(call FixPath, $4)))))" \
}$(COMMA), \
$1)
@@ -344,7 +344,7 @@ define CreateWindowsResourceFile
$(ECHO) $$($1_RES): \\ > $$($1_RES_DEPS_FILE) ; \
$(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_RES_DEPS_FILE)$(OBJ_SUFFIX).log \
>> $$($1_RES_DEPS_FILE) ; \
- $(ECHO) >> $$($1_RES_DEPS_FILE) ;\
+ $(ECHO) >> $$($1_RES_DEPS_FILE) ; \
$(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_RES_DEPS_FILE) \
> $$($1_RES_DEPS_TARGETS_FILE)
endif
diff --git a/make/common/native/DebugSymbols.gmk b/make/common/native/DebugSymbols.gmk
index 7e014f416d6..f7a5a4021e2 100644
--- a/make/common/native/DebugSymbols.gmk
+++ b/make/common/native/DebugSymbols.gmk
@@ -94,7 +94,7 @@ define CreateDebugSymbols
$1 += $$($1_DEBUGINFO_ZIP)
endif
- endif # !STATIC_LIBRARY
+ endif # !STATIC_LIBRARY
endif # $1_DEBUG_SYMBOLS != false
endif # COPY_DEBUG_SYMBOLS
endef
diff --git a/make/common/native/Link.gmk b/make/common/native/Link.gmk
index 2090218ffbb..23977e954ca 100644
--- a/make/common/native/Link.gmk
+++ b/make/common/native/Link.gmk
@@ -109,6 +109,11 @@ define CreateStaticLibrary
$(if $$($1_LINK_OBJS_RELATIVE), $$(CD) $$(OUTPUTDIR) ; ) \
$$($1_LD) $(LDFLAGS_CXX_PARTIAL_LINKING) $$($1_SYSROOT_LDFLAGS) \
-o $$($1_TARGET_RELOCATABLE) $$($1_LD_OBJ_ARG))
+ # 'ld -r' might invalidate the .llvm_addrsig section, and this will cause subsequent
+ # calls to lld (with '-Wl,--icf=safe') to fail when linking with this library, so
+ # remove that section.
+ $$(call ExecuteWithLog, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_objcopy_remove_llvm_addrsig_section, \
+ $$($1_OBJCOPY) --remove-section=.llvm_addrsig $$($1_TARGET_RELOCATABLE))
endif
$$(call ExecuteWithLog, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_run_ar, \
$(if $$($1_LINK_OBJS_RELATIVE), $$(CD) $$(OUTPUTDIR) ; ) \
@@ -193,4 +198,16 @@ define CreateDynamicLibraryOrExecutable
$(CODESIGN) -f -s $$($1_CODESIGN_OPTS) --entitlements \
$$(call GetEntitlementsFile, $$@) $$@)
endif
+
+ # This is for IDE integration purposes only, and is not normally generated
+ $1_LDFLAGS_FILE := $$(MAKESUPPORT_OUTPUTDIR)/compile-commands/$$($1_UNIQUE_NAME)-ldflags.txt
+
+ $1_ALL_LD_ARGS := $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $$($1_SYSROOT_LDFLAGS) \
+ $$($1_LIBS) $$($1_EXTRA_LIBS)
+
+ $$($1_LDFLAGS_FILE): $$($1_VARDEPS_FILE)
+ $$(call LogInfo, Creating compile commands linker flags output for $$($1_BASENAME))
+ $$(call MakeDir, $$(dir $$@))
+ $$(ECHO) $$($1_ALL_LD_ARGS) > $$@
+
endef
diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf
index deb5e36f605..a6b383daa8f 100644
--- a/make/conf/github-actions.conf
+++ b/make/conf/github-actions.conf
@@ -29,17 +29,21 @@ GTEST_VERSION=1.14.0
JTREG_VERSION=7.4+1
LINUX_X64_BOOT_JDK_EXT=tar.gz
-LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22/830ec9fcccef480bb3e73fb7ecafe059/36/GPL/openjdk-22_linux-x64_bin.tar.gz
-LINUX_X64_BOOT_JDK_SHA256=4d65cc6ed28711768fd72c2043a7925f7c83f5f51bb64970bd9d52f7791fc6ac
+LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_linux-x64_bin.tar.gz
+LINUX_X64_BOOT_JDK_SHA256=08fea92724127c6fa0f2e5ea0b07ff4951ccb1e2f22db3c21eebbd7347152a67
-MACOS_X64_BOOT_JDK_EXT=tar.gz
-MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22/830ec9fcccef480bb3e73fb7ecafe059/36/GPL/openjdk-22_macos-x64_bin.tar.gz
-MACOS_X64_BOOT_JDK_SHA256=ae31fe10916429e3fe284266095067a5ce9fecbdc03ff1a079d20459f731ca36
+ALPINE_LINUX_X64_BOOT_JDK_EXT=tar.gz
+ALPINE_LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin23-binaries/releases/download/jdk-23%2B37/OpenJDK23U-jdk_x64_alpine-linux_hotspot_23_37.tar.gz
+ALPINE_LINUX_X64_BOOT_JDK_SHA256=bff4c78f30d8d173e622bf2f40c36113df47337fc6d1ee5105ed2459841165aa
MACOS_AARCH64_BOOT_JDK_EXT=tar.gz
-MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22/830ec9fcccef480bb3e73fb7ecafe059/36/GPL/openjdk-22_macos-aarch64_bin.tar.gz
-MACOS_AARCH64_BOOT_JDK_SHA256=d10f82429d01047968c52c7975c326388cb5d212791e14c1de21c987463a4b53
+MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_macos-aarch64_bin.tar.gz
+MACOS_AARCH64_BOOT_JDK_SHA256=9527bf080a74ae6dca51df413aa826f0c011c6048885e4c8ad112172be8815f3
+
+MACOS_X64_BOOT_JDK_EXT=tar.gz
+MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_macos-x64_bin.tar.gz
+MACOS_X64_BOOT_JDK_SHA256=5c3a909fd2079d0e376dd43c85c4f7d02d08914866f196480bd47784b2a0121e
WINDOWS_X64_BOOT_JDK_EXT=zip
-WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22/830ec9fcccef480bb3e73fb7ecafe059/36/GPL/openjdk-22_windows-x64_bin.zip
-WINDOWS_X64_BOOT_JDK_SHA256=8f5138fecb53c08c20abd4fa6812f9400051f3852582a2142ffda0dff73a5824
+WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_windows-x64_bin.zip
+WINDOWS_X64_BOOT_JDK_SHA256=cba5013874ba50cae543c86fe6423453816c77281e2751a8a9a633d966f1dc04
diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js
index 30c45d4cde1..0785d340f48 100644
--- a/make/conf/jib-profiles.js
+++ b/make/conf/jib-profiles.js
@@ -390,8 +390,8 @@ var getJibProfilesCommon = function (input, data) {
};
};
- common.boot_jdk_version = "22";
- common.boot_jdk_build_number = "36";
+ common.boot_jdk_version = "23";
+ common.boot_jdk_build_number = "37";
common.boot_jdk_home = input.get("boot_jdk", "install_path") + "/jdk-"
+ common.boot_jdk_version
+ (input.build_os == "macosx" ? ".jdk/Contents/Home" : "");
@@ -415,7 +415,7 @@ var getJibProfilesProfiles = function (input, common, data) {
"linux-x64": {
target_os: "linux",
target_cpu: "x64",
- dependencies: ["devkit", "gtest", "build_devkit", "graphviz", "pandoc"],
+ dependencies: ["devkit", "gtest", "build_devkit", "graphviz", "pandoc", "tidy"],
configure_args: concat(
(input.build_cpu == "x64" ? common.configure_args_64bit
: "--openjdk-target=x86_64-linux-gnu"),
@@ -441,7 +441,7 @@ var getJibProfilesProfiles = function (input, common, data) {
"macosx-x64": {
target_os: "macosx",
target_cpu: "x64",
- dependencies: ["devkit", "gtest", "graphviz", "pandoc"],
+ dependencies: ["devkit", "gtest", "graphviz", "pandoc", "tidy"],
configure_args: concat(common.configure_args_64bit, "--with-zlib=system",
"--with-macosx-version-max=11.00.00",
"--enable-compatible-cds-alignment",
@@ -453,7 +453,7 @@ var getJibProfilesProfiles = function (input, common, data) {
"macosx-aarch64": {
target_os: "macosx",
target_cpu: "aarch64",
- dependencies: ["devkit", "gtest", "graphviz", "pandoc"],
+ dependencies: ["devkit", "gtest", "graphviz", "pandoc", "tidy"],
configure_args: concat(common.configure_args_64bit,
"--with-macosx-version-max=11.00.00"),
},
@@ -486,7 +486,7 @@ var getJibProfilesProfiles = function (input, common, data) {
"linux-aarch64": {
target_os: "linux",
target_cpu: "aarch64",
- dependencies: ["devkit", "gtest", "build_devkit", "graphviz", "pandoc"],
+ dependencies: ["devkit", "gtest", "build_devkit", "graphviz", "pandoc", "tidy"],
configure_args: [
"--with-zlib=system",
"--disable-dtrace",
@@ -957,7 +957,7 @@ var getJibProfilesProfiles = function (input, common, data) {
// Profiles used to run tests using Jib for internal dependencies.
var testedProfile = input.testedProfile;
- if (testedProfile == null) {
+ if (testedProfile == null || testedProfile == "docs") {
testedProfile = input.build_os + "-" + input.build_cpu;
}
var testedProfileJdk = testedProfile + ".jdk";
@@ -999,25 +999,38 @@ var getJibProfilesProfiles = function (input, common, data) {
testOnlyProfilesPrebuilt["run-test-prebuilt"]["dependencies"].push(testedProfile + ".jdk_symbols");
}
+ var testOnlyProfilesPrebuiltDocs = {
+ "run-test-prebuilt-docs": clone(testOnlyProfilesPrebuilt["run-test-prebuilt"])
+ };
+
+ testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].dependencies.push("docs.doc_api_spec", "tidy");
+ testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].environment["DOCS_JDK_IMAGE_DIR"]
+ = input.get("docs.doc_api_spec", "install_path");
+ testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].environment["TIDY"]
+ = input.get("tidy", "home_path") + "/bin/tidy";
+ testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].labels = "test-docs";
+
// If actually running the run-test-prebuilt profile, verify that the input
// variable is valid and if so, add the appropriate target_* values from
// the tested profile. Use testImageProfile value as backup.
- if (input.profile == "run-test-prebuilt") {
+ if (input.profile == "run-test-prebuilt" || input.profile == "run-test-prebuilt-docs") {
if (profiles[testedProfile] == null && profiles[testImageProfile] == null) {
error("testedProfile is not defined: " + testedProfile + " " + testImageProfile);
}
}
- if (profiles[testedProfile] != null) {
- testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_os"]
- = profiles[testedProfile]["target_os"];
- testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_cpu"]
- = profiles[testedProfile]["target_cpu"];
- } else if (profiles[testImageProfile] != null) {
- testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_os"]
- = profiles[testImageProfile]["target_os"];
- testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_cpu"]
- = profiles[testImageProfile]["target_cpu"];
+ function updateProfileTargets(profiles, testedProfile, testImageProfile, targetProfile, runTestProfile) {
+ var profileToCheck = profiles[testedProfile] || profiles[testImageProfile];
+
+ if (profileToCheck != null) {
+ targetProfile[runTestProfile]["target_os"] = profileToCheck["target_os"];
+ targetProfile[runTestProfile]["target_cpu"] = profileToCheck["target_cpu"];
+ }
}
+
+ updateProfileTargets(profiles, testedProfile, testImageProfile, testOnlyProfilesPrebuilt, "run-test-prebuilt");
+ updateProfileTargets(profiles, testedProfile, testImageProfile, testOnlyProfilesPrebuiltDocs, "run-test-prebuilt-docs");
+
+ profiles = concatObjects(profiles, testOnlyProfilesPrebuiltDocs);
profiles = concatObjects(profiles, testOnlyProfilesPrebuilt);
// On macosx add the devkit bin dir to the path in all the run-test profiles.
@@ -1067,6 +1080,8 @@ var getJibProfilesProfiles = function (input, common, data) {
}
profiles["run-test-prebuilt"] = concatObjects(profiles["run-test-prebuilt"],
runTestPrebuiltSrcFullExtra);
+ profiles["run-test-prebuilt-docs"] = concatObjects(profiles["run-test-prebuilt-docs"],
+ runTestPrebuiltSrcFullExtra);
}
// Generate the missing platform attributes
@@ -1275,6 +1290,14 @@ var getJibProfilesDependencies = function (input, common) {
ext: "tar.gz",
revision: "3.4.2+1.0"
},
+ tidy: {
+ organization: common.organization,
+ ext: "tar.gz",
+ revision: "5.9.20+1",
+ environment_path: input.get("tidy", "home_path") + "/bin/tidy",
+ configure_args: "TIDY=" + input.get("tidy", "home_path") + "/bin/tidy",
+ module: "tidy-html-" + (input.target_os === "macosx" ? input.target_os : input.target_platform),
+ },
};
return dependencies;
diff --git a/make/conf/module-loader-map.conf b/make/conf/module-loader-map.conf
index e904031186d..b628bfbf2da 100644
--- a/make/conf/module-loader-map.conf
+++ b/make/conf/module-loader-map.conf
@@ -62,6 +62,7 @@ UPGRADEABLE_PLATFORM_MODULES= \
java.compiler \
jdk.graal.compiler \
jdk.graal.compiler.management \
+ jdk.jsobject \
#
PLATFORM_MODULES= \
@@ -79,7 +80,6 @@ PLATFORM_MODULES= \
jdk.crypto.cryptoki \
jdk.dynalink \
jdk.httpserver \
- jdk.jsobject \
jdk.localedata \
jdk.naming.dns \
jdk.security.auth \
@@ -94,48 +94,26 @@ PLATFORM_MODULES_windows= \
NATIVE_ACCESS_MODULES= \
java.base \
- java.datatransfer \
java.desktop \
java.instrument \
- java.logging \
java.management \
- java.management.rmi \
- java.naming \
- java.net.http \
java.prefs \
java.rmi \
- java.scripting \
- java.se \
java.security.jgss \
- java.security.sasl \
java.smartcardio \
- java.sql \
- java.sql.rowset \
- java.transaction.xa \
- java.xml \
- java.xml.crypto \
jdk.accessibility \
- jdk.charsets \
+ jdk.attach \
jdk.crypto.cryptoki \
- jdk.dynalink \
- jdk.httpserver \
- jdk.incubator.vector \
+ jdk.crypto.mscapi \
+ jdk.hotspot.agent \
jdk.internal.le \
jdk.internal.vm.ci \
+ jdk.jdi \
jdk.jfr \
- jdk.jsobject \
- jdk.localedata \
+ jdk.jpackage \
jdk.management \
jdk.management.agent \
- jdk.management.jfr \
- jdk.naming.dns \
- jdk.naming.rmi \
jdk.net \
- jdk.nio.mapmode \
jdk.sctp \
jdk.security.auth \
- jdk.security.jgss \
- jdk.unsupported \
- jdk.xml.dom \
- jdk.zipfs \
#
diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf
index 1d47c2cddd0..055f9ca8866 100644
--- a/make/conf/version-numbers.conf
+++ b/make/conf/version-numbers.conf
@@ -37,6 +37,6 @@ DEFAULT_VERSION_DATE=2025-03-18
DEFAULT_VERSION_CLASSFILE_MAJOR=68 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
DEFAULT_VERSION_CLASSFILE_MINOR=0
DEFAULT_VERSION_DOCS_API_SINCE=11
-DEFAULT_ACCEPTABLE_BOOT_VERSIONS="22 23 24"
+DEFAULT_ACCEPTABLE_BOOT_VERSIONS="23 24"
DEFAULT_JDK_SOURCE_TARGET_VERSION=24
DEFAULT_PROMOTED_VERSION_PRE=ea
diff --git a/make/devkit/Makefile b/make/devkit/Makefile
index c85a7c21d29..9c498807a54 100644
--- a/make/devkit/Makefile
+++ b/make/devkit/Makefile
@@ -81,7 +81,7 @@ $(info target_platforms $(target_platforms))
all compile : $(platforms)
-ifeq (,$(SKIP_ME))
+ifeq ($(SKIP_ME), )
$(foreach p,$(filter-out $(me),$(platforms)),$(eval $(p) : $$(me)))
endif
diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk
index 5c29ee4db75..300501f5f35 100644
--- a/make/devkit/Tools.gmk
+++ b/make/devkit/Tools.gmk
@@ -23,7 +23,7 @@
# questions.
#
-##########################################################################################
+################################################################################
#
# Workhorse makefile for creating ONE cross compiler
# Needs either to be from BUILD -> BUILD OR have
@@ -92,7 +92,7 @@ else
$(error Unknown base OS $(BASE_OS))
endif
-##########################################################################################
+################################################################################
# Define external dependencies
# Latest that could be made to work.
@@ -223,7 +223,7 @@ RPM_LIST := \
systemtap-sdt-devel \
#
-##########################################################################################
+################################################################################
# Define common directories and files
# Ensure we have 32-bit libs also for x64. We enable mixed-mode.
@@ -258,7 +258,7 @@ download-rpms:
wget -r -np -nd $(patsubst %, -A "*%*.rpm", $(RPM_LIST)) $(BASE_URL)
endif
-##########################################################################################
+################################################################################
# Unpack source packages
# Generate downloading + unpacking of sources.
@@ -285,7 +285,7 @@ endef
# Download and unpack all source packages
$(foreach p,GCC BINUTILS CCACHE MPFR GMP MPC GDB,$(eval $(call Download,$(p))))
-##########################################################################################
+################################################################################
# Unpack RPMS
RPM_ARCHS := $(ARCH) noarch
@@ -324,7 +324,7 @@ endef
$(foreach p,$(RPM_FILE_LIST),$(eval $(call unrpm,$(p))))
-##########################################################################################
+################################################################################
# Note: MUST create a /usr/lib even if not really needed.
# gcc will use a path relative to it to resolve lib64. (x86_64).
@@ -344,7 +344,7 @@ $(libs) : $(rpms)
@mkdir -p $(SYSROOT)/usr/lib
@touch $@
-##########################################################################################
+################################################################################
# Create links for ffi header files so that they become visible by default when using the
# devkit.
ifeq ($(ARCH), x86_64)
@@ -357,12 +357,12 @@ ifeq ($(ARCH), x86_64)
SYSROOT_LINKS += $(SYSROOT)/usr/include/ffi.h $(SYSROOT)/usr/include/ffitarget.h
endif
-##########################################################################################
+################################################################################
# Define marker files for each source package to be compiled
$(foreach t,binutils mpfr gmp mpc gcc ccache gdb,$(eval $(t) = $(TARGETDIR)/$($(t)_ver).done))
-##########################################################################################
+################################################################################
# Default base config
CONFIG = --target=$(TARGET) \
@@ -390,7 +390,7 @@ endif
TOOLS ?= $(call declare_tools,_FOR_TARGET,$(TARGET)-)
-##########################################################################################
+################################################################################
# Create a TARGET bfd + libiberty only.
# Configure one or two times depending on mulitlib arch.
@@ -424,7 +424,7 @@ $(bfdmakes) : CONFIG = --target=$(TARGET) \
$(bfdmakes) : TOOLS = $(call declare_tools,_FOR_TARGET,$(TARGET)-) $(call declare_tools,,$(TARGET)-)
-##########################################################################################
+################################################################################
$(gcc) \
$(binutils) \
@@ -591,7 +591,7 @@ else
@echo 'done'
endif
-##########################################################################################
+################################################################################
# very straightforward. just build a ccache. it is only for host.
$(BUILDDIR)/$(ccache_ver)/Makefile \
: $(CCACHE_CFG)
@@ -606,7 +606,7 @@ $(BUILDDIR)/$(ccache_ver)/Makefile \
gccpatch = $(TARGETDIR)/gcc-patched
-##########################################################################################
+################################################################################
# For some reason cpp is not created as a target-compiler
ifeq ($(HOST),$(TARGET))
$(gccpatch) : $(gcc) link_libs
@@ -621,7 +621,7 @@ ifeq ($(HOST),$(TARGET))
@touch $@
@echo 'done'
- ##########################################################################################
+ ##############################################################################
# Ugly at best. Seems that when we compile host->host compiler, that are NOT
# the BUILD compiler, the result will not try searching for libs in package root.
# "Solve" this by create links from the target libdirs to where they are.
@@ -641,7 +641,7 @@ else
@echo 'done'
endif
-##########################################################################################
+################################################################################
# Build in two steps.
# make
# make install.
@@ -656,7 +656,7 @@ $(TARGETDIR)/%.done : $(BUILDDIR)/%/Makefile
@touch $@
@echo 'done'
-##########################################################################################
+################################################################################
$(PREFIX)/devkit.info:
@echo 'Creating devkit.info in the root of the kit'
@@ -670,7 +670,7 @@ $(PREFIX)/devkit.info:
echo 'DEVKIT_SYSROOT="$$DEVKIT_ROOT/$(TARGET)/sysroot"' >> $@
echo 'DEVKIT_EXTRA_PATH="$$DEVKIT_ROOT/bin"' >> $@
-##########################################################################################
+################################################################################
# Copy these makefiles into the root of the kit
$(PREFIX)/Makefile: ./Makefile
rm -rf $@
@@ -686,7 +686,7 @@ $(PREFIX)/Tars.gmk: ./Tars.gmk
THESE_MAKEFILES := $(PREFIX)/Makefile $(PREFIX)/Tools.gmk $(PREFIX)/Tars.gmk
-##########################################################################################
+################################################################################
ifeq ($(TARGET), $(HOST))
# To build with dtrace support, the build needs access to the dtrace executable from the
@@ -706,7 +706,7 @@ ifeq ($(TARGET), $(HOST))
ld.gold nm objcopy objdump ranlib readelf size strings strip)
endif
-##########################################################################################
+################################################################################
bfdlib : $(bfdlib)
binutils : $(binutils)
diff --git a/make/devkit/createAutoconfBundle.sh b/make/devkit/createAutoconfBundle.sh
index 861a0a47242..7363b9cd8a7 100644
--- a/make/devkit/createAutoconfBundle.sh
+++ b/make/devkit/createAutoconfBundle.sh
@@ -1,6 +1,6 @@
#!/bin/bash -e
#
-# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -25,50 +25,70 @@
#
# Create a bundle in the current directory, containing what's needed to run
-# the 'autoconf' program by the OpenJDK build.
+# the 'autoconf' program by the OpenJDK build. To override TARGET_PLATFORM
+# just set the variable before running this script.
# Autoconf depends on m4, so download and build that first.
AUTOCONF_VERSION=2.69
M4_VERSION=1.4.18
PACKAGE_VERSION=1.0.1
-TARGET_PLATFORM=linux_x86
+case `uname -s` in
+ Darwin)
+ os=macosx
+ ;;
+ Linux)
+ os=linux
+ ;;
+ CYGWIN*)
+ os=cygwin
+ ;;
+esac
+case `uname -m` in
+ arm64|aarch64)
+ arch=aarch64
+ ;;
+ amd64|x86_64|x64)
+ arch=x64
+ ;;
+esac
+TARGET_PLATFORM=${TARGET_PLATFORM:="${os}_${arch}"}
+
MODULE_NAME=autoconf-$TARGET_PLATFORM-$AUTOCONF_VERSION+$PACKAGE_VERSION
BUNDLE_NAME=$MODULE_NAME.tar.gz
-TMPDIR=`mktemp -d -t autoconfbundle-XXXX`
-trap "rm -rf \"$TMPDIR\"" EXIT
+SCRIPT_DIR="$(cd "$(dirname $0)" > /dev/null && pwd)"
+OUTPUT_ROOT="${SCRIPT_DIR}/../../build/autoconf"
-ORIG_DIR=`pwd`
-cd $TMPDIR
-OUTPUT_DIR=$TMPDIR/$MODULE_NAME
-mkdir -p $OUTPUT_DIR/usr
+cd $OUTPUT_ROOT
+IMAGE_DIR=$OUTPUT_ROOT/$MODULE_NAME
+mkdir -p $IMAGE_DIR/usr
# Download and build m4
if test "x$TARGET_PLATFORM" = xcygwin_x64; then
# On cygwin 64-bit, just copy the cygwin .exe file
- mkdir -p $OUTPUT_DIR/usr/bin
- cp /usr/bin/m4 $OUTPUT_DIR/usr/bin
+ mkdir -p $IMAGE_DIR/usr/bin
+ cp /usr/bin/m4 $IMAGE_DIR/usr/bin
elif test "x$TARGET_PLATFORM" = xcygwin_x86; then
# On cygwin 32-bit, just copy the cygwin .exe file
- mkdir -p $OUTPUT_DIR/usr/bin
- cp /usr/bin/m4 $OUTPUT_DIR/usr/bin
+ mkdir -p $IMAGE_DIR/usr/bin
+ cp /usr/bin/m4 $IMAGE_DIR/usr/bin
elif test "x$TARGET_PLATFORM" = xlinux_x64; then
M4_VERSION=1.4.13-5
wget http://yum.oracle.com/repo/OracleLinux/OL6/latest/x86_64/getPackage/m4-$M4_VERSION.el6.x86_64.rpm
- cd $OUTPUT_DIR
- rpm2cpio ../m4-$M4_VERSION.el6.x86_64.rpm | cpio -d -i
+ cd $IMAGE_DIR
+ rpm2cpio $OUTPUT_ROOT/m4-$M4_VERSION.el6.x86_64.rpm | cpio -d -i
elif test "x$TARGET_PLATFORM" = xlinux_x86; then
M4_VERSION=1.4.13-5
wget http://yum.oracle.com/repo/OracleLinux/OL6/latest/i386/getPackage/m4-$M4_VERSION.el6.i686.rpm
- cd $OUTPUT_DIR
- rpm2cpio ../m4-$M4_VERSION.el6.i686.rpm | cpio -d -i
+ cd $IMAGE_DIR
+ rpm2cpio $OUTPUT_ROOT/m4-$M4_VERSION.el6.i686.rpm | cpio -d -i
else
wget https://ftp.gnu.org/gnu/m4/m4-$M4_VERSION.tar.gz
tar xzf m4-$M4_VERSION.tar.gz
cd m4-$M4_VERSION
- ./configure --prefix=$OUTPUT_DIR/usr
+ ./configure --prefix=$IMAGE_DIR/usr CFLAGS="-w -Wno-everything"
make
make install
cd ..
@@ -79,15 +99,14 @@ fi
wget https://ftp.gnu.org/gnu/autoconf/autoconf-$AUTOCONF_VERSION.tar.gz
tar xzf autoconf-$AUTOCONF_VERSION.tar.gz
cd autoconf-$AUTOCONF_VERSION
-./configure --prefix=$OUTPUT_DIR/usr M4=$OUTPUT_DIR/usr/bin/m4
+./configure --prefix=$IMAGE_DIR/usr M4=$IMAGE_DIR/usr/bin/m4
make
make install
cd ..
-perl -pi -e "s!$OUTPUT_DIR/!./!" $OUTPUT_DIR/usr/bin/auto* $OUTPUT_DIR/usr/share/autoconf/autom4te.cfg
-cp $OUTPUT_DIR/usr/share/autoconf/autom4te.cfg $OUTPUT_DIR/autom4te.cfg
+perl -pi -e "s!$IMAGE_DIR/!./!" $IMAGE_DIR/usr/bin/auto* $IMAGE_DIR/usr/share/autoconf/autom4te.cfg
-cat > $OUTPUT_DIR/autoconf << EOF
+cat > $IMAGE_DIR/autoconf << EOF
#!/bin/bash
# Get an absolute path to this script
this_script_dir=\`dirname \$0\`
@@ -100,17 +119,10 @@ export AUTOHEADER="\$this_script_dir/usr/bin/autoheader"
export AC_MACRODIR="\$this_script_dir/usr/share/autoconf"
export autom4te_perllibdir="\$this_script_dir/usr/share/autoconf"
-autom4te_cfg=\$this_script_dir/usr/share/autoconf/autom4te.cfg
-cp \$this_script_dir/autom4te.cfg \$autom4te_cfg
-
-echo 'begin-language: "M4sugar"' >> \$autom4te_cfg
-echo "args: --prepend-include '"\$this_script_dir/usr/share/autoconf"'" >> \$autom4te_cfg
-echo 'end-language: "M4sugar"' >> \$autom4te_cfg
+PREPEND_INCLUDE="--prepend-include \$this_script_dir/usr/share/autoconf"
-exec \$this_script_dir/usr/bin/autoconf "\$@"
+exec \$this_script_dir/usr/bin/autoconf \$PREPEND_INCLUDE "\$@"
EOF
-chmod +x $OUTPUT_DIR/autoconf
-cd $OUTPUT_DIR
-tar -cvzf ../$BUNDLE_NAME *
-cd ..
-cp $BUNDLE_NAME "$ORIG_DIR"
+chmod +x $IMAGE_DIR/autoconf
+cd $IMAGE_DIR
+tar -cvzf $OUTPUT_ROOT/$BUNDLE_NAME *
diff --git a/make/devkit/createTidyBundle.sh b/make/devkit/createTidyBundle.sh
new file mode 100644
index 00000000000..b3f8e6bf078
--- /dev/null
+++ b/make/devkit/createTidyBundle.sh
@@ -0,0 +1,86 @@
+#!/bin/bash
+#
+# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# Creates a tidy bundle in the build directory. A dependency that can be
+# used to validate and correct HTML.
+
+# wget, cmake and gcc are required to build tidy.
+
+set -e
+
+GITHUB_USER="htacg"
+REPO_NAME="tidy-html5"
+COMMIT_HASH="d08ddc2860aa95ba8e301343a30837f157977cba"
+SCRIPT_DIR="$(cd "$(dirname $0)" > /dev/null && pwd)"
+INSTALL_PREFIX="${SCRIPT_DIR}/../../build/tidy/tidy/"
+BUILD_DIR="build/cmake"
+
+OS_NAME=$(uname -s)
+OS_ARCH=$(uname -m)
+
+DOWNLOAD_URL="https://github.com/$GITHUB_USER/$REPO_NAME/archive/$COMMIT_HASH.tar.gz"
+OUTPUT_FILE="$REPO_NAME-$COMMIT_HASH.tar.gz"
+
+wget "$DOWNLOAD_URL" -O "$OUTPUT_FILE"
+
+tar -xzf "$OUTPUT_FILE"
+rm -rf "$OUTPUT_FILE"
+
+SRC_DIR="$REPO_NAME-$COMMIT_HASH"
+
+mkdir -p "$SRC_DIR/$BUILD_DIR"
+cd "$SRC_DIR/$BUILD_DIR"
+
+case $OS_NAME in
+ Linux|Darwin)
+ echo "Building Tidy HTML5 for Unix-like platform ($OS_NAME)..."
+
+ CMAKE_ARCH_OPTIONS=""
+ if [ "$OS_NAME" == "Darwin" ]; then
+ if [[ "$OS_ARCH" == "arm64" || "$OS_ARCH" == "x86_64" ]]; then
+ CMAKE_ARCH_OPTIONS="-DCMAKE_OSX_ARCHITECTURES=x86_64;arm64"
+ fi
+ fi
+
+ cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" $CMAKE_ARCH_OPTIONS
+ make install
+ ;;
+
+ *)
+ echo "Unsupported OS: $OS_NAME"
+ exit 1
+ ;;
+esac
+
+cd "$SCRIPT_DIR"
+rm -rf "$SRC_DIR"
+
+cd "$INSTALL_PREFIX.."
+PACKAGED_FILE="tidy-html5.tar.gz"
+
+tar -czvf "$PACKAGED_FILE" -C "$INSTALL_PREFIX.." tidy
+
+echo "Created $INSTALL_PREFIX..$PACKAGED_FILE"
diff --git a/make/hotspot/CopyToExplodedJdk.gmk b/make/hotspot/CopyToExplodedJdk.gmk
index 4462af0dc3b..280224de19e 100644
--- a/make/hotspot/CopyToExplodedJdk.gmk
+++ b/make/hotspot/CopyToExplodedJdk.gmk
@@ -37,7 +37,8 @@ ifeq ($(call isTargetOs, windows), true)
$(eval $(call SetupCopyFiles, COPY_LIBS_LIB, \
SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base, \
DEST := $(JDK_OUTPUTDIR)/lib, \
- FILES := $(filter %.lib, $(LIB_TARGETS))))
+ FILES := $(filter %.lib, $(LIB_TARGETS)), \
+ ))
TARGETS += $(COPY_LIBS_BIN) $(COPY_LIBS_LIB)
else
diff --git a/make/hotspot/gensrc/GensrcAdlc.gmk b/make/hotspot/gensrc/GensrcAdlc.gmk
index 4c37fd1ebe6..ddb2c3e33e5 100644
--- a/make/hotspot/gensrc/GensrcAdlc.gmk
+++ b/make/hotspot/gensrc/GensrcAdlc.gmk
@@ -200,15 +200,22 @@ ifeq ($(call check-jvm-feature, compiler2), true)
)))
endif
+ ifeq ($(call check-jvm-feature, g1gc), true)
+ AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \
+ $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/g1/g1_$(HOTSPOT_TARGET_CPU).ad \
+ $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/g1/g1_$(HOTSPOT_TARGET_CPU_ARCH).ad \
+ )))
+ endif
+
SINGLE_AD_SRCFILE := $(ADLC_SUPPORT_DIR)/all-ad-src.ad
INSERT_FILENAME_AWK_SCRIPT := \
'{ \
- if (CUR_FN != FILENAME) { CUR_FN=FILENAME; NR_BASE=NR-1; need_lineno=1 } \
- if (need_lineno && $$0 !~ /\/\//) \
- { print "\n\n\#line " (NR-NR_BASE) " \"" FILENAME "\""; need_lineno=0 }; \
- print \
- }'
+ if (CUR_FN != FILENAME) { CUR_FN=FILENAME; NR_BASE=NR-1; need_lineno=1 } \
+ if (need_lineno && $$0 !~ /\/\//) \
+ { print "\n\n\#line " (NR-NR_BASE) " \"" FILENAME "\""; need_lineno=0 }; \
+ print \
+ }'
$(SINGLE_AD_SRCFILE): $(AD_SRC_FILES)
$(call LogInfo, Preprocessing adlc files $(^F))
diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk
index 696adb0c95f..8e55c9b669b 100644
--- a/make/hotspot/lib/CompileGtest.gmk
+++ b/make/hotspot/lib/CompileGtest.gmk
@@ -57,8 +57,9 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBGTEST, \
$(GTEST_FRAMEWORK_SRC)/googletest/src \
$(GTEST_FRAMEWORK_SRC)/googlemock/src, \
INCLUDE_FILES := gtest-all.cc gmock-all.cc, \
- DISABLED_WARNINGS_gcc := undef unused-result format-nonliteral maybe-uninitialized, \
- DISABLED_WARNINGS_clang := undef unused-result format-nonliteral, \
+ DISABLED_WARNINGS_gcc := format-nonliteral maybe-uninitialized undef \
+ unused-result zero-as-null-pointer-constant, \
+ DISABLED_WARNINGS_clang := format-nonliteral undef unused-result, \
DEFAULT_CFLAGS := false, \
CFLAGS := $(JVM_CFLAGS) \
-I$(GTEST_FRAMEWORK_SRC)/googletest \
@@ -94,11 +95,12 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBJVM, \
CFLAGS := $(JVM_CFLAGS) \
-I$(GTEST_FRAMEWORK_SRC)/googletest/include \
-I$(GTEST_FRAMEWORK_SRC)/googlemock/include \
- $(addprefix -I,$(GTEST_TEST_SRC)), \
+ $(addprefix -I, $(GTEST_TEST_SRC)), \
CFLAGS_windows := -EHsc, \
CFLAGS_macosx := -DGTEST_OS_MAC=1, \
DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc) \
undef stringop-overflow, \
+ DISABLED_WARNINGS_gcc_test_metaspace_misc.cpp := unused-const-variable, \
DISABLED_WARNINGS_gcc_test_threadCpuLoad.cpp := address, \
DISABLED_WARNINGS_clang := $(DISABLED_WARNINGS_clang) \
undef switch format-nonliteral tautological-undefined-compare \
diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk
index dff7a159ae5..49a96ec3273 100644
--- a/make/hotspot/lib/CompileJvm.gmk
+++ b/make/hotspot/lib/CompileJvm.gmk
@@ -92,10 +92,12 @@ CFLAGS_VM_VERSION := \
DISABLED_WARNINGS_gcc := array-bounds comment delete-non-virtual-dtor \
empty-body implicit-fallthrough int-in-bool-context \
maybe-uninitialized missing-field-initializers \
- shift-negative-value unknown-pragmas
+ shift-negative-value unknown-pragmas unused-but-set-variable \
+ unused-local-typedefs unused-variable
-DISABLED_WARNINGS_clang := sometimes-uninitialized \
- missing-braces delete-non-abstract-non-virtual-dtor unknown-pragmas
+DISABLED_WARNINGS_clang := delete-non-abstract-non-virtual-dtor missing-braces \
+ sometimes-uninitialized unknown-pragmas unused-but-set-variable \
+ unused-function unused-local-typedef unused-private-field unused-variable
ifneq ($(DEBUG_LEVEL), release)
# Assert macro gives warning
@@ -177,15 +179,27 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \
arguments.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \
DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc), \
DISABLED_WARNINGS_gcc_ad_$(HOTSPOT_TARGET_CPU_ARCH).cpp := nonnull, \
+ DISABLED_WARNINGS_gcc_bytecodeInterpreter.cpp := unused-label, \
+ DISABLED_WARNINGS_gcc_c1_Runtime1_aarch64.cpp := unused-const-variable, \
DISABLED_WARNINGS_gcc_cgroupV1Subsystem_linux.cpp := address, \
DISABLED_WARNINGS_gcc_cgroupV2Subsystem_linux.cpp := address, \
+ DISABLED_WARNINGS_gcc_g1FreeIdSet.cpp := unused-const-variable, \
DISABLED_WARNINGS_gcc_handshake.cpp := stringop-overflow, \
DISABLED_WARNINGS_gcc_interp_masm_x86.cpp := uninitialized, \
+ DISABLED_WARNINGS_gcc_javaClasses.cpp := unused-const-variable, \
+ DISABLED_WARNINGS_gcc_jfrChunkWriter.cpp := unused-const-variable, \
+ DISABLED_WARNINGS_gcc_jfrMemorySizer.cpp := unused-const-variable, \
+ DISABLED_WARNINGS_gcc_jfrTraceIdKlassQueue.cpp := unused-const-variable, \
DISABLED_WARNINGS_gcc_jvmciCodeInstaller.cpp := stringop-overflow, \
+ DISABLED_WARNINGS_gcc_jvmFlag.cpp := unused-const-variable, \
DISABLED_WARNINGS_gcc_jvmtiTagMap.cpp := stringop-overflow, \
+ DISABLED_WARNINGS_gcc_macroAssembler_ppc_sha.cpp := unused-const-variable, \
DISABLED_WARNINGS_gcc_postaloc.cpp := address, \
DISABLED_WARNINGS_gcc_shenandoahLock.cpp := stringop-overflow, \
+ DISABLED_WARNINGS_gcc_stubGenerator_s390.cpp := unused-const-variable, \
DISABLED_WARNINGS_gcc_synchronizer.cpp := stringop-overflow, \
+ DISABLED_WARNINGS_gcc_templateInterpreterGenerator_x86.cpp := unused-const-variable, \
+ DISABLED_WARNINGS_gcc_xGlobals_ppc.cpp := unused-const-variable, \
DISABLED_WARNINGS_clang := $(DISABLED_WARNINGS_clang), \
DISABLED_WARNINGS_clang_arguments.cpp := missing-field-initializers, \
DISABLED_WARNINGS_clang_codeBuffer.cpp := tautological-undefined-compare, \
@@ -268,7 +282,7 @@ ifneq ($(GENERATE_COMPILE_COMMANDS_ONLY), true)
ifeq ($(JVM_VARIANT), $(JVM_VARIANT_MAIN))
$(eval $(call SetupCopyFiles, COPY_JVM_LIB, \
DEST := $(LIB_OUTPUTDIR), \
- FILES :=$(BUILD_LIBJVM_IMPORT_LIBRARY), \
+ FILES := $(BUILD_LIBJVM_IMPORT_LIBRARY), \
))
TARGETS += $(COPY_JVM_LIB)
endif
diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk
index a0136870d8c..c4c030810fc 100644
--- a/make/hotspot/lib/JvmFeatures.gmk
+++ b/make/hotspot/lib/JvmFeatures.gmk
@@ -47,9 +47,10 @@ endif
ifeq ($(call check-jvm-feature, zero), true)
JVM_EXCLUDES += opto libadt
JVM_EXCLUDE_PATTERNS += c1_ c1/ c2_ runtime_ /c2/
- JVM_EXCLUDE_FILES += templateInterpreter.cpp templateInterpreterGenerator.cpp \
- bcEscapeAnalyzer.cpp ciTypeFlow.cpp
- JVM_CFLAGS_FEATURES += -DZERO -DZERO_LIBARCH='"$(OPENJDK_TARGET_CPU_LEGACY_LIB)"' $(LIBFFI_CFLAGS)
+ JVM_EXCLUDE_FILES += templateInterpreter.cpp \
+ templateInterpreterGenerator.cpp bcEscapeAnalyzer.cpp ciTypeFlow.cpp
+ JVM_CFLAGS_FEATURES += -DZERO \
+ -DZERO_LIBARCH='"$(OPENJDK_TARGET_CPU_LEGACY_LIB)"' $(LIBFFI_CFLAGS)
JVM_LIBS_FEATURES += $(LIBFFI_LIBS)
ifeq ($(ENABLE_LIBFFI_BUNDLING), true)
JVM_LDFLAGS_FEATURES += $(call SET_EXECUTABLE_ORIGIN,/..)
@@ -69,7 +70,8 @@ endif
ifeq ($(call check-jvm-feature, minimal), true)
JVM_CFLAGS_FEATURES += -DMINIMAL_JVM -DVMTYPE=\"Minimal\"
ifeq ($(call isTargetOs, linux), true)
- # Override the default -g with a more liberal strip policy for the minimal JVM
+ # Override the default -g with a more liberal strip policy for the
+ # minimal JVM
JVM_STRIPFLAGS := --strip-unneeded
endif
endif
@@ -80,11 +82,14 @@ endif
ifneq ($(call check-jvm-feature, jvmti), true)
JVM_CFLAGS_FEATURES += -DINCLUDE_JVMTI=0
- JVM_EXCLUDE_FILES += jvmtiGetLoadedClasses.cpp jvmtiThreadState.cpp jvmtiExtensions.cpp \
- jvmtiImpl.cpp jvmtiManageCapabilities.cpp jvmtiRawMonitor.cpp jvmtiUtil.cpp jvmtiTrace.cpp \
- jvmtiCodeBlobEvents.cpp jvmtiEnv.cpp jvmtiRedefineClasses.cpp jvmtiEnvBase.cpp jvmtiEnvThreadState.cpp \
- jvmtiTagMap.cpp jvmtiEventController.cpp evmCompat.cpp jvmtiEnter.xsl jvmtiExport.cpp \
- jvmtiClassFileReconstituter.cpp jvmtiTagMapTable.cpp jvmtiAgent.cpp jvmtiAgentList.cpp jfrJvmtiAgent.cpp
+ JVM_EXCLUDE_FILES += jvmtiGetLoadedClasses.cpp jvmtiThreadState.cpp \
+ jvmtiExtensions.cpp jvmtiImpl.cpp jvmtiManageCapabilities.cpp \
+ jvmtiRawMonitor.cpp jvmtiUtil.cpp jvmtiTrace.cpp jvmtiCodeBlobEvents.cpp \
+ jvmtiEnv.cpp jvmtiRedefineClasses.cpp jvmtiEnvBase.cpp \
+ jvmtiEnvThreadState.cpp jvmtiTagMap.cpp jvmtiEventController.cpp \
+ evmCompat.cpp jvmtiEnter.xsl jvmtiExport.cpp \
+ jvmtiClassFileReconstituter.cpp jvmtiTagMapTable.cpp jvmtiAgent.cpp \
+ jvmtiAgentList.cpp jfrJvmtiAgent.cpp
endif
ifneq ($(call check-jvm-feature, jvmci), true)
@@ -166,8 +171,10 @@ ifeq ($(call check-jvm-feature, link-time-opt), true)
# later on if desired
JVM_OPTIMIZATION := HIGHEST_JVM
ifeq ($(call isCompiler, gcc), true)
- JVM_CFLAGS_FEATURES += -flto=auto -fuse-linker-plugin -fno-strict-aliasing -fno-fat-lto-objects
- JVM_LDFLAGS_FEATURES += $(CXX_O_FLAG_HIGHEST_JVM) -flto=auto -fuse-linker-plugin -fno-strict-aliasing
+ JVM_CFLAGS_FEATURES += -flto=auto -fuse-linker-plugin -fno-strict-aliasing \
+ -fno-fat-lto-objects
+ JVM_LDFLAGS_FEATURES += $(CXX_O_FLAG_HIGHEST_JVM) -flto=auto \
+ -fuse-linker-plugin -fno-strict-aliasing
else ifeq ($(call isCompiler, microsoft), true)
JVM_CFLAGS_FEATURES += -GL
JVM_LDFLAGS_FEATURES += -LTCG:INCREMENTAL
diff --git a/make/hotspot/lib/JvmOverrideFiles.gmk b/make/hotspot/lib/JvmOverrideFiles.gmk
index 92e0f9e861e..63169b4d672 100644
--- a/make/hotspot/lib/JvmOverrideFiles.gmk
+++ b/make/hotspot/lib/JvmOverrideFiles.gmk
@@ -124,7 +124,7 @@ else ifeq ($(call isTargetOs, aix), true)
# mode, so don't optimize sharedRuntimeTrig.cpp at all.
BUILD_LIBJVM_sharedRuntimeTrig.cpp_CXXFLAGS := $(CXX_O_FLAG_NONE)
- ifneq ($(DEBUG_LEVEL),slowdebug)
+ ifneq ($(DEBUG_LEVEL), slowdebug)
# Compiling jvmtiEnterTrace.cpp with full optimization needs more than 30min
# (mostly because of '-qhot=level=1' and the more than 1300 'log_trace' calls
# which cause a lot of template expansion).
diff --git a/make/ide/eclipse/CreateWorkspace.gmk b/make/ide/eclipse/CreateWorkspace.gmk
index 2849303d570..793377ec51e 100644
--- a/make/ide/eclipse/CreateWorkspace.gmk
+++ b/make/ide/eclipse/CreateWorkspace.gmk
@@ -55,7 +55,7 @@ FindModuleNativeDirs = \
# Taken from JdkNativeCompilation.gmk
FindJavaHeaderDir = \
- $(if $(strip $1),$(wildcard $(SUPPORT_OUTPUTDIR)/headers/$(strip $1)))
+ $(if $(strip $1), $(wildcard $(SUPPORT_OUTPUTDIR)/headers/$(strip $1)))
JAVA_DIRS := $(strip $(foreach module, $(call FindAllModules), \
$(patsubst $(TOPDIR)/%,%,$(filter-out $(OUTPUTDIR)%, \
@@ -112,7 +112,7 @@ define SetupEclipseWorkspaceBody
# Eclipse crashes when processing multiple module-info.java files
# This is an annoying bug that has not been fixed for some time now
- $1_CLASSPATH += $$(foreach src,$(JAVA_DIRS), \
+ $1_CLASSPATH += $$(foreach src, $(JAVA_DIRS), \
$$(NEWLINE))
$$(eval $$(call SetupTextFileProcessing, $1_CREATE_CLASSPATH_FILE, \
@@ -157,7 +157,7 @@ define SetupEclipseWorkspaceBody
$$(NEWLINE)
ifneq ($$(findstring $$($1_NATURE), NATIVE MIXED), )
- $1_NATIVE_SRCS += $$(foreach src,$(NATIVE_DIRS), \
+ $1_NATIVE_SRCS += $$(foreach src, $(NATIVE_DIRS), \
$$(NEWLINE))
endif
@@ -188,7 +188,7 @@ define SetupEclipseWorkspaceBody
$1_PLAIN_MAKE_TARGETS := update-build-docs docs gensrc gendata copy java \
launchers libs hotspot jdk product-images product-bundles all-images test-image clean
- $1_MATCHING_MAKE_TARGETS += $$(foreach name,$$($1_PLAIN_MAKE_TARGETS), \
+ $1_MATCHING_MAKE_TARGETS += $$(foreach name, $$($1_PLAIN_MAKE_TARGETS), \
\
$$($1_MAKE) \
-C $$(call FixPath, $(TOPDIR)) \
@@ -292,7 +292,7 @@ define SetupEclipseWorkspaceBody
endif
ifneq ($$(findstring $$($1_NATURE), JAVA MIXED), )
- $1_LINKED_RESOURCES += $$(foreach src,$(JAVA_DIRS), \
+ $1_LINKED_RESOURCES += $$(foreach src, $(JAVA_DIRS), \
\
$$(strip $$(src)) \
2 \
@@ -317,7 +317,7 @@ define SetupEclipseWorkspaceBody
endif
ifneq ($$(findstring $$($1_NATURE), NATIVE MIXED), )
- $1_LINKED_RESOURCES += $$(foreach src,$(NATIVE_DIRS), \
+ $1_LINKED_RESOURCES += $$(foreach src, $(NATIVE_DIRS), \
\
$$(strip $$(src)) \
2 \
diff --git a/make/ide/idea/jdk/idea.gmk b/make/ide/idea/jdk/idea.gmk
index 310b582591c..cc4d0a174cd 100644
--- a/make/ide/idea/jdk/idea.gmk
+++ b/make/ide/idea/jdk/idea.gmk
@@ -28,8 +28,8 @@ include make/MainSupport.gmk
.PHONY: idea
-ifeq ($(SPEC),)
- ifneq ($(words $(SPECS)),1)
+ifeq ($(SPEC), )
+ ifneq ($(words $(SPECS)), 1)
@echo "Error: Multiple build specification files found. Please select one explicitly."
@exit 2
endif
@@ -39,7 +39,7 @@ ifeq ($(SPEC),)
else #with SPEC
include make/common/Modules.gmk
- ifeq ($(MODULES),)
+ ifeq ($(MODULES), )
SEL_MODULES := $(call FindAllModules)
else
SEL_MODULES := $(MODULES)
@@ -47,7 +47,7 @@ else #with SPEC
idea:
$(ECHO) "SUPPORT=$(SUPPORT_OUTPUTDIR)" >> $(OUT)
- $(ECHO) "MODULE_ROOTS=\"$(foreach mod, $(SEL_MODULES), $(call FindModuleSrcDirs,$(mod)))\"" >> $(OUT)
+ $(ECHO) "MODULE_ROOTS=\"$(foreach mod, $(SEL_MODULES), $(call FindModuleSrcDirs, $(mod)))\"" >> $(OUT)
$(ECHO) "MODULE_NAMES=\"$(strip $(foreach mod, $(SEL_MODULES), $(mod)))\"" >> $(OUT)
$(ECHO) "SEL_MODULES=\"$(SEL_MODULES)\"" >> $(OUT)
$(ECHO) "BOOT_JDK=\"$(BOOT_JDK)\"" >> $(OUT)
diff --git a/make/ide/visualstudio/hotspot/CreateVSProject.gmk b/make/ide/visualstudio/hotspot/CreateVSProject.gmk
index cd093d3c6de..db48cdea9f7 100644
--- a/make/ide/visualstudio/hotspot/CreateVSProject.gmk
+++ b/make/ide/visualstudio/hotspot/CreateVSProject.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -80,10 +80,10 @@ ifeq ($(call isTargetOs, windows), true)
-ignorePath zero \
#
- ################################################################################
+ ##############################################################################
# Build the ProjectCreator java tool.
- TOOLS_OUTPUTDIR := $(HOTSPOT_OUTPUTDIR)/support/ide_classes
+ TOOLS_OUTPUTDIR := $(MAKESUPPORT_OUTPUTDIR)/ide/visualstudio
$(eval $(call SetupJavaCompilation, BUILD_PROJECT_CREATOR, \
TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \
diff --git a/make/ide/vscode/hotspot/CreateVSCodeProject.gmk b/make/ide/vscode/hotspot/CreateVSCodeProject.gmk
index bc56e878de6..5ceef111086 100644
--- a/make/ide/vscode/hotspot/CreateVSCodeProject.gmk
+++ b/make/ide/vscode/hotspot/CreateVSCodeProject.gmk
@@ -47,7 +47,7 @@ GetIndexerFragment = \
################################################################################
# Show indexer-specific notes if they exist, otherwise do nothing
################################################################################
-ifneq (,$(wildcard $(call GetIndexerFragment,notes)))
+ifneq ($(wildcard $(call GetIndexerFragment,notes)), )
ShowIndexerNotes = $(CAT) $(call GetIndexerFragment,notes)
else
ShowIndexerNotes =
@@ -66,7 +66,7 @@ endif
# Return an additional configuration fragment if the WORKSPACE_ROOT is different
# from TOPDIR.
################################################################################
-ifneq ($(WORKSPACE_ROOT),$(TOPDIR))
+ifneq ($(WORKSPACE_ROOT), $(TOPDIR))
GetExtraWorkspaceRoot = $(TOPDIR)/make/ide/vscode/hotspot/template-workspace-folder.txt
else
GetExtraWorkspaceRoot = /dev/null
diff --git a/make/ide/xcode/hotspot/CreateXcodeProject.gmk b/make/ide/xcode/hotspot/CreateXcodeProject.gmk
new file mode 100644
index 00000000000..db8f7f401ef
--- /dev/null
+++ b/make/ide/xcode/hotspot/CreateXcodeProject.gmk
@@ -0,0 +1,112 @@
+#
+# Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# This must be the first rule
+default: all
+
+include $(SPEC)
+include MakeBase.gmk
+include CopyFiles.gmk
+include Execute.gmk
+include JavaCompilation.gmk
+
+ifeq ($(call isTargetOs, macosx), true)
+ ##############################################################################
+ # Build the XcodeProjectMaker java tool.
+
+ PROJECT_MAKER_DIR := $(TOPDIR)/make/ide/xcode/hotspot
+ TOOLS_OUTPUTDIR := $(MAKESUPPORT_OUTPUTDIR)/ide/xcode
+ IDE_OUTPUTDIR := $(OUTPUTDIR)/xcode
+ PROJECT_FILE_NAME := hotspot.xcodeproj
+
+ COMPILE_COMMAND_FILE := $(OUTPUTDIR)/compile_commands.json
+ LINKER_FLAGS_FILE := $(MAKESUPPORT_OUTPUTDIR)/compile-commands/jvm-ldflags.txt
+
+ $(eval $(call SetupJavaCompilation, BUILD_PROJECT_CREATOR, \
+ TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \
+ SRC := $(PROJECT_MAKER_DIR)/src/classes, \
+ BIN := $(TOOLS_OUTPUTDIR), \
+ DISABLED_WARNINGS := rawtypes unchecked serial, \
+ ))
+
+ TARGETS += $(BUILD_PROJECT_CREATOR)
+
+ # Run the XcodeProjectMaker tool
+ PROJECT_CREATOR_TOOL := $(JAVA_SMALL) -cp $(TOOLS_OUTPUTDIR) XcodeProjectMaker
+
+ ifneq ($(findstring $(LOG_LEVEL), debug trace), )
+ XCODE_PROJ_DEBUG_OPTION := -d
+ endif
+
+ XCODE_PROJ_VARDEPS := $(WORKSPACE_ROOT) $(IDE_OUTPUTDIR) \
+ $(PROJECT_MAKER_DIR)/data $(COMPILE_COMMAND_FILE) $(LINKER_FLAGS_FILE)
+ XCODE_PROJ_VARDEPS_FILE := $(call DependOnVariable, XCODE_PROJ_VARDEPS, \
+ $(TOOLS_OUTPUTDIR)/xcodeproj.vardeps)
+
+ $(eval $(call SetupExecute, build_xcode_project, \
+ WARN := Generating Xcode project file, \
+ DEPS := $(BUILD_PROJECT_CREATOR) $(COMPILE_COMMAND_FILE) \
+ $(LINKER_FLAGS_FILE) $(XCODE_PROJ_VARDEPS_FILE), \
+ OUTPUT_DIR := $(TOOLS_OUTPUTDIR), \
+ COMMAND := $(PROJECT_CREATOR_TOOL) $(WORKSPACE_ROOT) $(IDE_OUTPUTDIR) \
+ $(PROJECT_MAKER_DIR)/data $(COMPILE_COMMAND_FILE) \
+ $(LINKER_FLAGS_FILE) $(XCODE_PROJ_DEBUG_OPTION), \
+ ))
+
+ TARGETS += $(build_xcode_project)
+
+ $(eval $(call SetupCopyFiles, copy_xcode_project, \
+ DEST := $(IDE_OUTPUTDIR), \
+ FILES := $(PROJECT_MAKER_DIR)/data/script_before.sh $(PROJECT_MAKER_DIR)/data/script_after.sh , \
+ MACRO := copy-and-chmod-executable, \
+ ))
+
+ TARGETS += $(copy_xcode_project)
+
+ $(eval $(call SetupExecute, open_xcode_project, \
+ INFO := Opening Xcode project file, \
+ DEPS := $(build_xcodeproject_TARGET) FORCE, \
+ OUTPUT_DIR := $(TOOLS_OUTPUTDIR), \
+ COMMAND := open $(IDE_OUTPUTDIR)/$(PROJECT_FILE_NAME), \
+ ))
+
+ TARGETS += $(open_xcode_project)
+
+ # Always call open without considering dependencies being up to date
+ FORCE:
+
+ build: $(build_xcode_project) $(copy_xcode_project)
+
+ open: $(open_xcode_project)
+
+ all: $(TARGETS)
+else
+ build:
+ open:
+ all:
+ $(info Xcode projects are only supported on macOS)
+endif
+
+.PHONY: default all build open
diff --git a/make/ide/xcode/hotspot/data/Breakpoints_v2.xcbkptlist.template b/make/ide/xcode/hotspot/data/Breakpoints_v2.xcbkptlist.template
new file mode 100644
index 00000000000..42f6c9a689a
--- /dev/null
+++ b/make/ide/xcode/hotspot/data/Breakpoints_v2.xcbkptlist.template
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/make/ide/xcode/hotspot/data/jvm.xcscheme.template b/make/ide/xcode/hotspot/data/jvm.xcscheme.template
new file mode 100644
index 00000000000..894d4ffc46f
--- /dev/null
+++ b/make/ide/xcode/hotspot/data/jvm.xcscheme.template
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/make/ide/xcode/hotspot/data/project.pbxproj.template b/make/ide/xcode/hotspot/data/project.pbxproj.template
new file mode 100644
index 00000000000..2af90477210
--- /dev/null
+++ b/make/ide/xcode/hotspot/data/project.pbxproj.template
@@ -0,0 +1,207 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 48;
+ objects = {
+
+/* Begin PBXBuildFile section */
+TEMPLATE_PBXBUILDFILE
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ D60000000000000000000003 /* script_before.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = script_before.sh; sourceTree = ""; };
+ D60000000000000000000002 /* script_after.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = script_after.sh; sourceTree = ""; };
+ D60000000000000000000006 /* libjvm.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libjvm.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+TEMPLATE_PBXFILEREFERENCE
+/* End PBXFileReference section */
+
+/* Begin PBXGroup section */
+ D60000000000000000000004 /* scripts */ = {
+ isa = PBXGroup;
+ children = (
+ D60000000000000000000003 /* script_before.sh */,
+ D60000000000000000000002 /* script_after.sh */,
+ );
+ name = scripts;
+ sourceTree = "";
+ };
+ D60000000000000000000005 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ D60000000000000000000006 /* libjvm.dylib */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ D60000000000000000000001 = {
+ isa = PBXGroup;
+ children = (
+ D60000000000000000000004 /* scripts */,
+TEMPLATE_GROUP_GENSRC /* gensrc */,
+TEMPLATE_GROUP_SRC /* src */,
+TEMPLATE_GROUP_TEST /* test */,
+ D60000000000000000000005 /* Products */,
+ );
+ sourceTree = "";
+ };
+TEMPLATE_GROUPS
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ D60000000000000000000000 /* jvm */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D6000000000000000000000F /* Build configuration list for PBXNativeTarget "jvm" */;
+ buildPhases = (
+ D60000000000000000000007 /* Run script_before */,
+ D60000000000000000000008 /* Sources */,
+ D6000000000000000000000A /* Run script_after */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = jvm;
+ productName = jvm;
+ productReference = D60000000000000000000006 /* libjvm.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ D60000000000000000000010 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0900;
+ ORGANIZATIONNAME = Oracle;
+ TargetAttributes = {
+ D60000000000000000000000 = {
+ CreatedOnToolsVersion = 9.0;
+ ProvisioningStyle = Automatic;
+ };
+ };
+ };
+ buildConfigurationList = D6000000000000000000000E /* Build configuration list for PBXProject "jvm" */;
+ compatibilityVersion = "Xcode 8.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = D60000000000000000000001;
+ productRefGroup = D60000000000000000000005 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ D60000000000000000000000 /* jvm */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ D60000000000000000000007 /* Run script_before */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run script_before";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "cd $PROJECT_DIR;\ntime ./script_before.sh;\n";
+ };
+ D6000000000000000000000A /* Run script_after */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run script_after";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "cd $PROJECT_DIR;\ntime ./script_after.sh;\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ D60000000000000000000008 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+TEMPLATE_PBXSOURCESSBUILDPHASE
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ D6000000000000000000000B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CODE_SIGN_IDENTITY = "-";
+ CONFIGURATION_BUILD_DIR = build/jdk/lib/server;
+ CONFIGURATION_TEMP_DIR = build;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ MTL_ENABLE_DEBUG_INFO = NO;
+ OBJROOT = build;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = macosx;
+ };
+ name = Release;
+ };
+ D6000000000000000000000D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
+ EXECUTABLE_PREFIX = lib;
+ FRAMEWORK_SEARCH_PATHS = (
+TEMPLATE_FRAMEWORK_SEARCH_PATHS
+ );
+ OTHER_CFLAGS = (
+TEMPLATE_OTHER_CFLAGS
+ );
+ OTHER_LDFLAGS = (
+TEMPLATE_OTHER_LDFLAGS
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SYMROOT = build/jdk/lib/server;
+ USER_HEADER_SEARCH_PATHS = (
+TEMPLATE_USER_HEADER_SEARCH_PATHS
+ );
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ D6000000000000000000000E /* Build configuration list for PBXProject "jvm" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D6000000000000000000000B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ D6000000000000000000000F /* Build configuration list for PBXNativeTarget "jvm" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D6000000000000000000000D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = D60000000000000000000010 /* Project object */;
+}
diff --git a/make/ide/xcode/hotspot/data/runJ2Demo.xcscheme.template b/make/ide/xcode/hotspot/data/runJ2Demo.xcscheme.template
new file mode 100644
index 00000000000..fc387753004
--- /dev/null
+++ b/make/ide/xcode/hotspot/data/runJ2Demo.xcscheme.template
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/make/ide/xcode/hotspot/data/script_after.sh b/make/ide/xcode/hotspot/data/script_after.sh
new file mode 100644
index 00000000000..8ce4507faf1
--- /dev/null
+++ b/make/ide/xcode/hotspot/data/script_after.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+echo "running script_after.sh"
+
+readonly JDK_LIB_PATH="build/jdk/lib/server/libjvm.dylib";
+
+if [ ! -f ${JDK_LIB_PATH} ] ; then
+{
+ echo ">>>>>>> Cannot find ${JDK_LIB_PATH}, the build failed!?";
+ exit 1;
+}
+fi
diff --git a/make/ide/xcode/hotspot/data/script_before.sh b/make/ide/xcode/hotspot/data/script_before.sh
new file mode 100644
index 00000000000..5ba7e62e428
--- /dev/null
+++ b/make/ide/xcode/hotspot/data/script_before.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+#
+# Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+echo "running script_before.sh"
+
+readonly JDK_BUILD_PATH="..";
+readonly JAVAC_LOCATE_PATTERN="images/jdk/bin/javac";
+readonly HOTSPOT_TOUCH_FILE="../../../src/hotspot/os/posix/jvm_posix.cpp";
+
+echo ">>>>>>> Making a copy of JDK ...";
+
+javac_file_array=( $(find ${JDK_BUILD_PATH} | grep ${JAVAC_LOCATE_PATTERN}) );
+javac_file=${javac_file_array[0]};
+if [ -z ${javac_file} ] ; then
+{
+ echo ">>>>>>> ERROR: could not locate ${JAVAC_LOCATE_PATTERN} (did you remember to do \"make images\"?)";
+ exit 1;
+}
+fi
+
+jdk_build_path=$(dirname $(dirname ${javac_file}));
+if [ ! -f "build/${JAVAC_LOCATE_PATTERN}" ] ; then
+{
+ echo ">>>>>>> Copying jdk over...";
+ rsync -a "${jdk_build_path}" "build/";
+}
+fi
+
+# the following files will be supplied by the Xcode build
+rm -rf "build/jdk/lib/server/libjvm.dylib";
+rm -rf "build/jdk/lib/server/libjvm.dylib.dSYM";
+
+echo ">>>>>>> DONE";
+
+echo ">>>>>>> Touching ${HOTSPOT_TOUCH_FILE} to force HotspotVM rebuilt";
+if [ ! -f ${HOTSPOT_TOUCH_FILE} ] ; then
+{
+ echo ">>>>>>> Cannot find ${HOTSPOT_TOUCH_FILE}";
+ exit 1;
+}
+fi
+touch ${HOTSPOT_TOUCH_FILE};
+
+echo ">>>>>>> DONE";
+
+echo ">>>>>>> Xcode should be building the HotspotVM now...";
diff --git a/make/ide/xcode/hotspot/src/classes/DiskFile.java b/make/ide/xcode/hotspot/src/classes/DiskFile.java
new file mode 100644
index 00000000000..bef90b427ae
--- /dev/null
+++ b/make/ide/xcode/hotspot/src/classes/DiskFile.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+public class DiskFile extends LinkedHashMap implements Comparable {
+ // xcode id ex: D50000000000000000000000
+ private static long xcodeIdCount = 0xF0000001;
+ private final Path path;
+ private final boolean directory;
+ private final String xcodeId;
+ private final String xcodeId2;
+ private Iterable compilerFlags;
+
+ public DiskFile(String path, boolean directory) {
+ this(stringToPath(path), directory);
+ }
+
+ private DiskFile(Path path, boolean directory) {
+ this.path = path;
+ this.directory = directory;
+ this.compilerFlags = null;
+ this.xcodeId = getNextXcodeId();
+ this.xcodeId2 = getNextXcodeId();
+ }
+
+ private static Path stringToPath(String string) {
+ if (string != null) {
+ return new File(string).toPath();
+ } else {
+ return null;
+ }
+ }
+
+ private static Path clipPath(Path path, String clip) {
+ return clipPath(path.toString(), clip);
+ }
+
+ private static Path clipPath(String path, String clip) {
+ String subpath = path;
+ if (path.contains(clip)) {
+ subpath = clip;
+ }
+ int index = path.indexOf(subpath);
+ return stringToPath(path.substring(index));
+ }
+
+ private String getNextXcodeId() {
+ String id = "D5FFFFFF" + Long.toHexString(xcodeIdCount).toUpperCase(Locale.ROOT);
+ xcodeIdCount++;
+
+ return id;
+ }
+
+ private String getPath() {
+ return this.path.toString();
+ }
+
+ public boolean isDirectory() {
+ return this.directory;
+ }
+
+ public void markAsCompiled(List compilerFlags) {
+ this.compilerFlags = compilerFlags;
+ }
+
+ private boolean isCompiled() {
+ return (this.compilerFlags != null);
+ }
+
+ public String getXcodeId() {
+ return this.xcodeId;
+ }
+
+ public String generatePbxSourcesBuildPhase() {
+ String string = "";
+ if (isCompiled()) {
+ String fileName = getFileName();
+ string += String.format(" %s /* %s in Sources */,\n", this.xcodeId2, fileName);
+ } else if (isDirectory()) {
+ for (Map.Entry entry : entrySet()) {
+ DiskFile file = entry.getValue();
+ string += file.generatePbxSourcesBuildPhase();
+ }
+ }
+ return string;
+ }
+
+ // D5FFFFFFFFFFFFFFF0006506 /* vm_version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5FFFFFFFFFFFFFFF0006505 /* vm_version.cpp */; settings = {COMPILER_FLAGS = HEREHERE; }; };
+ public String generatePbxBuildFile() {
+ String string = "";
+ if (isCompiled()) {
+ String flagsString = "";
+ for (String flag : this.compilerFlags) {
+ flagsString += flag.replace("\"", "\\\\\"") + " ";
+ }
+ String fileName = getFileName();
+ string += String.format(" %s /* %s in Sources */ = {isa = PBXBuildFile; fileRef = %s /* %s */; settings = {COMPILER_FLAGS = \"%s\"; }; };\n", this.xcodeId2, fileName, this.xcodeId, fileName, flagsString);
+ } else if (isDirectory()) {
+ for (Map.Entry entry : entrySet()) {
+ DiskFile file = entry.getValue();
+ string += file.generatePbxBuildFile();
+ }
+ }
+ return string;
+ }
+
+ public String generatePbxFileReference(String relativePathToRoot) {
+ String string = "";
+ if (!isDirectory()) {
+ String fileName = getFileName();
+ String suffix = getFileNameSuffix();
+ string += String.format(" %s /* %s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = %s%s; name = %s; path = \"%s%s\"; sourceTree = \"\"; };\n", this.xcodeId, fileName, fileName, suffix, fileName, relativePathToRoot, getPath());
+ } else if (isDirectory()) {
+ for (Map.Entry entry : entrySet()) {
+ DiskFile file = entry.getValue();
+ string += file.generatePbxFileReference(relativePathToRoot);
+ }
+ }
+ return string;
+ }
+
+ public String generatePbxGroup() {
+ String string = String.format(" %s /* %s */ = {\n isa = PBXGroup;\n children = (\n", this.xcodeId, getFileName());
+
+ Set sortedSet = new TreeSet<>(values());
+
+ for (DiskFile file : sortedSet) {
+ string += String.format(" %s /* %s */,\n", file.getXcodeId(), file.getFileName());
+ }
+ string += String.format(" );\n name = %s;\n sourceTree = \"\";\n };\n", getFileName());
+
+ for (DiskFile file : sortedSet) {
+ if (file.isDirectory()) {
+ string += file.generatePbxGroup();
+ }
+ }
+
+ return string;
+ }
+
+ private ArrayList getFiles(ArrayList array) {
+ for (Map.Entry entry : entrySet()) {
+ DiskFile file = entry.getValue();
+ if (file.isDirectory()) {
+ array.add(file);
+ array = file.getFiles(array);
+ } else {
+ array.add(file);
+ }
+ }
+ return array;
+ }
+
+ public ArrayList getFiles() {
+ return getFiles(new ArrayList<>());
+ }
+
+ public String getFilePath() {
+ return this.path.toString();
+ }
+
+ private String getFileName() {
+ Path fileName = this.path.getFileName();
+ if (fileName != null) {
+ return fileName.toString();
+ } else {
+ return this.path.toString();
+ }
+ }
+
+ private String getFileNameNoSuffix() {
+ String string;
+ Path fileName = this.path.getFileName();
+ if (fileName != null) {
+ string = fileName.toString();
+ int index = string.indexOf('.');
+ if (index >= 0) {
+ string = string.substring(0, index);
+ }
+ } else {
+ string = this.path.toString();
+ }
+ return string;
+ }
+
+ private String getFileNameSuffix() {
+ String fileName = getFileName();
+ int index = fileName.indexOf('.');
+ if (index >= 0) {
+ return fileName.substring(index);
+ } else {
+ return "";
+ }
+ }
+
+ public DiskFile getChild(String fileName) {
+ DiskFile child = null;
+ for (Map.Entry entry : entrySet()) {
+ DiskFile file = entry.getValue();
+ if (file.getFileName().equals(fileName)) {
+ child = entry.getValue();
+ break;
+ } else if (file.isDirectory()) {
+ child = file.getChild(fileName);
+ if (child != null) {
+ break;
+ }
+ }
+ }
+ return child;
+ }
+
+ private DiskFile getParent(Path path) {
+ Path pathParent = path.getParent();
+ DiskFile parent = get(pathParent);
+ if (parent == null) {
+ if (this.path.equals(pathParent)) {
+ parent = this;
+ } else {
+ parent = getParent(pathParent).get(pathParent);
+ }
+ parent.putIfAbsent(path, new DiskFile(path, true));
+ }
+ return parent;
+ }
+
+ public void addFile(Path path, String clip) {
+ path = clipPath(path, clip);
+ DiskFile parent = getParent(path);
+ parent.put(path, new DiskFile(path, false));
+ }
+
+ public void addDirectory(Path path, String clip) {
+ path = clipPath(path, clip);
+ DiskFile parent = getParent(path);
+ parent.putIfAbsent(path, new DiskFile(path, true));
+ }
+
+ @Override
+ public int compareTo(DiskFile file) {
+ // ".hpp", then ".inline.hpp", then ".cpp"
+ int equal = getFileNameNoSuffix().compareTo(file.getFileNameNoSuffix());
+ if (equal == 0) {
+ String suffix1 = getFileNameSuffix();
+ String suffix2 = file.getFileNameSuffix();
+ if (!suffix1.equals(".inline.hpp") && !suffix2.equals(".inline.hpp")) {
+ // .hpp before .cpp
+ equal = -(getFileNameSuffix().compareTo(file.getFileNameSuffix()));
+ } else if (suffix1.equals(".inline.hpp") && suffix2.equals(".hpp")) {
+ return 1;
+ } else if (suffix1.equals(".inline.hpp") && suffix2.equals(".cpp")) {
+ return -1;
+ } else if (suffix1.equals(".hpp") && suffix2.equals(".inline.hpp")) {
+ return -1;
+ } else if (suffix1.equals(".cpp") && suffix2.equals(".inline.hpp")) {
+ return 1;
+ }
+ }
+ return equal;
+ }
+}
diff --git a/make/ide/xcode/hotspot/src/classes/XcodeProjectMaker.java b/make/ide/xcode/hotspot/src/classes/XcodeProjectMaker.java
new file mode 100644
index 00000000000..9e262a82778
--- /dev/null
+++ b/make/ide/xcode/hotspot/src/classes/XcodeProjectMaker.java
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileSystemLoopException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+public final class XcodeProjectMaker {
+ private static final String JDK_SCRIPT_TOKEN_1 = "configure";
+ private static final String JDK_SCRIPT_TOKEN_2 = ".jcheck";
+ private static final String COMPILER_LINE_HEADER = "-I";
+ private static final String COMPILER_IFRAMEWORK = "-iframework";
+ private static final String COMPILER_FFRAMEWORK = "-F";
+ private static final String SRC_HOTSPOT_PATH = "/src/hotspot";
+ private static final String TEST_HOTSPOT_PATH = "/test/hotspot/gtest";
+ private static final String ALIAS_JAVA_OLD = "java_old.sh";
+ private static final String ALIAS_JAVA_NEW = "java_new.sh";
+ private static final String JDK_BIN_JAVA = "/jdk/bin/java";
+ private static final String FILE_TOKEN = "\"file\": ";
+ private static final String COMMAND_TOKEN = "\"command\": ";
+ private static final String QUOTE_START_TOKEN = "'\\\"";
+ private static final String QUOTE_END_TOKEN = "\\\"'";
+ private static final String VERSION = "2.0.0";
+ private static final String EXCLUDE_PARSE_TOKEN_1 = "gtest";
+ private static final String TEMPLATE_FRAMEWORK_SEARCH_PATHS = "TEMPLATE_FRAMEWORK_SEARCH_PATHS";
+ private static final String TEMPLATE_OTHER_CFLAGS = "TEMPLATE_OTHER_CFLAGS";
+ private static final String TEMPLATE_OTHER_LDFLAGS = "TEMPLATE_OTHER_LDFLAGS";
+ private static final String TEMPLATE_USER_HEADER_SEARCH_PATHS = "TEMPLATE_USER_HEADER_SEARCH_PATHS";
+ private static final String TEMPLATE_GROUP_GENSRC = "TEMPLATE_GROUP_GENSRC";
+ private static final String TEMPLATE_GROUP_SRC = "TEMPLATE_GROUP_SRC";
+ private static final String TEMPLATE_GROUP_TEST = "TEMPLATE_GROUP_TEST";
+ private static final String TEMPLATE_GROUPS = "TEMPLATE_GROUPS";
+ private static final String TEMPLATE_PBXBUILDFILE = "TEMPLATE_PBXBUILDFILE";
+ private static final String TEMPLATE_PBXFILEREFERENCE = "TEMPLATE_PBXFILEREFERENCE";
+ private static final String TEMPLATE_PBXSOURCESSBUILDPHASE = "TEMPLATE_PBXSOURCESSBUILDPHASE";
+ private static final String TEMPLATE_JDK_PATH = "TEMPLATE_JDK_PATH";
+ private static final String HOTSPOT_PBXPROJ = "hotspot.xcodeproj";
+ private static final String PBXPROJ = "project.pbxproj";
+ private static final String XCSAHAREDDATA = "xcshareddata";
+ private static final String XCSCHEMES = "xcschemes";
+ private static final String JVM_XCSCHEME = "jvm.xcscheme";
+ private static final String J2D_XCSCHEME = "runJ2Demo.xcscheme";
+ private static final String XCDEBUGGER = "xcdebugger";
+ private static final String XCBKPTLIST = "Breakpoints_v2.xcbkptlist";
+ private static final String TEMPLATE_PBXPROJ = PBXPROJ + ".template";
+ private static final String TEMPLATE_JVM_XCSCHEME = JVM_XCSCHEME + ".template";
+ private static final String TEMPLATE_J2D_XCSCHEME = J2D_XCSCHEME + ".template";
+ private static final String TEMPLATE_XCBKPTLIST = XCBKPTLIST + ".template";
+ private static final String[] EXCLUDE_FILES_PREFIX = {"."};
+ private static final String[] EXCLUDE_FILES_POSTFIX = {".log", ".cmdline"};
+ private static final String[] COMPILER_FLAGS_INCLUDE = {"-m", "-f", "-D", "-W"};
+ private static final String[] COMPILER_FLAGS_IS = {"-g", "-Os", "-0"};
+ private static final String[] COMPILER_FLAGS_EXCLUDE = {"-DTHIS_FILE", "-DGTEST_OS_MAC", "-mmacosx-version-min", "-Werror"}; // "-Werror" causes Xcode to stop compiling
+ private static final int EXIT4 = -4;
+ private static final int EXIT5 = -5;
+ private static final int EXIT6 = -6;
+ private static final int EXIT7 = -7;
+
+ private final HashMap> compiledFiles = new HashMap<>();
+ private final TreeSet compilerFlags = new TreeSet<>();
+ private List linkerFlags = List.of();
+ private final TreeSet headerPaths = new TreeSet<>();
+ private final boolean debugLog;
+ private String projectMakerDataPath = null;
+ private String generatedHotspotPath = null;
+ private String iframework = null;
+ private String fframework = null;
+ private DiskFile rootGensrc = new DiskFile("/", true);
+ private DiskFile rootSrc = new DiskFile("/", true);
+ private DiskFile rootTest = new DiskFile("/", true);
+
+ public XcodeProjectMaker(boolean debugLog) {
+ this.debugLog = debugLog;
+ }
+
+ public static void main(String[] args) {
+ String workspaceRoot = args[0];
+ String outputDir = args[1];
+ String pathToProjectMakerData = args[2];
+ String pathToCompileCommands = args[3];
+ String pathToLinkerOptionsFile = args[4];
+ String linkerOptionsString = readFile(pathToLinkerOptionsFile);
+ boolean debugLog = args.length > 5 && args[5].equals("-d");
+
+ File xcodeFolder = new File(outputDir);
+ xcodeFolder.mkdirs();
+ String workspaceRootPathFromOutputDir = findRelativePathToWorkspaceRoot(outputDir);
+
+ if (debugLog) {
+ System.out.println();
+ System.out.println("Version " + VERSION);
+ System.out.println();
+ System.out.println(" Path to workspace root is \"" + workspaceRoot + "\"");
+ System.out.println("Path to compile commands file is \"" + pathToCompileCommands + "\"");
+ System.out.println(" Xcode project will be placed in \"" + outputDir + "\"");
+ System.out.println();
+ }
+
+ XcodeProjectMaker maker = new XcodeProjectMaker(debugLog);
+ maker.parseHotspotCompileCommands(pathToCompileCommands);
+ maker.linkerFlags = List.of(linkerOptionsString.split(" "));
+ maker.projectMakerDataPath = pathToProjectMakerData;
+
+ maker.printLogDetails();
+
+ maker.prepareFiles(workspaceRoot);
+ maker.makeXcodeProj(outputDir, workspaceRootPathFromOutputDir);
+
+ String pathToBuild = getFileParent(outputDir);
+ maker.makeAliases(outputDir, pathToBuild);
+
+ System.out.println();
+ System.out.println("The Xcode project for hotspot was succesfully created");
+ System.out.println("It can be found in '" + outputDir + "/" + HOTSPOT_PBXPROJ + "'");
+ System.out.println();
+ }
+
+ // find a path to what looks like jdk
+ private static String findRelativePathToWorkspaceRoot(String root) {
+ String pathToWorkspaceRoot = null;
+ String path = root;
+ boolean found1 = false;
+ boolean found2 = false;
+
+ while (!found1 && !found2) {
+ File folder = new File(path);
+ File[] files = folder.listFiles();
+ for (File file : files) {
+ String fileName = file.toPath().getFileName().toString();
+ if (fileName.equals(JDK_SCRIPT_TOKEN_1)) {
+ found1 = true;
+ }
+ if (fileName.equals(JDK_SCRIPT_TOKEN_2)) {
+ found2 = true;
+ }
+ if (found1 && found2) {
+ break;
+ }
+ }
+
+ if (!found1 && !found2) {
+ path = Paths.get(path).getParent().toString();
+ if (pathToWorkspaceRoot == null) {
+ pathToWorkspaceRoot = "..";
+ } else {
+ pathToWorkspaceRoot += "/..";
+ }
+ }
+ }
+ return pathToWorkspaceRoot;
+ }
+
+ private static String readFile(File file) {
+ return readFile(file.toPath());
+ }
+
+ private static String readFile(String path) {
+ return readFile(Paths.get(path));
+ }
+
+ private static String readFile(Path path) {
+ try {
+ return Files.readString(path);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ private static void writeFile(File file, String string) {
+ writeFile(file.toPath(), string);
+ }
+
+ private static void writeFile(Path path, String string) {
+ try {
+ Files.writeString(path, string);
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.exit(EXIT4);
+ }
+ }
+
+ private static boolean excludeFile(Path path) {
+ return excludeFile(path.toString());
+ }
+
+ private static boolean excludeFile(String string) {
+ return excludeFile(string, null);
+ }
+
+ private static boolean excludeFile(String string, String exclude) {
+ if (exclude != null) {
+ if (contains(string, exclude)) {
+ return true;
+ }
+ }
+ for (String excludeFilesPrefix : EXCLUDE_FILES_PREFIX) {
+ if (string.startsWith(excludeFilesPrefix)) {
+ return true;
+ }
+ }
+ for (String excludeFilesPostfix : EXCLUDE_FILES_POSTFIX) {
+ if (string.endsWith(excludeFilesPostfix)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isExcludeCompilerFlag(String string) {
+ boolean flag = false;
+ for (String exclude : COMPILER_FLAGS_EXCLUDE) {
+ if (string.contains(exclude)) {
+ flag = true;
+ break;
+ }
+ }
+ return flag;
+ }
+
+ private static boolean isCompilerFlag(String string) {
+ boolean flag = false;
+ for (String include : COMPILER_FLAGS_INCLUDE) {
+ if (string.startsWith(include)) {
+ flag = true;
+ break;
+ }
+ }
+ for (String is : COMPILER_FLAGS_IS) {
+ if (string.equals(is)) {
+ flag = true;
+ break;
+ }
+ }
+ if (isExcludeCompilerFlag(string)) {
+ flag = false;
+ }
+ return flag;
+ }
+
+ private static String strip(String string) {
+ return string.substring(2, string.length() - 1);
+ }
+
+ private static String strip(String string, String token) {
+ int start = string.indexOf(token);
+ int end = start + token.length();
+ return strip(string.substring(end));
+ }
+
+ private static boolean contains(String string, String token) {
+ return ((string.length() >= token.length()) && (string.contains(token)));
+ }
+
+ private static String getFileParent(String path) {
+ return Paths.get(path).getParent().toString();
+ }
+
+ private static String extractPath(String string, String from, String to) {
+ String result = null;
+ String[] tokens = string.split("/");
+ int i = 0;
+ for (; i < tokens.length; i++) {
+ if (tokens[i].equals(from)) {
+ result = "";
+ break;
+ }
+ }
+ for (; i < tokens.length; i++) {
+ result += "/" + tokens[i];
+ if (tokens[i].equals(to)) {
+ break;
+ }
+ }
+ return result;
+ }
+
+ private void extractCommonCompilerFlags() {
+ // heuristic, find average count of number of flags used by each compiled file
+ int countFiles = 0;
+ int countFlags = 0;
+
+ for (Map.Entry> entry : this.compiledFiles.entrySet()) {
+ countFiles++;
+ List flags = entry.getValue();
+ countFlags += flags.size();
+ }
+
+ // when finding common flags, only consider files with this many flags
+ int flagCutoff = (countFlags / countFiles) / 2;
+
+ // collect all flags
+ for (Map.Entry> entry : this.compiledFiles.entrySet()) {
+ List flags = entry.getValue();
+ if (flags.size() > flagCutoff) {
+ this.compilerFlags.addAll(flags);
+ }
+ }
+
+ // find flags to remove
+ Set removeFlags = new TreeSet<>();
+ for (Map.Entry> entry : this.compiledFiles.entrySet()) {
+ List flags = entry.getValue();
+ if (flags.size() > flagCutoff) {
+ for (String common : this.compilerFlags) {
+ if (!flags.contains(common)) {
+ removeFlags.add(common);
+ }
+ }
+ }
+ }
+
+ // leave only common flags
+ for (String flag : removeFlags) {
+ this.compilerFlags.remove(flag);
+ }
+
+ // remove common flags from each compiler file, leaving only the unique ones
+ for (Map.Entry> entry : this.compiledFiles.entrySet()) {
+ List flags = entry.getValue();
+ if (flags.size() > flagCutoff) {
+ for (String common : this.compilerFlags) {
+ flags.remove(common);
+ }
+ }
+ }
+ }
+
+ private void extractCompilerFlags(String line) {
+ boolean verboseCompilerTokens = false;
+ String file = null;
+ ArrayList flags = null;
+
+ String[] commands = line.split(",");
+ for (String command : commands) {
+ if (contains(command, FILE_TOKEN)) {
+ file = strip(command, FILE_TOKEN);
+ //verbose_compiler_tokens = Contains(file, "vm_version.cpp");
+ } else if (contains(command, COMMAND_TOKEN)) {
+ String tokens = strip(command, COMMAND_TOKEN);
+ String[] arguments = tokens.split(" ");
+ if (arguments.length >= 3) {
+ flags = new ArrayList<>();
+ for (int a = 2; a < arguments.length; a++) {
+ String argument = arguments[a];
+ if (isCompilerFlag(argument)) {
+ // catch argument like -DVMTYPE=\"Minimal\"
+ if (contains(argument, "\\\\\\\"") && argument.endsWith("\\\\\\\"")) {
+ // TODO: more robust fix needed here
+ argument = argument.replace("\\", "");
+ argument = argument.replaceFirst("\"", "~.~"); // temp token ~.~
+ argument = argument.replace("\"", "\\\"'");
+ argument = argument.replace("~.~", "'\\\"");
+ }
+
+ // argument like -DHOTSPOT_VM_DISTRO='\"Java HotSpot(TM)\"'
+ // gets split up, so reconstruct as single string
+ if (contains(argument, QUOTE_START_TOKEN) && !argument.endsWith(QUOTE_END_TOKEN)) {
+ String fullArgument = argument;
+ do {
+ ++a;
+ argument = arguments[a];
+ fullArgument = fullArgument + " " + argument;
+ } while (!argument.endsWith(QUOTE_END_TOKEN));
+ argument = fullArgument;
+ }
+ flags.add(argument);
+ if (verboseCompilerTokens) {
+ System.out.println(" FOUND COMPILER FLAG: " + argument);
+ }
+ } else if (argument.startsWith(COMPILER_LINE_HEADER)) {
+ this.headerPaths.add(argument.substring(2));
+ } else if (argument.equals(COMPILER_IFRAMEWORK)) {
+ if (iframework == null) {
+ ++a;
+ this.iframework = arguments[a]; // gets the value, so skip it for the next loop
+ }
+ } else if (argument.equals(COMPILER_FFRAMEWORK)) {
+ if (fframework == null) {
+ ++a;
+ this.fframework = arguments[a]; // gets the value, so skip it for the next loop
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ((file != null) && (flags != null)) {
+ this.compiledFiles.put(file, flags);
+ } else {
+ System.err.println(" WARNING: extractCompilerFlags returns file:" + file + ", flags:" + flags);
+ }
+
+ if (verboseCompilerTokens) {
+ System.exit(0);
+ }
+ }
+
+ public void parseHotspotCompileCommands(String path) {
+ String content = readFile(path);
+ String[] parts = content.split("\\{"); // }
+
+ int found = 0;
+ for (String line : parts) {
+ if (!contains(line, EXCLUDE_PARSE_TOKEN_1) && !line.startsWith("[")) {
+ extractCompilerFlags(line);
+ found++;
+ }
+ }
+ if (debugLog) {
+ System.out.println("Found total of " + found + " files that make up the libjvm.dylib");
+ }
+ extractCommonCompilerFlags();
+
+ // figure out "gensrc" folder
+ // from: "/Users/gerard/Desktop/jdk_test/jdk10/build/macosx-x86_64-normal-server-fastdebug/hotspot/variant-server/gensrc/adfiles/ad_x86_clone.cpp"
+ // to: "/build/macosx-x86_64-normal-server-fastdebug/hotspot/variant-server/gensrc"
+ for (Map.Entry> entry : this.compiledFiles.entrySet()) {
+ String file = entry.getKey();
+ if (file.contains("gensrc")) {
+ this.generatedHotspotPath = extractPath(file, "build", "gensrc");
+ //generatedHotspotPath = "/build/macosx-x64/hotspot/variant-server/gensrc";
+ //generatedHotspotPath = "/build/macosx-x86_64-normal-server-fastdebug/hotspot/variant-server/gensrc";
+ }
+ }
+ }
+
+ // https://docs.oracle.com/javase/tutorial/displayCode.html?code=https://docs.oracle.com/javase/tutorial/essential/io/examples/Copy.java
+ private DiskFile getHotspotFiles(DiskFile root, String workspaceRoot, String hotspotPath) {
+ File file = new File(workspaceRoot + "/" + hotspotPath);
+ if (!file.exists()) {
+ return null;
+ }
+
+ try {
+ final Path rootDir = Paths.get(workspaceRoot + hotspotPath);
+ Files.walkFileTree(rootDir, new HotspotFileVisitor(root, hotspotPath));
+ } catch (IOException ex) {
+ System.err.println("ex: " + ex);
+ }
+
+ return root;
+ }
+
+ public void prepareFiles(String workspaceRoot) {
+ this.rootGensrc = getHotspotFiles(this.rootGensrc, workspaceRoot, this.generatedHotspotPath);
+ this.rootSrc = getHotspotFiles(this.rootSrc, workspaceRoot, SRC_HOTSPOT_PATH);
+ this.rootTest = getHotspotFiles(this.rootTest, workspaceRoot, TEST_HOTSPOT_PATH);
+
+ // make a copy of files from the log
+ Set logFiles = new TreeSet<>(this.compiledFiles.keySet());
+
+ int totalMarkedFiles = 0;
+ DiskFile[] roots = { this.rootGensrc, this.rootSrc };
+ for (DiskFile root : roots) {
+ List diskFiles = root.getFiles();
+ for (DiskFile diskFile : diskFiles) {
+ if (!diskFile.isDirectory()) {
+ String logFileProcessed = null;
+ String diskFilePath = diskFile.getFilePath();
+ for (String logFilePath : logFiles) {
+ if (contains(logFilePath, diskFilePath)) {
+ totalMarkedFiles++;
+
+ logFileProcessed = logFilePath;
+
+ // mark the file as needing compilation
+ diskFile.markAsCompiled(this.compiledFiles.get(logFilePath));
+
+ // break early if found
+ break;
+ }
+ }
+ if (logFileProcessed != null) {
+ // remove the file, so we don't have to search through it again
+ logFiles.remove(logFileProcessed);
+ }
+ }
+ }
+ }
+
+ if (this.compiledFiles.size() != totalMarkedFiles) {
+ System.err.println("\nError: was expecting to compile " + this.compiledFiles.size() + " files, but marked " + totalMarkedFiles);
+ for (String file : logFiles) {
+ System.err.println("file: " + file);
+ }
+ System.exit(EXIT5);
+ }
+
+ if (!logFiles.isEmpty()) {
+ System.err.println("\nError: unprocessed files left over:");
+ for (String logFile : logFiles) {
+ System.err.println(" " + logFile);
+ }
+ System.exit(EXIT6);
+ }
+ }
+
+ public void printLogDetails() {
+ if (!debugLog) return;
+
+ System.out.println("\nFound " + this.compilerFlags.size() + " common compiler flags:");
+ for (String flag : this.compilerFlags) {
+ System.out.println(" " + flag);
+ }
+
+ System.out.println("\nList of compiled files (each one uses common compiler flags plus extra ones as specified):");
+ int count = 1;
+ for (Map.Entry> entry : this.compiledFiles.entrySet()) {
+ String file = entry.getKey();
+ System.out.format("%4d: %s\n", (count), file);
+ count++;
+ List flags = entry.getValue();
+ for (String flag : flags) {
+ System.out.println(" " + flag);
+ }
+ }
+
+ System.out.println("\nFound " + this.linkerFlags.size() + " linker flags:");
+ for (String flag : this.linkerFlags) {
+ System.out.println(" " + flag);
+ }
+
+ System.out.println("\nFound " + this.headerPaths.size() + " header paths:");
+ for (String header : this.headerPaths) {
+ System.out.println(" " + header);
+ }
+
+ System.out.println("\nFrameworks:");
+ System.out.println(" -iframework " + iframework);
+ System.out.println(" -f " + fframework);
+ }
+
+ private String makeProjectPbxproj(String workspaceRootPathFromOutputDir, String string) {
+ String cFlags = "";
+ for (String flag : this.compilerFlags) {
+ cFlags += " \"" + flag.replace("\"", "\\\\\"") + "\",\n";
+ }
+ cFlags = cFlags.substring(0, cFlags.length() - 2);
+ string = string.replaceFirst(TEMPLATE_OTHER_CFLAGS, cFlags);
+
+ String ldFlags = "";
+ for (String flag : this.linkerFlags) {
+ ldFlags += " \"" + flag + "\",\n";
+ }
+ ldFlags = ldFlags.substring(0, ldFlags.length() - 2);
+ string = string.replaceFirst(TEMPLATE_OTHER_LDFLAGS, ldFlags);
+
+ String headerPaths = "";
+ for (String header : this.headerPaths) {
+ headerPaths += " \"" + header + "\",\n";
+ }
+ headerPaths = headerPaths.substring(0, headerPaths.length() - 2);
+ string = string.replaceFirst(TEMPLATE_USER_HEADER_SEARCH_PATHS, headerPaths);
+
+ String frameworkPaths = "";
+ if (fframework != null) {
+ frameworkPaths += " \"" + fframework + "\"\n";
+ }
+ string = string.replaceFirst(TEMPLATE_FRAMEWORK_SEARCH_PATHS, frameworkPaths);
+
+ DiskFile gensrcFile = this.rootGensrc.getChild("gensrc");
+ string = string.replaceFirst(TEMPLATE_GROUP_GENSRC, " " + gensrcFile.getXcodeId());
+
+ DiskFile srcFile = this.rootSrc.getChild("src");
+ string = string.replaceFirst(TEMPLATE_GROUP_SRC, " " + srcFile.getXcodeId());
+
+ DiskFile testFile = this.rootTest.getChild("test");
+ string = string.replaceFirst(TEMPLATE_GROUP_TEST, " " + testFile.getXcodeId());
+
+ String gensrcGroups = gensrcFile.generatePbxGroup();
+ String srcGroups = srcFile.generatePbxGroup();
+ String testGroups = testFile.generatePbxGroup();
+ string = string.replaceFirst(TEMPLATE_GROUPS, gensrcGroups + srcGroups + testGroups);
+
+ String gensrcFiles = gensrcFile.generatePbxFileReference(workspaceRootPathFromOutputDir);
+ String srcFiles = srcFile.generatePbxFileReference(workspaceRootPathFromOutputDir);
+ String testFiles = testFile.generatePbxFileReference(workspaceRootPathFromOutputDir);
+ string = string.replaceFirst(TEMPLATE_PBXFILEREFERENCE, gensrcFiles + srcFiles + testFiles);
+
+ String gensrcCompiled = gensrcFile.generatePbxBuildFile();
+ String compiled = srcFile.generatePbxBuildFile();
+ string = string.replaceFirst(TEMPLATE_PBXBUILDFILE, gensrcCompiled + compiled);
+
+ String gensrcBuilt = gensrcFile.generatePbxSourcesBuildPhase();
+ String built = srcFile.generatePbxSourcesBuildPhase();
+ string = string.replaceFirst(TEMPLATE_PBXSOURCESSBUILDPHASE, gensrcBuilt + built);
+
+ return string;
+ }
+
+ private String makeTemplateXcscheme(String outputDir, String string) {
+ string = string.replaceAll(TEMPLATE_JDK_PATH, outputDir);
+
+ return string;
+ }
+
+ public void makeXcodeProj(String outputDir, String workspaceRootPathFromOutputDir) {
+ /*
+ jvm.xcodeproj <-- folder
+ project.pbxproj <-- file
+ xcshareddata <-- folder
+ xcschemes <-- folder
+ jvm.xcscheme <-- file
+ xcdebugger <-- folder
+ Breakpoints_v2.xcbkptlist <-- file
+ */
+ File xcodeDir = new File(outputDir);
+ File jvmXcodeprojDir = new File(xcodeDir, HOTSPOT_PBXPROJ);
+ File projectPbxprojFile = new File(jvmXcodeprojDir, PBXPROJ);
+ File xcshareddataDir = new File(jvmXcodeprojDir, XCSAHAREDDATA);
+ File xcschemesDir = new File(xcshareddataDir, XCSCHEMES);
+ File jvmXcschemeFile = new File(xcschemesDir, JVM_XCSCHEME);
+ File j2DemoXcschemeFile = new File(xcschemesDir, J2D_XCSCHEME);
+ File xcdebuggerDir = new File(xcshareddataDir, XCDEBUGGER);
+ File jBreakpointsV2XcbkptlistFile = new File(xcdebuggerDir, XCBKPTLIST);
+
+ if (xcodeDir.exists()) {
+ xcodeDir.delete();
+ }
+
+ jvmXcodeprojDir.mkdirs();
+ xcshareddataDir.mkdirs();
+ xcschemesDir.mkdirs();
+ xcdebuggerDir.mkdirs();
+
+ File dataDir = new File(projectMakerDataPath);
+ File templateProjectPbxprojFile = new File(dataDir, TEMPLATE_PBXPROJ);
+ File templateJvmXcschemeFile = new File(dataDir, TEMPLATE_JVM_XCSCHEME);
+ File templateJ2DemoXcschemeFile = new File(dataDir, TEMPLATE_J2D_XCSCHEME);
+ File templateJBreakpointsV2XcbkptlistFile = new File(dataDir, TEMPLATE_XCBKPTLIST);
+
+ String projectPbxprojString = readFile(templateProjectPbxprojFile);
+ String jvmXcschemeString = readFile(templateJvmXcschemeFile);
+ String j2DemoXcschemeString = readFile(templateJ2DemoXcschemeFile);
+ String jBreakpointsV2XcbkptlistString = readFile(templateJBreakpointsV2XcbkptlistFile);
+
+ writeFile(projectPbxprojFile, makeProjectPbxproj(workspaceRootPathFromOutputDir, projectPbxprojString));
+ writeFile(jvmXcschemeFile, makeTemplateXcscheme(outputDir, jvmXcschemeString));
+ writeFile(j2DemoXcschemeFile, makeTemplateXcscheme(outputDir, j2DemoXcschemeString));
+ writeFile(jBreakpointsV2XcbkptlistFile, jBreakpointsV2XcbkptlistString);
+ }
+
+ public void makeAliases(String outputDir, String pathToBuild) {
+ File xcodeDir = new File(outputDir);
+ File jdkOldSh = new File(xcodeDir, ALIAS_JAVA_OLD);
+ File jdkNewSh = new File(xcodeDir, ALIAS_JAVA_NEW);
+
+ writeFile(jdkOldSh, "#!/bin/bash\n" + pathToBuild + JDK_BIN_JAVA + " $@");
+ writeFile(jdkNewSh, "#!/bin/bash\n" + outputDir + "/build" + JDK_BIN_JAVA + " $@");
+
+ try {
+ Set permissions = new HashSet<>();
+ permissions.add(PosixFilePermission.OWNER_READ);
+ permissions.add(PosixFilePermission.OWNER_WRITE);
+ permissions.add(PosixFilePermission.OWNER_EXECUTE);
+ permissions.add(PosixFilePermission.GROUP_READ);
+ permissions.add(PosixFilePermission.OTHERS_READ);
+ Files.setPosixFilePermissions(jdkOldSh.toPath(), permissions);
+ Files.setPosixFilePermissions(jdkNewSh.toPath(), permissions);
+ } catch (IOException ex) {
+ System.err.println("Warning: unable to change file permissions");
+ System.err.println(ex);
+ }
+ }
+
+ private static class HotspotFileVisitor implements FileVisitor {
+ private final DiskFile root;
+ private final String hotspotPath;
+
+ public HotspotFileVisitor(DiskFile root, String hotspotPath) {
+ this.root = root;
+ this.hotspotPath = hotspotPath;
+ }
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs) {
+ if (excludeFile(path)) {
+ return FileVisitResult.SKIP_SUBTREE;
+ } else {
+ // consider folders based on their names
+ Path file = path.getFileName();
+ if (!excludeFile(file)) {
+ root.addDirectory(path, hotspotPath);
+ return FileVisitResult.CONTINUE;
+ } else {
+ // skip folders with names beginning with ".", etc
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ }
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
+ Path file = path.getFileName();
+ if (!excludeFile(file)) {
+ //System.err.println(path.toString());
+ root.addFile(path, hotspotPath);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path path, IOException exc) {
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path path, IOException exc) {
+ if (exc instanceof FileSystemLoopException) {
+ System.err.println("cycle detected: " + path);
+ } else {
+ System.err.format("Unable to process: %s: %s\n", path, exc);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ }
+}
diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java
index 15251358a01..8865e3908ae 100644
--- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java
+++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java
@@ -786,7 +786,10 @@ private static Map extractZoneNames(Map map, Str
String tzKey = Optional.ofNullable((String)handlerSupplMeta.get(tzid))
.orElse(tzid);
// Follow link, if needed
- var tzLink = tzdbLinks.get(tzKey);
+ String tzLink = null;
+ for (var k = tzKey; tzdbLinks.containsKey(k);) {
+ k = tzLink = tzdbLinks.get(k);
+ }
if (tzLink == null && tzdbLinks.containsValue(tzKey)) {
// reverse link search
// this is needed as in tzdb, "America/Buenos_Aires" links to
@@ -1214,7 +1217,7 @@ private static void generateZoneName() throws Exception {
private static Set getAvailableZoneIds() {
assert handlerMetaZones != null;
if (AVAILABLE_TZIDS == null) {
- AVAILABLE_TZIDS = new HashSet<>(ZoneId.getAvailableZoneIds());
+ AVAILABLE_TZIDS = new HashSet<>(Arrays.asList(TimeZone.getAvailableIDs()));
AVAILABLE_TZIDS.addAll(handlerMetaZones.keySet());
AVAILABLE_TZIDS.remove(MetaZonesParseHandler.NO_METAZONE_KEY);
}
@@ -1372,6 +1375,7 @@ private static Map coverageLevelsMap() throws Exception {
private static void generateTZDBShortNamesMap() throws IOException {
Files.walk(Path.of(tzDataDir), 1, FileVisitOption.FOLLOW_LINKS)
.filter(p -> p.toFile().isFile())
+ .filter(p -> p.getFileName().toString().matches("africa|antarctica|asia|australasia|backward|etcetera|europe|northamerica|southamerica"))
.forEach(p -> {
try {
String zone = null;
@@ -1394,43 +1398,41 @@ private static void generateTZDBShortNamesMap() throws IOException {
}
// remove comments in-line
line = line.replaceAll("[ \t]*#.*", "");
-
+ var tokens = line.split("[ \t]+", -1);
+ var token0len = tokens.length > 0 ? tokens[0].length() : 0;
// Zone line
- if (line.startsWith("Zone")) {
+ if (token0len > 0 && tokens[0].regionMatches(true, 0, "Zone", 0, token0len)) {
if (zone != null) {
tzdbShortNamesMap.put(zone, format + NBSP + rule);
}
- var zl = line.split("[ \t]+", -1);
- zone = zl[1];
- rule = zl[3];
- format = flipIfNeeded(inVanguard, zl[4]);
+ zone = tokens[1];
+ rule = tokens[3];
+ format = flipIfNeeded(inVanguard, tokens[4]);
} else {
if (zone != null) {
- if (line.startsWith("Rule") ||
- line.startsWith("Link")) {
+ if (token0len > 0 &&
+ (tokens[0].regionMatches(true, 0, "Rule", 0, token0len) ||
+ tokens[0].regionMatches(true, 0, "Link", 0, token0len))) {
tzdbShortNamesMap.put(zone, format + NBSP + rule);
zone = null;
rule = null;
format = null;
} else {
- var s = line.split("[ \t]+", -1);
- rule = s[2];
- format = flipIfNeeded(inVanguard, s[3]);
+ rule = tokens[2];
+ format = flipIfNeeded(inVanguard, tokens[3]);
}
}
}
// Rule line
- if (line.startsWith("Rule")) {
- var rl = line.split("[ \t]+", -1);
- tzdbSubstLetters.put(rl[1] + NBSP + (rl[8].equals("0") ? STD : DST),
- rl[9].replace(NO_SUBST, ""));
+ if (token0len > 0 && tokens[0].regionMatches(true, 0, "Rule", 0, token0len)) {
+ tzdbSubstLetters.put(tokens[1] + NBSP + (tokens[8].equals("0") ? STD : DST),
+ tokens[9].replace(NO_SUBST, ""));
}
// Link line
- if (line.startsWith("Link")) {
- var ll = line.split("[ \t]+", -1);
- tzdbLinks.put(ll[2], ll[1]);
+ if (token0len > 0 && tokens[0].regionMatches(true, 0, "Link", 0, token0len)) {
+ tzdbLinks.put(tokens[2], tokens[1]);
}
}
@@ -1491,13 +1493,14 @@ private static void fillTZDBShortNames(String tzid, String[] names) {
/*
* Convert TZDB offsets to JDK's offsets, eg, "-08" to "GMT-08:00".
* If it cannot recognize the pattern, return the argument as is.
+ * Returning null results in generating the GMT format at runtime.
*/
private static String convertGMTName(String f) {
try {
- // Should pre-fill GMT format once COMPAT is gone.
- // Till then, fall back to GMT format at runtime, after COMPAT short
- // names are populated
- ZoneOffset.of(f);
+ if (!f.equals("%z")) {
+ // Validate if the format is an offset
+ ZoneOffset.of(f);
+ }
return null;
} catch (DateTimeException dte) {
// textual representation. return as is
diff --git a/make/jdk/src/classes/build/tools/taglet/JSpec.java b/make/jdk/src/classes/build/tools/taglet/JSpec.java
index fda372c8b01..34cc2bd6b50 100644
--- a/make/jdk/src/classes/build/tools/taglet/JSpec.java
+++ b/make/jdk/src/classes/build/tools/taglet/JSpec.java
@@ -106,7 +106,8 @@ public JVMS() {
this.idPrefix = idPrefix;
}
- private static final Pattern TAG_PATTERN = Pattern.compile("(?s)(.+ )?(?[1-9][0-9]*)(?[0-9.]*)( .*)?$");
+ // Note: Matches special cases like @jvms 6.5.checkcast
+ private static final Pattern TAG_PATTERN = Pattern.compile("(?s)(.+ )?(?[1-9][0-9]*)(?[0-9a-z_.]*)( .*)?$");
/**
* Returns the set of locations in which the tag may be used.
diff --git a/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesCompiler.java b/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesCompiler.java
index 630d3a390d1..426d0bb10ed 100644
--- a/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesCompiler.java
+++ b/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesCompiler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -273,7 +273,7 @@ private void outputFile(Path dstFile, String version,
// link version-region-rules
out.writeShort(builtZones.size());
for (Map.Entry entry : builtZones.entrySet()) {
- int regionIndex = Arrays.binarySearch(regionArray, entry.getKey());
+ int regionIndex = findRegionIndex(regionArray, entry.getKey());
int rulesIndex = rulesList.indexOf(entry.getValue());
out.writeShort(regionIndex);
out.writeShort(rulesIndex);
@@ -281,8 +281,8 @@ private void outputFile(Path dstFile, String version,
// alias-region
out.writeShort(links.size());
for (Map.Entry entry : links.entrySet()) {
- int aliasIndex = Arrays.binarySearch(regionArray, entry.getKey());
- int regionIndex = Arrays.binarySearch(regionArray, entry.getValue());
+ int aliasIndex = findRegionIndex(regionArray, entry.getKey());
+ int regionIndex = findRegionIndex(regionArray, entry.getValue());
out.writeShort(aliasIndex);
out.writeShort(regionIndex);
}
@@ -294,6 +294,14 @@ private void outputFile(Path dstFile, String version,
}
}
+ private static int findRegionIndex(String[] regionArray, String region) {
+ int index = Arrays.binarySearch(regionArray, region);
+ if (index < 0) {
+ throw new IllegalArgumentException("Unknown region: " + region);
+ }
+ return index;
+ }
+
/** Whether to output verbose messages. */
private boolean verbose;
diff --git a/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesProvider.java b/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesProvider.java
index d82e58e3420..ecca3c69c06 100644
--- a/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesProvider.java
+++ b/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -164,7 +164,8 @@ private void load(List files) throws IOException {
}
continue;
}
- if (line.startsWith("Zone")) { // parse Zone line
+ int token0len = tokens.length > 0 ? tokens[0].length() : line.length();
+ if (line.regionMatches(true, 0, "Zone", 0, token0len)) { // parse Zone line
String name = tokens[1];
if (excludedZones.contains(name)){
continue;
@@ -182,13 +183,13 @@ private void load(List files) throws IOException {
if (zLine.parse(tokens, 2)) {
openZone = null;
}
- } else if (line.startsWith("Rule")) { // parse Rule line
+ } else if (line.regionMatches(true, 0, "Rule", 0, token0len)) { // parse Rule line
String name = tokens[1];
if (!rules.containsKey(name)) {
rules.put(name, new ArrayList(10));
}
rules.get(name).add(new RuleLine().parse(tokens));
- } else if (line.startsWith("Link")) { // parse link line
+ } else if (line.regionMatches(true, 0, "Link", 0, token0len)) { // parse link line
if (tokens.length >= 3) {
String realId = tokens[1];
String aliasId = tokens[2];
@@ -304,7 +305,7 @@ private void parse(String[] tokens, int off) {
month = parseMonth(tokens[off++]);
if (off < tokens.length) {
String dayRule = tokens[off++];
- if (dayRule.startsWith("last")) {
+ if (dayRule.regionMatches(true, 0, "last", 0, 4)) {
dayOfMonth = -1;
dayOfWeek = parseDayOfWeek(dayRule.substring(4));
adjustForwards = false;
@@ -355,42 +356,45 @@ private void parse(String[] tokens, int off) {
}
int parseYear(String year, int defaultYear) {
- switch (year.toLowerCase()) {
- case "min": return 1900;
- case "max": return Year.MAX_VALUE;
- case "only": return defaultYear;
- }
+ int len = year.length();
+
+ if (year.regionMatches(true, 0, "minimum", 0, len)) return 1900;
+ if (year.regionMatches(true, 0, "maximum", 0, len)) return Year.MAX_VALUE;
+ if (year.regionMatches(true, 0, "only", 0, len)) return defaultYear;
+
return Integer.parseInt(year);
}
Month parseMonth(String mon) {
- switch (mon) {
- case "Jan": return Month.JANUARY;
- case "Feb": return Month.FEBRUARY;
- case "Mar": return Month.MARCH;
- case "Apr": return Month.APRIL;
- case "May": return Month.MAY;
- case "Jun": return Month.JUNE;
- case "Jul": return Month.JULY;
- case "Aug": return Month.AUGUST;
- case "Sep": return Month.SEPTEMBER;
- case "Oct": return Month.OCTOBER;
- case "Nov": return Month.NOVEMBER;
- case "Dec": return Month.DECEMBER;
- }
+ int len = mon.length();
+
+ if (mon.regionMatches(true, 0, "January", 0, len)) return Month.JANUARY;
+ if (mon.regionMatches(true, 0, "February", 0, len)) return Month.FEBRUARY;
+ if (mon.regionMatches(true, 0, "March", 0, len)) return Month.MARCH;
+ if (mon.regionMatches(true, 0, "April", 0, len)) return Month.APRIL;
+ if (mon.regionMatches(true, 0, "May", 0, len)) return Month.MAY;
+ if (mon.regionMatches(true, 0, "June", 0, len)) return Month.JUNE;
+ if (mon.regionMatches(true, 0, "July", 0, len)) return Month.JULY;
+ if (mon.regionMatches(true, 0, "August", 0, len)) return Month.AUGUST;
+ if (mon.regionMatches(true, 0, "September", 0, len)) return Month.SEPTEMBER;
+ if (mon.regionMatches(true, 0, "October", 0, len)) return Month.OCTOBER;
+ if (mon.regionMatches(true, 0, "November", 0, len)) return Month.NOVEMBER;
+ if (mon.regionMatches(true, 0, "December", 0, len)) return Month.DECEMBER;
+
throw new IllegalArgumentException("Unknown month: " + mon);
}
DayOfWeek parseDayOfWeek(String dow) {
- switch (dow) {
- case "Mon": return DayOfWeek.MONDAY;
- case "Tue": return DayOfWeek.TUESDAY;
- case "Wed": return DayOfWeek.WEDNESDAY;
- case "Thu": return DayOfWeek.THURSDAY;
- case "Fri": return DayOfWeek.FRIDAY;
- case "Sat": return DayOfWeek.SATURDAY;
- case "Sun": return DayOfWeek.SUNDAY;
- }
+ int len = dow.length();
+
+ if (dow.regionMatches(true, 0, "Monday", 0, len)) return DayOfWeek.MONDAY;
+ if (dow.regionMatches(true, 0, "Tuesday", 0, len)) return DayOfWeek.TUESDAY;
+ if (dow.regionMatches(true, 0, "Wednesday", 0, len)) return DayOfWeek.WEDNESDAY;
+ if (dow.regionMatches(true, 0, "Thursday", 0, len)) return DayOfWeek.THURSDAY;
+ if (dow.regionMatches(true, 0, "Friday", 0, len)) return DayOfWeek.FRIDAY;
+ if (dow.regionMatches(true, 0, "Saturday", 0, len)) return DayOfWeek.SATURDAY;
+ if (dow.regionMatches(true, 0, "Sunday", 0, len)) return DayOfWeek.SUNDAY;
+
throw new IllegalArgumentException("Unknown day-of-week: " + dow);
}
diff --git a/make/modules/java.base/Copy.gmk b/make/modules/java.base/Copy.gmk
index 911fff60ea8..fea544a47a1 100644
--- a/make/modules/java.base/Copy.gmk
+++ b/make/modules/java.base/Copy.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -51,27 +51,25 @@ endif
ifeq ($(call isTargetOs, windows)+$(CREATING_BUILDJDK), true+false)
# Chmod to avoid permission issues if bundles are unpacked on unix platforms.
- define copy-and-chmod
- $(install-file)
- $(CHMOD) a+rx $@
- endef
-
# Use separate macro calls in case the source files are not in the same
# directory.
- $(eval $(call SetupCopyFiles,COPY_MSVCR, \
+ $(eval $(call SetupCopyFiles, COPY_MSVCR, \
DEST := $(LIB_DST_DIR), \
FILES := $(MSVCR_DLL), \
- MACRO := copy-and-chmod))
+ MACRO := copy-and-chmod-executable, \
+ ))
- $(eval $(call SetupCopyFiles,COPY_VCRUNTIME_1, \
+ $(eval $(call SetupCopyFiles, COPY_VCRUNTIME_1, \
DEST := $(LIB_DST_DIR), \
FILES := $(VCRUNTIME_1_DLL), \
- MACRO := copy-and-chmod))
+ MACRO := copy-and-chmod-executable, \
+ ))
- $(eval $(call SetupCopyFiles,COPY_MSVCP, \
+ $(eval $(call SetupCopyFiles, COPY_MSVCP, \
DEST := $(LIB_DST_DIR), \
FILES := $(MSVCP_DLL), \
- MACRO := copy-and-chmod))
+ MACRO := copy-and-chmod-executable, \
+ ))
TARGETS += $(COPY_MSVCR) $(COPY_VCRUNTIME_1) $(COPY_MSVCP)
@@ -80,7 +78,7 @@ ifeq ($(call isTargetOs, windows)+$(CREATING_BUILDJDK), true+false)
DEST := $(LIB_DST_DIR), \
SRC := $(UCRT_DLL_DIR), \
FILES := $(wildcard $(UCRT_DLL_DIR)/*.dll), \
- MACRO := copy-and-chmod, \
+ MACRO := copy-and-chmod-executable, \
))
TARGETS += $(COPY_UCRT_DLLS)
@@ -133,7 +131,7 @@ POLICY_SRC_LIST := $(POLICY_SRC)
$(POLICY_DST): $(POLICY_SRC_LIST)
$(call MakeTargetDir)
$(RM) $@ $@.tmp
- $(foreach f,$(POLICY_SRC_LIST),$(CAT) $(f) >> $@.tmp;)
+ $(foreach f, $(POLICY_SRC_LIST), $(CAT) $(f) >> $@.tmp;)
$(MV) $@.tmp $@
TARGETS += $(POLICY_DST)
@@ -158,7 +156,7 @@ endif
$(DEF_POLICY_DST): $(DEF_POLICY_SRC_LIST)
$(call MakeTargetDir)
$(RM) $@ $@.tmp
- $(foreach f,$(DEF_POLICY_SRC_LIST),$(CAT) $(f) >> $@.tmp;)
+ $(foreach f, $(DEF_POLICY_SRC_LIST), $(CAT) $(f) >> $@.tmp;)
$(MV) $@.tmp $@
TARGETS += $(DEF_POLICY_DST)
diff --git a/make/modules/java.base/Lib.gmk b/make/modules/java.base/Lib.gmk
index 3f4b1c73e89..2c3df4622b1 100644
--- a/make/modules/java.base/Lib.gmk
+++ b/make/modules/java.base/Lib.gmk
@@ -44,9 +44,11 @@ include lib/CoreLibraries.gmk
$(eval $(call SetupJdkLibrary, BUILD_LIBNET, \
NAME := net, \
OPTIMIZATION := LOW, \
- DISABLED_WARNINGS_gcc_net_util_md.c := format-nonliteral, \
+ DISABLED_WARNINGS_gcc_net_util_md.c := format-nonliteral unused-variable, \
DISABLED_WARNINGS_gcc_NetworkInterface.c := unused-function, \
- DISABLED_WARNINGS_clang_net_util_md.c := format-nonliteral, \
+ DISABLED_WARNINGS_clang_net_util_md.c := format-nonliteral \
+ unused-variable, \
+ DISABLED_WARNINGS_clang_NetworkInterface.c := unused-function, \
DISABLED_WARNINGS_clang_aix_DefaultProxySelector.c := \
deprecated-non-prototype, \
DISABLED_WARNINGS_clang_aix_NetworkInterface.c := gnu-pointer-arith, \
@@ -56,7 +58,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBNET, \
-delayload:winhttp.dll, \
JDK_LIBS := libjava libjvm, \
LIBS_linux := $(LIBDL), \
- LIBS_aix := $(LIBDL),\
+ LIBS_aix := $(LIBDL), \
LIBS_windows := advapi32.lib delayimp.lib iphlpapi.lib secur32.lib \
winhttp.lib ws2_32.lib, \
LIBS_macosx := \
@@ -77,6 +79,8 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBNIO, \
libnio/ch \
libnio/fs \
libjvm, \
+ DISABLED_WARNINGS_clang_Net.c := unused-function unused-variable, \
+ DISABLED_WARNINGS_clang_UnixNativeDispatcher.c := unused-variable, \
JDK_LIBS := libjava libnet, \
LIBS_linux := $(LIBDL) -lpthread, \
LIBS_aix := $(LIBDL), \
@@ -96,7 +100,8 @@ ifeq ($(call isTargetOs, macosx), true)
$(eval $(call SetupJdkLibrary, BUILD_LIBOSXSECURITY, \
NAME := osxsecurity, \
OPTIMIZATION := LOW, \
- DISABLED_WARNINGS_clang_KeystoreImpl.m := deprecated-declarations, \
+ DISABLED_WARNINGS_clang_KeystoreImpl.m := deprecated-declarations \
+ unused-but-set-variable unused-variable, \
JDK_LIBS := libjava, \
LIBS_macosx := -lobjc \
-framework CoreServices \
@@ -116,6 +121,8 @@ ifeq ($(call isTargetOsType, unix), true)
NAME := jsig, \
OPTIMIZATION := LOW, \
jsig.c_CFLAGS := -DHOTSPOT_VM_DISTRO='"$(HOTSPOT_VM_DISTRO)"', \
+ DISABLED_WARNINGS_gcc_jsig.c := unused-but-set-variable, \
+ DISABLED_WARNINGS_clang_jsig.c := unused-but-set-variable, \
LIBS_linux := $(LIBDL), \
LIBS_aix := $(LIBDL), \
))
@@ -169,6 +176,7 @@ ifeq ($(ENABLE_FALLBACK_LINKER), true)
NAME := fallbackLinker, \
EXTRA_HEADER_DIRS := java.base:libjava, \
CFLAGS := $(LIBFFI_CFLAGS), \
+ DISABLED_WARNINGS_gcc := implicit-function-declaration unused-variable, \
LIBS := $(LIBFFI_LIBS), \
LIBS_windows := ws2_32.lib, \
))
@@ -186,6 +194,7 @@ ifeq ($(call isTargetOs, linux)+$(call isTargetCpu, x86_64)+$(INCLUDE_COMPILER2)
LINK_TYPE := C++, \
OPTIMIZATION := HIGH, \
CXXFLAGS := -std=c++17, \
+ DISABLED_WARNINGS_gcc := unused-variable, \
LIBS_linux := $(LIBDL) $(LIBM), \
))
diff --git a/make/modules/java.base/gensrc/GensrcBuffer.gmk b/make/modules/java.base/gensrc/GensrcBuffer.gmk
index ce22230a8e1..8255cc62eec 100644
--- a/make/modules/java.base/gensrc/GensrcBuffer.gmk
+++ b/make/modules/java.base/gensrc/GensrcBuffer.gmk
@@ -279,101 +279,101 @@ endef
X_BUF := X-Buffer
-$(eval $(call SetupGenBuffer,ByteBuffer, $(X_BUF), type:=byte, BIN:=1))
-$(eval $(call SetupGenBuffer,CharBuffer, $(X_BUF), type:=char))
-$(eval $(call SetupGenBuffer,ShortBuffer, $(X_BUF), type:=short))
-$(eval $(call SetupGenBuffer,IntBuffer, $(X_BUF), type:=int))
-$(eval $(call SetupGenBuffer,LongBuffer, $(X_BUF), type:=long))
-$(eval $(call SetupGenBuffer,FloatBuffer, $(X_BUF), type:=float))
-$(eval $(call SetupGenBuffer,DoubleBuffer,$(X_BUF), type:=double))
+$(eval $(call SetupGenBuffer,ByteBuffer, $(X_BUF), type := byte, BIN := 1))
+$(eval $(call SetupGenBuffer,CharBuffer, $(X_BUF), type := char))
+$(eval $(call SetupGenBuffer,ShortBuffer, $(X_BUF), type := short))
+$(eval $(call SetupGenBuffer,IntBuffer, $(X_BUF), type := int))
+$(eval $(call SetupGenBuffer,LongBuffer, $(X_BUF), type := long))
+$(eval $(call SetupGenBuffer,FloatBuffer, $(X_BUF), type := float))
+$(eval $(call SetupGenBuffer,DoubleBuffer,$(X_BUF), type := double))
# Buffers whose contents are heap-allocated
#
HEAP_X_BUF := Heap-X-Buffer
-$(eval $(call SetupGenBuffer,HeapByteBuffer, $(HEAP_X_BUF), type:=byte))
-$(eval $(call SetupGenBuffer,HeapByteBufferR, $(HEAP_X_BUF), type:=byte, RW:=R))
-$(eval $(call SetupGenBuffer,HeapCharBuffer, $(HEAP_X_BUF), type:=char))
-$(eval $(call SetupGenBuffer,HeapCharBufferR, $(HEAP_X_BUF), type:=char, RW:=R))
-$(eval $(call SetupGenBuffer,HeapShortBuffer, $(HEAP_X_BUF), type:=short))
-$(eval $(call SetupGenBuffer,HeapShortBufferR, $(HEAP_X_BUF), type:=short, RW:=R))
-$(eval $(call SetupGenBuffer,HeapIntBuffer, $(HEAP_X_BUF), type:=int))
-$(eval $(call SetupGenBuffer,HeapIntBufferR, $(HEAP_X_BUF), type:=int, RW:=R))
-$(eval $(call SetupGenBuffer,HeapLongBuffer, $(HEAP_X_BUF), type:=long))
-$(eval $(call SetupGenBuffer,HeapLongBufferR, $(HEAP_X_BUF), type:=long, RW:=R))
-$(eval $(call SetupGenBuffer,HeapFloatBuffer, $(HEAP_X_BUF), type:=float))
-$(eval $(call SetupGenBuffer,HeapFloatBufferR, $(HEAP_X_BUF), type:=float, RW:=R))
-$(eval $(call SetupGenBuffer,HeapDoubleBuffer, $(HEAP_X_BUF), type:=double))
-$(eval $(call SetupGenBuffer,HeapDoubleBufferR,$(HEAP_X_BUF), type:=double, RW:=R))
+$(eval $(call SetupGenBuffer,HeapByteBuffer, $(HEAP_X_BUF), type := byte))
+$(eval $(call SetupGenBuffer,HeapByteBufferR, $(HEAP_X_BUF), type := byte, RW := R))
+$(eval $(call SetupGenBuffer,HeapCharBuffer, $(HEAP_X_BUF), type := char))
+$(eval $(call SetupGenBuffer,HeapCharBufferR, $(HEAP_X_BUF), type := char, RW := R))
+$(eval $(call SetupGenBuffer,HeapShortBuffer, $(HEAP_X_BUF), type := short))
+$(eval $(call SetupGenBuffer,HeapShortBufferR, $(HEAP_X_BUF), type := short, RW := R))
+$(eval $(call SetupGenBuffer,HeapIntBuffer, $(HEAP_X_BUF), type := int))
+$(eval $(call SetupGenBuffer,HeapIntBufferR, $(HEAP_X_BUF), type := int, RW := R))
+$(eval $(call SetupGenBuffer,HeapLongBuffer, $(HEAP_X_BUF), type := long))
+$(eval $(call SetupGenBuffer,HeapLongBufferR, $(HEAP_X_BUF), type := long, RW := R))
+$(eval $(call SetupGenBuffer,HeapFloatBuffer, $(HEAP_X_BUF), type := float))
+$(eval $(call SetupGenBuffer,HeapFloatBufferR, $(HEAP_X_BUF), type := float, RW := R))
+$(eval $(call SetupGenBuffer,HeapDoubleBuffer, $(HEAP_X_BUF), type := double))
+$(eval $(call SetupGenBuffer,HeapDoubleBufferR,$(HEAP_X_BUF), type := double, RW := R))
# Direct byte buffer
#
DIRECT_X_BUF := Direct-X-Buffer
-$(eval $(call SetupGenBuffer,DirectByteBuffer, $(DIRECT_X_BUF), type:=byte, BIN:=1))
-$(eval $(call SetupGenBuffer,DirectByteBufferR,$(DIRECT_X_BUF), type:=byte, BIN:=1, RW:=R))
+$(eval $(call SetupGenBuffer,DirectByteBuffer, $(DIRECT_X_BUF), type := byte, BIN := 1))
+$(eval $(call SetupGenBuffer,DirectByteBufferR,$(DIRECT_X_BUF), type := byte, BIN := 1, RW := R))
# Unswapped views of direct byte buffers
#
-$(eval $(call SetupGenBuffer,DirectCharBufferU, $(DIRECT_X_BUF), type:=char, BO:=U))
-$(eval $(call SetupGenBuffer,DirectCharBufferRU, $(DIRECT_X_BUF), type:=char, RW:=R, BO:=U))
-$(eval $(call SetupGenBuffer,DirectShortBufferU, $(DIRECT_X_BUF), type:=short, BO:=U))
-$(eval $(call SetupGenBuffer,DirectShortBufferRU, $(DIRECT_X_BUF), type:=short, RW:=R, BO:=U))
-$(eval $(call SetupGenBuffer,DirectIntBufferU, $(DIRECT_X_BUF), type:=int, BO:=U))
-$(eval $(call SetupGenBuffer,DirectIntBufferRU, $(DIRECT_X_BUF), type:=int, RW:=R, BO:=U))
-$(eval $(call SetupGenBuffer,DirectLongBufferU, $(DIRECT_X_BUF), type:=long, BO:=U))
-$(eval $(call SetupGenBuffer,DirectLongBufferRU, $(DIRECT_X_BUF), type:=long, RW:=R, BO:=U))
-$(eval $(call SetupGenBuffer,DirectFloatBufferU, $(DIRECT_X_BUF), type:=float, BO:=U))
-$(eval $(call SetupGenBuffer,DirectFloatBufferRU, $(DIRECT_X_BUF), type:=float, RW:=R, BO:=U))
-$(eval $(call SetupGenBuffer,DirectDoubleBufferU, $(DIRECT_X_BUF), type:=double, BO:=U))
-$(eval $(call SetupGenBuffer,DirectDoubleBufferRU,$(DIRECT_X_BUF), type:=double, RW:=R, BO:=U))
+$(eval $(call SetupGenBuffer,DirectCharBufferU, $(DIRECT_X_BUF), type := char, BO := U))
+$(eval $(call SetupGenBuffer,DirectCharBufferRU, $(DIRECT_X_BUF), type := char, RW := R, BO := U))
+$(eval $(call SetupGenBuffer,DirectShortBufferU, $(DIRECT_X_BUF), type := short, BO := U))
+$(eval $(call SetupGenBuffer,DirectShortBufferRU, $(DIRECT_X_BUF), type := short, RW := R, BO := U))
+$(eval $(call SetupGenBuffer,DirectIntBufferU, $(DIRECT_X_BUF), type := int, BO := U))
+$(eval $(call SetupGenBuffer,DirectIntBufferRU, $(DIRECT_X_BUF), type := int, RW := R, BO := U))
+$(eval $(call SetupGenBuffer,DirectLongBufferU, $(DIRECT_X_BUF), type := long, BO := U))
+$(eval $(call SetupGenBuffer,DirectLongBufferRU, $(DIRECT_X_BUF), type := long, RW := R, BO := U))
+$(eval $(call SetupGenBuffer,DirectFloatBufferU, $(DIRECT_X_BUF), type := float, BO := U))
+$(eval $(call SetupGenBuffer,DirectFloatBufferRU, $(DIRECT_X_BUF), type := float, RW := R, BO := U))
+$(eval $(call SetupGenBuffer,DirectDoubleBufferU, $(DIRECT_X_BUF), type := double, BO := U))
+$(eval $(call SetupGenBuffer,DirectDoubleBufferRU,$(DIRECT_X_BUF), type := double, RW := R, BO := U))
# Swapped views of direct byte buffers
#
-$(eval $(call SetupGenBuffer,DirectCharBufferS, $(DIRECT_X_BUF), type:=char, BO:=S))
-$(eval $(call SetupGenBuffer,DirectCharBufferRS, $(DIRECT_X_BUF), type:=char, RW:=R, BO:=S))
-$(eval $(call SetupGenBuffer,DirectShortBufferS, $(DIRECT_X_BUF), type:=short, BO:=S))
-$(eval $(call SetupGenBuffer,DirectShortBufferRS, $(DIRECT_X_BUF), type:=short, RW:=R, BO:=S))
-$(eval $(call SetupGenBuffer,DirectIntBufferS, $(DIRECT_X_BUF), type:=int, BO:=S))
-$(eval $(call SetupGenBuffer,DirectIntBufferRS, $(DIRECT_X_BUF), type:=int, RW:=R, BO:=S))
-$(eval $(call SetupGenBuffer,DirectLongBufferS, $(DIRECT_X_BUF), type:=long, BO:=S))
-$(eval $(call SetupGenBuffer,DirectLongBufferRS, $(DIRECT_X_BUF), type:=long, RW:=R, BO:=S))
-$(eval $(call SetupGenBuffer,DirectFloatBufferS, $(DIRECT_X_BUF), type:=float, BO:=S))
-$(eval $(call SetupGenBuffer,DirectFloatBufferRS, $(DIRECT_X_BUF), type:=float, RW:=R, BO:=S))
-$(eval $(call SetupGenBuffer,DirectDoubleBufferS, $(DIRECT_X_BUF), type:=double, BO:=S))
-$(eval $(call SetupGenBuffer,DirectDoubleBufferRS,$(DIRECT_X_BUF), type:=double, RW:=R, BO:=S))
+$(eval $(call SetupGenBuffer,DirectCharBufferS, $(DIRECT_X_BUF), type := char, BO := S))
+$(eval $(call SetupGenBuffer,DirectCharBufferRS, $(DIRECT_X_BUF), type := char, RW := R, BO := S))
+$(eval $(call SetupGenBuffer,DirectShortBufferS, $(DIRECT_X_BUF), type := short, BO := S))
+$(eval $(call SetupGenBuffer,DirectShortBufferRS, $(DIRECT_X_BUF), type := short, RW := R, BO := S))
+$(eval $(call SetupGenBuffer,DirectIntBufferS, $(DIRECT_X_BUF), type := int, BO := S))
+$(eval $(call SetupGenBuffer,DirectIntBufferRS, $(DIRECT_X_BUF), type := int, RW := R, BO := S))
+$(eval $(call SetupGenBuffer,DirectLongBufferS, $(DIRECT_X_BUF), type := long, BO := S))
+$(eval $(call SetupGenBuffer,DirectLongBufferRS, $(DIRECT_X_BUF), type := long, RW := R, BO := S))
+$(eval $(call SetupGenBuffer,DirectFloatBufferS, $(DIRECT_X_BUF), type := float, BO := S))
+$(eval $(call SetupGenBuffer,DirectFloatBufferRS, $(DIRECT_X_BUF), type := float, RW := R, BO := S))
+$(eval $(call SetupGenBuffer,DirectDoubleBufferS, $(DIRECT_X_BUF), type := double, BO := S))
+$(eval $(call SetupGenBuffer,DirectDoubleBufferRS,$(DIRECT_X_BUF), type := double, RW := R, BO := S))
# Big-endian views of byte buffers
#
BYTE_X_BUF := ByteBufferAs-X-Buffer
-$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferB, $(BYTE_X_BUF), type:=char, BO:=B))
-$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferRB, $(BYTE_X_BUF), type:=char, RW:=R, BO:=B))
-$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferB, $(BYTE_X_BUF), type:=short, BO:=B))
-$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferRB, $(BYTE_X_BUF), type:=short, RW:=R, BO:=B))
-$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferB, $(BYTE_X_BUF), type:=int, BO:=B))
-$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferRB, $(BYTE_X_BUF), type:=int, RW:=R, BO:=B))
-$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferB, $(BYTE_X_BUF), type:=long, BO:=B))
-$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferRB, $(BYTE_X_BUF), type:=long, RW:=R, BO:=B))
-$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferB, $(BYTE_X_BUF), type:=float, BO:=B))
-$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferRB, $(BYTE_X_BUF), type:=float, RW:=R, BO:=B))
-$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferB, $(BYTE_X_BUF), type:=double, BO:=B))
-$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferRB,$(BYTE_X_BUF), type:=double, RW:=R, BO:=B))
+$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferB, $(BYTE_X_BUF), type := char, BO := B))
+$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferRB, $(BYTE_X_BUF), type := char, RW := R, BO := B))
+$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferB, $(BYTE_X_BUF), type := short, BO := B))
+$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferRB, $(BYTE_X_BUF), type := short, RW := R, BO := B))
+$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferB, $(BYTE_X_BUF), type := int, BO := B))
+$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferRB, $(BYTE_X_BUF), type := int, RW := R, BO := B))
+$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferB, $(BYTE_X_BUF), type := long, BO := B))
+$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferRB, $(BYTE_X_BUF), type := long, RW := R, BO := B))
+$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferB, $(BYTE_X_BUF), type := float, BO := B))
+$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferRB, $(BYTE_X_BUF), type := float, RW := R, BO := B))
+$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferB, $(BYTE_X_BUF), type := double, BO := B))
+$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferRB,$(BYTE_X_BUF), type := double, RW := R, BO := B))
# Little-endian views of byte buffers
#
-$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferL, $(BYTE_X_BUF), type:=char, BO:=L))
-$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferRL, $(BYTE_X_BUF), type:=char, RW:=R, BO:=L))
-$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferL, $(BYTE_X_BUF), type:=short, BO:=L))
-$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferRL, $(BYTE_X_BUF), type:=short, RW:=R, BO:=L))
-$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferL, $(BYTE_X_BUF), type:=int, BO:=L))
-$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferRL, $(BYTE_X_BUF), type:=int, RW:=R, BO:=L))
-$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferL, $(BYTE_X_BUF), type:=long, BO:=L))
-$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferRL, $(BYTE_X_BUF), type:=long, RW:=R, BO:=L))
-$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferL, $(BYTE_X_BUF), type:=float, BO:=L))
-$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferRL, $(BYTE_X_BUF), type:=float, RW:=R, BO:=L))
-$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferL, $(BYTE_X_BUF), type:=double, BO:=L))
-$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferRL,$(BYTE_X_BUF), type:=double, RW:=R, BO:=L))
+$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferL, $(BYTE_X_BUF), type := char, BO := L))
+$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferRL, $(BYTE_X_BUF), type := char, RW := R, BO := L))
+$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferL, $(BYTE_X_BUF), type := short, BO := L))
+$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferRL, $(BYTE_X_BUF), type := short, RW := R, BO := L))
+$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferL, $(BYTE_X_BUF), type := int, BO := L))
+$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferRL, $(BYTE_X_BUF), type := int, RW := R, BO := L))
+$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferL, $(BYTE_X_BUF), type := long, BO := L))
+$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferRL, $(BYTE_X_BUF), type := long, RW := R, BO := L))
+$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferL, $(BYTE_X_BUF), type := float, BO := L))
+$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferRL, $(BYTE_X_BUF), type := float, RW := R, BO := L))
+$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferL, $(BYTE_X_BUF), type := double, BO := L))
+$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferRL,$(BYTE_X_BUF), type := double, RW := R, BO := L))
###
diff --git a/make/modules/java.base/gensrc/GensrcExceptions.gmk b/make/modules/java.base/gensrc/GensrcExceptions.gmk
index 1c4974b4a28..f3509710a37 100644
--- a/make/modules/java.base/gensrc/GensrcExceptions.gmk
+++ b/make/modules/java.base/gensrc/GensrcExceptions.gmk
@@ -40,7 +40,7 @@ $(GENSRC_EXCEPTIONS_DST)/_the.%.marker: $(GENSRC_EXCEPTIONS_SRC)/%/exceptions \
$(GENSRC_EXCEPTIONS_CMD) $< $(@D)/$* $(LOG_DEBUG)
$(TOUCH) $@
-GENSRC_EXCEPTIONS += $(foreach D,$(GENSRC_EXCEPTIONS_SRC_DIRS),$(GENSRC_EXCEPTIONS_DST)/_the.$(D).marker)
+GENSRC_EXCEPTIONS += $(foreach D, $(GENSRC_EXCEPTIONS_SRC_DIRS), $(GENSRC_EXCEPTIONS_DST)/_the.$(D).marker)
$(GENSRC_EXCEPTIONS): $(BUILD_TOOLS_JDK)
diff --git a/make/modules/java.base/gensrc/GensrcMisc.gmk b/make/modules/java.base/gensrc/GensrcMisc.gmk
index 578adce4e9d..19d7c6dee9d 100644
--- a/make/modules/java.base/gensrc/GensrcMisc.gmk
+++ b/make/modules/java.base/gensrc/GensrcMisc.gmk
@@ -87,7 +87,7 @@ ifneq ($(filter $(TOOLCHAIN_TYPE), gcc clang), )
else ifeq ($(TOOLCHAIN_TYPE), microsoft)
CPP_FLAGS += -nologo
- ifeq ($(OPENJDK_TARGET_CPU),aarch64)
+ ifeq ($(OPENJDK_TARGET_CPU), aarch64)
# cl.exe does only recognize few file extensions as valid (ex: .c, .h, .cpp), so
# make sure *.java.template files are recognized as valid input files
CPP_FILEPREFIX = -Tc
diff --git a/make/modules/java.base/gensrc/GensrcModuleLoaderMap.gmk b/make/modules/java.base/gensrc/GensrcModuleLoaderMap.gmk
index 4ec9ee587cc..ce91cdc861c 100644
--- a/make/modules/java.base/gensrc/GensrcModuleLoaderMap.gmk
+++ b/make/modules/java.base/gensrc/GensrcModuleLoaderMap.gmk
@@ -42,7 +42,7 @@ NATIVE_ACCESS_MODULES_LIST := $(call SubstComma, $(NATIVE_ACCESS_MODULES))
VARDEPS_VALUE := $(BOOT_MODULES_LIST) $(PLATFORM_MODULES_LIST) $(NATIVE_ACCESS_MODULES_LIST)
VARDEPS_FILE := $(call DependOnVariable, VARDEPS_VALUE)
-############################################################################
+################################################################################
$(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/module/ModuleLoaderMap.java: \
$(TOPDIR)/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java \
diff --git a/make/modules/java.base/lib/CoreLibraries.gmk b/make/modules/java.base/lib/CoreLibraries.gmk
index 7fed18491d1..61ac495968a 100644
--- a/make/modules/java.base/lib/CoreLibraries.gmk
+++ b/make/modules/java.base/lib/CoreLibraries.gmk
@@ -35,6 +35,8 @@ endif
$(eval $(call SetupJdkLibrary, BUILD_LIBVERIFY, \
NAME := verify, \
OPTIMIZATION := $(LIBVERIFY_OPTIMIZATION), \
+ DISABLED_WARNINGS_gcc_check_code.c := unused-variable, \
+ DISABLED_WARNINGS_clang_check_code.c := unused-variable, \
EXTRA_HEADER_DIRS := libjava, \
JDK_LIBS := libjvm, \
))
@@ -58,9 +60,10 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJAVA, \
java_props_md.c_CFLAGS := \
-DARCHPROPNAME='"$(OPENJDK_TARGET_CPU_OSARCH)"', \
DISABLED_WARNINGS_gcc_ProcessImpl_md.c := unused-result, \
+ DISABLED_WARNINGS_clang_TimeZone_md.c := unused-variable, \
JDK_LIBS := libjvm, \
LIBS_linux := $(LIBDL), \
- LIBS_aix := $(LIBDL) $(LIBM),\
+ LIBS_aix := $(LIBDL) $(LIBM), \
LIBS_macosx := \
-framework CoreFoundation \
-framework Foundation \
@@ -92,6 +95,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBZIP, \
DISABLED_WARNINGS_gcc_zip_util.c := unused-function, \
DISABLED_WARNINGS_clang := deprecated-non-prototype, \
DISABLED_WARNINGS_clang_gzwrite.c := format-nonliteral, \
+ DISABLED_WARNINGS_clang_zip_util.c := unused-function, \
JDK_LIBS := libjava libjvm, \
LIBS_unix := $(LIBZ_LIBS), \
))
@@ -108,6 +112,12 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJIMAGE, \
OPTIMIZATION := LOW, \
EXTRA_HEADER_DIRS := libjava, \
CFLAGS_unix := -UDEBUG, \
+ DISABLED_WARNINGS_gcc_imageDecompressor.cpp := unused-variable, \
+ DISABLED_WARNINGS_gcc_imageFile.cpp := unused-const-variable \
+ unused-variable, \
+ DISABLED_WARNINGS_clang_imageDecompressor.cpp := unused-variable, \
+ DISABLED_WARNINGS_clang_imageFile.cpp := unused-private-field \
+ unused-variable, \
LDFLAGS := $(LDFLAGS_CXX_JDK), \
JDK_LIBS := libjvm, \
LIBS_unix := $(LIBDL), \
@@ -167,8 +177,10 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJLI, \
EXTRA_HEADER_DIRS := libjvm, \
OPTIMIZATION := HIGH, \
CFLAGS := $(LIBJLI_CFLAGS) $(LIBZ_CFLAGS), \
- DISABLED_WARNINGS_gcc := unused-function, \
- DISABLED_WARNINGS_clang := format-nonliteral deprecated-non-prototype, \
+ DISABLED_WARNINGS_gcc := unused-function unused-variable, \
+ DISABLED_WARNINGS_clang := deprecated-non-prototype format-nonliteral \
+ unused-function, \
+ DISABLED_WARNINGS_clang_java_md_macosx.m := unused-variable, \
LIBS_unix := $(LIBZ_LIBS), \
LIBS_linux := $(LIBDL) -lpthread, \
LIBS_macosx := \
diff --git a/make/modules/java.desktop/Lib.gmk b/make/modules/java.desktop/Lib.gmk
index 01b51fd4788..18f386ae6b4 100644
--- a/make/modules/java.desktop/Lib.gmk
+++ b/make/modules/java.desktop/Lib.gmk
@@ -64,8 +64,11 @@ ifeq ($(call isTargetOs, aix), false)
EXTRA_HEADER_DIRS := java.base:libjava, \
CFLAGS := $(LIBJSOUND_CFLAGS), \
CXXFLAGS := $(LIBJSOUND_CFLAGS), \
- DISABLED_WARNINGS_gcc := undef, \
- DISABLED_WARNINGS_clang := undef, \
+ DISABLED_WARNINGS_gcc := undef unused-variable, \
+ DISABLED_WARNINGS_clang := undef unused-variable, \
+ DISABLED_WARNINGS_clang_PLATFORM_API_MacOSX_MidiUtils.c := \
+ unused-but-set-variable, \
+ DISABLED_WARNINGS_clang_DirectAudioDevice.c := unused-function, \
LIBS_linux := $(ALSA_LIBS), \
LIBS_macosx := \
-framework AudioToolbox \
diff --git a/make/modules/java.desktop/lib/AwtLibraries.gmk b/make/modules/java.desktop/lib/AwtLibraries.gmk
index 11f92585bd9..b2904f961fd 100644
--- a/make/modules/java.desktop/lib/AwtLibraries.gmk
+++ b/make/modules/java.desktop/lib/AwtLibraries.gmk
@@ -106,12 +106,14 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBAWT, \
CXXFLAGS := $(LIBAWT_CFLAGS) $(X_CFLAGS), \
CFLAGS_gcc := -fgcse-after-reload, \
EXTRA_HEADER_DIRS := $(LIBAWT_EXTRA_HEADER_DIRS), \
+ DISABLED_WARNINGS_gcc := unused-but-set-variable unused-variable, \
DISABLED_WARNINGS_gcc_awt_LoadLibrary.c := unused-result, \
DISABLED_WARNINGS_gcc_debug_mem.c := format-nonliteral, \
DISABLED_WARNINGS_gcc_ProcessPath.c := maybe-uninitialized, \
DISABLED_WARNINGS_gcc_Region.c := maybe-uninitialized, \
DISABLED_WARNINGS_gcc_SurfaceData.c := unused-value, \
DISABLED_WARNINGS_gcc_TransformHelper.c := sign-compare, \
+ DISABLED_WARNINGS_clang := unused-but-set-variable unused-variable, \
DISABLED_WARNINGS_clang_awt_ImagingLib.c := deprecated-non-prototype, \
DISABLED_WARNINGS_clang_debug_trace.c := format-nonliteral, \
DISABLED_WARNINGS_clang_Trace.c := format-nonliteral, \
@@ -125,7 +127,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBAWT, \
JDK_LIBS := java.base:libjava java.base:libjvm, \
LIBS_unix := $(LIBM), \
LIBS_linux := $(LIBDL), \
- LIBS_aix := $(LIBDL),\
+ LIBS_aix := $(LIBDL), \
LIBS_macosx := \
-framework ApplicationServices \
-framework AudioToolbox \
@@ -178,8 +180,12 @@ ifeq ($(call isTargetOs, windows macosx), false)
CFLAGS := -DHEADLESS=true $(CUPS_CFLAGS) $(FONTCONFIG_CFLAGS) \
$(X_CFLAGS), \
EXTRA_HEADER_DIRS := $(LIBAWT_HEADLESS_EXTRA_HEADER_DIRS), \
+ DISABLED_WARNINGS_gcc := unused-variable, \
+ DISABLED_WARNINGS_clang := unused-variable, \
DISABLED_WARNINGS_gcc_X11Renderer.c := unused-function, \
DISABLED_WARNINGS_gcc_X11SurfaceData.c := unused-function, \
+ DISABLED_WARNINGS_clang_X11Renderer.c := unused-function, \
+ DISABLED_WARNINGS_clang_X11SurfaceData.c := unused-function, \
JDK_LIBS := libawt java.base:libjava, \
LIBS_linux := $(LIBDL) $(LIBM), \
STATIC_LIB_EXCLUDE_OBJS := $(LIBAWT_HEADLESS_STATIC_EXCLUDE_OBJS), \
@@ -234,10 +240,10 @@ ifeq ($(call isTargetOs, windows macosx)+$(ENABLE_HEADLESS_ONLY), false+false)
OPTIMIZATION := LOW, \
CFLAGS := -DXAWT -DXAWT_HACK $(LIBAWT_XAWT_CFLAGS) \
$(FONTCONFIG_CFLAGS) $(CUPS_CFLAGS) $(X_CFLAGS), \
- DISABLED_WARNINGS_gcc := int-to-pointer-cast, \
+ DISABLED_WARNINGS_gcc := int-to-pointer-cast unused-variable, \
+ DISABLED_WARNINGS_clang := unused-variable, \
DISABLED_WARNINGS_gcc_awt_Taskbar.c := parentheses, \
DISABLED_WARNINGS_gcc_GLXSurfaceData.c := unused-function, \
- DISABLED_WARNINGS_gcc_gtk2_interface.c := parentheses type-limits, \
DISABLED_WARNINGS_gcc_gtk3_interface.c := parentheses type-limits \
unused-function, \
DISABLED_WARNINGS_gcc_OGLBufImgOps.c := format-nonliteral, \
@@ -245,30 +251,31 @@ ifeq ($(call isTargetOs, windows macosx)+$(ENABLE_HEADLESS_ONLY), false+false)
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_X11Color.c := unused-but-set-variable, \
DISABLED_WARNINGS_gcc_X11SurfaceData.c := implicit-fallthrough \
- pointer-to-int-cast, \
+ pointer-to-int-cast unused-but-set-variable, \
+ DISABLED_WARNINGS_gcc_X11TextRenderer_md.c := unused-but-set-variable, \
DISABLED_WARNINGS_gcc_XlibWrapper.c := type-limits pointer-to-int-cast, \
DISABLED_WARNINGS_gcc_XRBackendNative.c := maybe-uninitialized, \
DISABLED_WARNINGS_gcc_XToolkit.c := unused-result, \
DISABLED_WARNINGS_gcc_XWindow.c := unused-function, \
DISABLED_WARNINGS_clang_awt_Taskbar.c := parentheses, \
- DISABLED_WARNINGS_clang_gtk2_interface.c := parentheses, \
- DISABLED_WARNINGS_clang_gtk3_interface.c := parentheses, \
+ DISABLED_WARNINGS_clang_gtk3_interface.c := unused-function parentheses, \
+ DISABLED_WARNINGS_clang_GLXSurfaceData.c := unused-function, \
DISABLED_WARNINGS_clang_OGLBufImgOps.c := format-nonliteral, \
DISABLED_WARNINGS_clang_OGLPaints.c := format-nonliteral, \
DISABLED_WARNINGS_clang_screencast_pipewire.c := format-nonliteral, \
DISABLED_WARNINGS_clang_sun_awt_X11_GtkFileDialogPeer.c := parentheses, \
+ DISABLED_WARNINGS_clang_XWindow.c := unused-function, \
DISABLED_WARNINGS_clang_aix := deprecated-non-prototype, \
DISABLED_WARNINGS_clang_aix_awt_Taskbar.c := parentheses, \
DISABLED_WARNINGS_clang_aix_OGLPaints.c := format-nonliteral, \
DISABLED_WARNINGS_clang_aix_OGLBufImgOps.c := format-nonliteral, \
- DISABLED_WARNINGS_clang_aix_gtk2_interface.c := parentheses \
- logical-op-parentheses, \
- DISABLED_WARNINGS_clang_aix_gtk3_interface.c := parentheses \
+ DISABLED_WARNINGS_clang_aix_gtk3_interface.c := unused-function parentheses \
logical-op-parentheses, \
DISABLED_WARNINGS_clang_aix_sun_awt_X11_GtkFileDialogPeer.c := \
parentheses, \
- DISABLED_WARNINGS_clang_aix_awt_InputMethod.c := sign-compare, \
+ DISABLED_WARNINGS_clang_aix_awt_InputMethod.c := unused-function sign-compare, \
JDK_LIBS := libawt java.base:libjava, \
LIBS_unix := $(LIBDL) $(LIBM) $(X_LIBS) -lX11 -lXext -lXi -lXrender \
-lXtst, \
@@ -312,9 +319,10 @@ ifeq ($(call isTargetOs, macosx), true)
EXCLUDES := $(LIBAWT_LWAWT_EXCLUDES), \
OPTIMIZATION := LOW, \
EXTRA_HEADER_DIRS := $(LIBAWT_LWAWT_EXTRA_HEADER_DIRS), \
- DISABLED_WARNINGS_clang := incomplete-implementation \
- deprecated-declarations objc-method-access \
- incompatible-pointer-types extra-tokens sign-compare undef, \
+ DISABLED_WARNINGS_clang := deprecated-declarations extra-tokens \
+ incompatible-pointer-types incomplete-implementation \
+ objc-method-access sign-compare undef unused-function \
+ unused-variable, \
DISABLED_WARNINGS_clang_AWTWindow.m := bitwise-op-parentheses, \
DISABLED_WARNINGS_clang_CFileDialog.m := semicolon-before-method-body, \
DISABLED_WARNINGS_clang_CGGlyphImages.m := pointer-arith, \
diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk
index f0239695369..31323021780 100644
--- a/make/modules/java.desktop/lib/ClientLibraries.gmk
+++ b/make/modules/java.desktop/lib/ClientLibraries.gmk
@@ -46,6 +46,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBMLIB_IMAGE, \
CFLAGS := -D__USE_J2D_NAMES -D__MEDIALIB_OLD_NAMES -DMLIB_NO_LIBSUNMATH \
$(LIBMLIB_IMAGE_CFLAGS), \
DISABLED_WARNINGS_gcc := unused-function, \
+ DISABLED_WARNINGS_clang_mlib_ImageCreate.c := unused-function, \
LIBS_unix := $(LIBDL) $(LIBM), \
))
@@ -84,8 +85,8 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBLCMS, \
libawt/java2d \
java.base:libjvm, \
HEADERS_FROM_SRC := $(LIBLCMS_HEADERS_FROM_SRC), \
- DISABLED_WARNINGS_gcc := format-nonliteral type-limits \
- stringop-truncation, \
+ DISABLED_WARNINGS_gcc := format-nonliteral stringop-truncation type-limits \
+ unused-variable, \
DISABLED_WARNINGS_clang := format-nonliteral, \
JDK_LIBS := libawt java.base:libjava, \
LIBS_unix := $(LCMS_LIBS) $(LIBM), \
@@ -100,7 +101,8 @@ TARGETS += $(BUILD_LIBLCMS)
ifeq ($(USE_EXTERNAL_LIBJPEG), true)
LIBJAVAJPEG_INCLUDE_FILES := \
imageioJPEG.c \
- jpegdecoder.c
+ jpegdecoder.c \
+ #
# If we're using an external library, we can't include our own SRC path
# as includes, instead the system headers should be used.
LIBJAVAJPEG_HEADERS_FROM_SRC := false
@@ -118,9 +120,11 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJAVAJPEG, \
INCLUDE_FILES := $(LIBJAVAJPEG_INCLUDE_FILES), \
OPTIMIZATION := HIGHEST, \
HEADERS_FROM_SRC := $(LIBJAVAJPEG_HEADERS_FROM_SRC), \
- DISABLED_WARNINGS_gcc_imageioJPEG.c := clobbered array-bounds, \
+ DISABLED_WARNINGS_gcc_imageioJPEG.c := array-bounds clobbered \
+ unused-but-set-variable, \
DISABLED_WARNINGS_gcc_jcmaster.c := implicit-fallthrough, \
DISABLED_WARNINGS_gcc_jdphuff.c := shift-negative-value, \
+ DISABLED_WARNINGS_clang_imageioJPEG.c := unused-but-set-variable, \
JDK_LIBS := java.base:libjava, \
LIBS := $(LIBJPEG_LIBS), \
))
@@ -224,14 +228,17 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false)
maybe-uninitialized, \
DISABLED_WARNINGS_gcc_splashscreen_impl.c := implicit-fallthrough \
sign-compare unused-function, \
- DISABLED_WARNINGS_gcc_splashscreen_sys.c := type-limits unused-result, \
+ DISABLED_WARNINGS_gcc_splashscreen_sys.c := type-limits \
+ unused-but-set-variable unused-result unused-variable, \
DISABLED_WARNINGS_clang := deprecated-non-prototype, \
DISABLED_WARNINGS_clang_dgif_lib.c := sign-compare, \
DISABLED_WARNINGS_clang_gzwrite.c := format-nonliteral, \
- DISABLED_WARNINGS_clang_splashscreen_impl.c := sign-compare, \
+ DISABLED_WARNINGS_clang_splashscreen_impl.c := sign-compare \
+ unused-but-set-variable unused-function, \
DISABLED_WARNINGS_clang_splashscreen_png.c := \
incompatible-pointer-types, \
- DISABLED_WARNINGS_clang_splashscreen_sys.m := deprecated-declarations, \
+ DISABLED_WARNINGS_clang_splashscreen_sys.m := deprecated-declarations \
+ unused-variable unused-but-set-variable, \
DISABLED_WARNINGS_microsoft_dgif_lib.c := 4018 4267, \
DISABLED_WARNINGS_microsoft_splashscreen_impl.c := 4018 4267 4244, \
DISABLED_WARNINGS_microsoft_splashscreen_png.c := 4267, \
@@ -279,50 +286,51 @@ endif
################################################################################
ifeq ($(USE_EXTERNAL_HARFBUZZ), true)
- LIBFONTMANAGER_EXTRA_SRC =
- LIBFONTMANAGER_LIBS += $(HARFBUZZ_LIBS)
- LIBFONTMANAGER_CFLAGS += $(HARFBUZZ_CFLAGS)
+ LIBFONTMANAGER_EXTRA_SRC =
+ LIBFONTMANAGER_LIBS += $(HARFBUZZ_LIBS)
+ LIBFONTMANAGER_CFLAGS += $(HARFBUZZ_CFLAGS)
else
- LIBFONTMANAGER_EXTRA_SRC = libharfbuzz
+ LIBFONTMANAGER_EXTRA_SRC = libharfbuzz
- ifeq ($(call isTargetOs, windows), false)
- HARFBUZZ_CFLAGS += -DGETPAGESIZE -DHAVE_MPROTECT -DHAVE_PTHREAD \
+ ifeq ($(call isTargetOs, windows), false)
+ HARFBUZZ_CFLAGS += -DGETPAGESIZE -DHAVE_MPROTECT -DHAVE_PTHREAD \
-DHAVE_SYSCONF -DHAVE_SYS_MMAN_H -DHAVE_UNISTD_H \
-DHB_NO_PRAGMA_GCC_DIAGNOSTIC
- endif
- ifeq ($(call isTargetOs, linux macosx), true)
- HARFBUZZ_CFLAGS += -DHAVE_INTEL_ATOMIC_PRIMITIVES -DHB_NO_VISIBILITY
- endif
-
- # hb-ft.cc is not presently needed, and requires freetype 2.4.2 or later.
- # hb-subset and hb-style APIs are not needed, excluded to cut on compilation
- # time.
- LIBFONTMANAGER_EXCLUDE_FILES += gsubgpos-context.cc hb-ft.cc hb-style.cc \
+ endif
+ ifeq ($(call isTargetOs, linux macosx), true)
+ HARFBUZZ_CFLAGS += -DHAVE_INTEL_ATOMIC_PRIMITIVES -DHB_NO_VISIBILITY
+ endif
+
+ # hb-ft.cc is not presently needed, and requires freetype 2.4.2 or later.
+ # hb-subset and hb-style APIs are not needed, excluded to cut on compilation
+ # time.
+ LIBFONTMANAGER_EXCLUDE_FILES += gsubgpos-context.cc hb-ft.cc hb-style.cc \
hb-subset-cff-common.cc hb-subset-cff1.cc hb-subset-cff2.cc \
hb-subset-input.cc hb-subset-instancer-solver.cc hb-subset-plan.cc \
hb-subset.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 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+.
- # maybe-uninitialized required for GCC 8 builds. Not required for GCC 9+.
- # calloc-transposed-args required for GCC 14 builds. (fixed upstream in
- # Harfbuzz 032c931e1c0cfb20f18e5acb8ba005775242bd92)
- HARFBUZZ_DISABLED_WARNINGS_CXX_gcc := class-memaccess noexcept-type \
- expansion-to-defined dangling-reference maybe-uninitialized \
- calloc-transposed-args
- HARFBUZZ_DISABLED_WARNINGS_clang := missing-field-initializers \
- range-loop-analysis
- HARFBUZZ_DISABLED_WARNINGS_microsoft := 4267 4244
-
- LIBFONTMANAGER_CFLAGS += $(HARFBUZZ_CFLAGS)
+ # 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 parentheses \
+ unused-variable
+ # 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+.
+ # maybe-uninitialized required for GCC 8 builds. Not required for GCC 9+.
+ # calloc-transposed-args required for GCC 14 builds. (fixed upstream in
+ # Harfbuzz 032c931e1c0cfb20f18e5acb8ba005775242bd92)
+ HARFBUZZ_DISABLED_WARNINGS_CXX_gcc := class-memaccess noexcept-type \
+ expansion-to-defined dangling-reference maybe-uninitialized \
+ calloc-transposed-args
+ HARFBUZZ_DISABLED_WARNINGS_clang := missing-field-initializers \
+ range-loop-analysis unused-variable
+ HARFBUZZ_DISABLED_WARNINGS_microsoft := 4267 4244
+
+ LIBFONTMANAGER_CFLAGS += $(HARFBUZZ_CFLAGS)
endif
LIBFONTMANAGER_EXTRA_HEADER_DIRS := \
@@ -384,7 +392,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBFONTMANAGER, \
DISABLED_WARNINGS_clang := $(HARFBUZZ_DISABLED_WARNINGS_clang), \
DISABLED_WARNINGS_microsoft := $(HARFBUZZ_DISABLED_WARNINGS_microsoft), \
LDFLAGS := $(LDFLAGS_CXX_JDK), \
- LDFLAGS_FILTER_OUT :=-Wl$(COMMA)-z$(COMMA)defs, \
+ LDFLAGS_FILTER_OUT := -Wl$(COMMA)-z$(COMMA)defs, \
LDFLAGS_aix := -Wl$(COMMA)-berok, \
JDK_LIBS := libawt java.base:libjava $(LIBFONTMANAGER_JDK_LIBS), \
JDK_LIBS_macosx := libawt_lwawt, \
diff --git a/make/modules/java.management/Lib.gmk b/make/modules/java.management/Lib.gmk
index 3d2e42e42ec..b9f79da4516 100644
--- a/make/modules/java.management/Lib.gmk
+++ b/make/modules/java.management/Lib.gmk
@@ -37,8 +37,10 @@ endif
$(eval $(call SetupJdkLibrary, BUILD_LIBMANAGEMENT, \
NAME := management, \
OPTIMIZATION := $(LIBMANAGEMENT_OPTIMIZATION), \
+ DISABLED_WARNINGS_gcc_VMManagementImpl.c := unused-variable, \
+ DISABLED_WARNINGS_clang_VMManagementImpl.c := unused-variable, \
JDK_LIBS := java.base:libjava java.base:libjvm, \
- LIBS_aix := -lperfstat,\
+ LIBS_aix := -lperfstat, \
LIBS_windows := advapi32.lib psapi.lib, \
))
diff --git a/make/modules/java.security.jgss/Lib.gmk b/make/modules/java.security.jgss/Lib.gmk
index 4cef4576dea..2c827b84109 100644
--- a/make/modules/java.security.jgss/Lib.gmk
+++ b/make/modules/java.security.jgss/Lib.gmk
@@ -33,8 +33,8 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJ2GSS, \
NAME := j2gss, \
OPTIMIZATION := LOW, \
EXTRA_HEADER_DIRS := java.base:libjava, \
- DISABLED_WARNINGS_gcc := undef, \
- DISABLED_WARNINGS_clang := undef, \
+ DISABLED_WARNINGS_gcc := undef unused-but-set-variable, \
+ DISABLED_WARNINGS_clang := undef unused-but-set-variable, \
LIBS_unix := $(LIBDL), \
))
diff --git a/make/modules/jdk.accessibility/Launcher.gmk b/make/modules/jdk.accessibility/Launcher.gmk
index 6ea52b244d7..2499cf56616 100644
--- a/make/modules/jdk.accessibility/Launcher.gmk
+++ b/make/modules/jdk.accessibility/Launcher.gmk
@@ -93,7 +93,7 @@ ifeq ($(call isTargetOs, windows), true)
LIBS_windows := advapi32.lib comctl32.lib gdi32.lib user32.lib, \
VERSIONINFO_RESOURCE := \
$(ACCESSIBILITY_SRCDIR)/jaccesswalker/jaccesswalkerWindow.rc, \
- ))
+ ))
TARGETS += $$(BUILD_JACCESSWALKER$1)
endef
diff --git a/make/modules/jdk.crypto.cryptoki/Lib.gmk b/make/modules/jdk.crypto.cryptoki/Lib.gmk
index 9a21177af4f..ec80aaf46b4 100644
--- a/make/modules/jdk.crypto.cryptoki/Lib.gmk
+++ b/make/modules/jdk.crypto.cryptoki/Lib.gmk
@@ -33,6 +33,8 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJ2PKCS11, \
NAME := j2pkcs11, \
OPTIMIZATION := LOW, \
EXTRA_HEADER_DIRS := java.base:libjava, \
+ DISABLED_WARNINGS_gcc_p11_md.c := unused-variable, \
+ DISABLED_WARNINGS_clang_p11_md.c := unused-variable, \
DISABLED_WARNINGS_clang_p11_util.c := format-nonliteral, \
LIBS_unix := $(LIBDL), \
))
diff --git a/make/modules/jdk.hotspot.agent/Lib.gmk b/make/modules/jdk.hotspot.agent/Lib.gmk
index 48429a9004d..12f1c1f2a90 100644
--- a/make/modules/jdk.hotspot.agent/Lib.gmk
+++ b/make/modules/jdk.hotspot.agent/Lib.gmk
@@ -60,9 +60,10 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBSAPROC, \
EXTRA_HEADER_DIRS := java.base:libjvm, \
DISABLED_WARNINGS_gcc := sign-compare, \
DISABLED_WARNINGS_gcc_ps_core.c := pointer-arith, \
- DISABLED_WARNINGS_clang_ps_core.c := pointer-arith, \
DISABLED_WARNINGS_clang := sign-compare, \
DISABLED_WARNINGS_clang_libproc_impl.c := format-nonliteral, \
+ DISABLED_WARNINGS_clang_MacosxDebuggerLocal.m := unused-variable, \
+ DISABLED_WARNINGS_clang_ps_core.c := pointer-arith, \
DISABLED_WARNINGS_clang_sadis.c := format-nonliteral, \
CFLAGS := $(LIBSAPROC_CFLAGS), \
CXXFLAGS := $(LIBSAPROC_CFLAGS) $(LIBSAPROC_CXXFLAGS), \
diff --git a/make/modules/jdk.incubator.vector/Lib.gmk b/make/modules/jdk.incubator.vector/Lib.gmk
index 0620549f05c..bf6ace6f97f 100644
--- a/make/modules/jdk.incubator.vector/Lib.gmk
+++ b/make/modules/jdk.incubator.vector/Lib.gmk
@@ -37,3 +37,21 @@ ifeq ($(call isTargetOs, linux windows)+$(call isTargetCpu, x86_64)+$(INCLUDE_CO
TARGETS += $(BUILD_LIBJSVML)
endif
+
+################################################################################
+## Build libsleef
+################################################################################
+
+ifeq ($(call isTargetOs, linux)+$(call isTargetCpu, riscv64)+$(INCLUDE_COMPILER2), true+true+true)
+ $(eval $(call SetupJdkLibrary, BUILD_LIBSLEEF, \
+ NAME := sleef, \
+ OPTIMIZATION := HIGH, \
+ SRC := libsleef/lib, \
+ EXTRA_SRC := libsleef/generated, \
+ DISABLED_WARNINGS_gcc := unused-function sign-compare tautological-compare ignored-qualifiers, \
+ DISABLED_WARNINGS_clang := unused-function sign-compare tautological-compare ignored-qualifiers, \
+ CFLAGS := -march=rv64gcv, \
+ ))
+
+ TARGETS += $(BUILD_LIBSLEEF)
+endif
diff --git a/make/modules/jdk.javadoc/Gensrc.gmk b/make/modules/jdk.javadoc/Gensrc.gmk
index 7aa92545fee..0d25ff61e92 100644
--- a/make/modules/jdk.javadoc/Gensrc.gmk
+++ b/make/modules/jdk.javadoc/Gensrc.gmk
@@ -26,7 +26,7 @@
include GensrcCommon.gmk
include GensrcProperties.gmk
-$(eval $(call SetupVersionProperties, JAVADOC_VERSION,\
+$(eval $(call SetupVersionProperties, JAVADOC_VERSION, \
jdk/javadoc/internal/tool/resources/version.properties))
$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
diff --git a/make/modules/jdk.jdeps/Gensrc.gmk b/make/modules/jdk.jdeps/Gensrc.gmk
index a81297348f3..cb9a27908ce 100644
--- a/make/modules/jdk.jdeps/Gensrc.gmk
+++ b/make/modules/jdk.jdeps/Gensrc.gmk
@@ -29,7 +29,7 @@ include GensrcProperties.gmk
$(eval $(call SetupVersionProperties, JAVAP_VERSION, \
com/sun/tools/javap/resources/version.properties))
-$(eval $(call SetupVersionProperties, JDEPS_VERSION,\
+$(eval $(call SetupVersionProperties, JDEPS_VERSION, \
com/sun/tools/jdeps/resources/version.properties))
$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
diff --git a/make/modules/jdk.jdwp.agent/Lib.gmk b/make/modules/jdk.jdwp.agent/Lib.gmk
index d83ff06f786..53b48cc7c45 100644
--- a/make/modules/jdk.jdwp.agent/Lib.gmk
+++ b/make/modules/jdk.jdwp.agent/Lib.gmk
@@ -52,16 +52,25 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJDWP, \
NAME := jdwp, \
OPTIMIZATION := LOW, \
CFLAGS := -DJDWP_LOGGING, \
+ DISABLED_WARNINGS_gcc_eventFilter.c := unused-variable, \
DISABLED_WARNINGS_gcc_SDE.c := unused-function, \
+ DISABLED_WARNINGS_gcc_threadControl.c := unused-but-set-variable \
+ unused-variable, \
+ DISABLED_WARNINGS_gcc_utf_util.c := unused-but-set-variable, \
DISABLED_WARNINGS_clang_error_messages.c := format-nonliteral, \
+ DISABLED_WARNINGS_clang_eventFilter.c := unused-variable, \
DISABLED_WARNINGS_clang_EventRequestImpl.c := self-assign, \
DISABLED_WARNINGS_clang_inStream.c := sometimes-uninitialized, \
DISABLED_WARNINGS_clang_log_messages.c := format-nonliteral, \
+ DISABLED_WARNINGS_clang_SDE.c := unused-function, \
+ DISABLED_WARNINGS_clang_threadControl.c := unused-but-set-variable \
+ unused-variable, \
+ DISABLED_WARNINGS_clang_utf_util.c := unused-but-set-variable, \
EXTRA_HEADER_DIRS := \
include \
libjdwp/export \
- java.base:libjava \
- java.base:libjvm, \
+ java.base:libjava, \
+ JDK_LIBS := java.base:libjvm, \
LIBS_linux := $(LIBDL), \
LIBS_macosx := -liconv, \
LIBS_aix := -liconv, \
diff --git a/make/modules/jdk.jlink/Launcher.gmk b/make/modules/jdk.jlink/Launcher.gmk
index f0543ef73b8..d4279065193 100644
--- a/make/modules/jdk.jlink/Launcher.gmk
+++ b/make/modules/jdk.jlink/Launcher.gmk
@@ -29,7 +29,7 @@ include LauncherCommon.gmk
## Build jimage
################################################################################
-$(eval $(call SetupBuildLauncher, jimage,\
+$(eval $(call SetupBuildLauncher, jimage, \
MAIN_CLASS := jdk.tools.jimage.Main, \
CFLAGS := -DENABLE_ARG_FILES, \
))
@@ -38,7 +38,7 @@ $(eval $(call SetupBuildLauncher, jimage,\
## Build jlink
################################################################################
-$(eval $(call SetupBuildLauncher, jlink,\
+$(eval $(call SetupBuildLauncher, jlink, \
MAIN_CLASS := jdk.tools.jlink.internal.Main, \
JAVA_ARGS := --add-modules ALL-DEFAULT, \
CFLAGS := -DENABLE_ARG_FILES -DEXPAND_CLASSPATH_WILDCARDS, \
@@ -48,7 +48,7 @@ $(eval $(call SetupBuildLauncher, jlink,\
## Build jmod
################################################################################
-$(eval $(call SetupBuildLauncher, jmod,\
+$(eval $(call SetupBuildLauncher, jmod, \
MAIN_CLASS := jdk.tools.jmod.Main, \
CFLAGS := -DENABLE_ARG_FILES -DEXPAND_CLASSPATH_WILDCARDS, \
))
diff --git a/make/modules/jdk.jpackage/Lib.gmk b/make/modules/jdk.jpackage/Lib.gmk
index 5ead47cd73c..75548133019 100644
--- a/make/modules/jdk.jpackage/Lib.gmk
+++ b/make/modules/jdk.jpackage/Lib.gmk
@@ -53,8 +53,9 @@ $(eval $(call SetupJdkExecutable, BUILD_JPACKAGEAPPLAUNCHER, \
EXTRA_SRC := common, \
INCLUDE_FILES := $(JPACKAGEAPPLAUNCHER_INCLUDE_FILES), \
OPTIMIZATION := LOW, \
- DISABLED_WARNINGS_clang_LinuxPackage.c := format-nonliteral, \
DISABLED_WARNINGS_clang_JvmLauncherLib.c := format-nonliteral, \
+ DISABLED_WARNINGS_clang_LinuxPackage.c := format-nonliteral, \
+ DISABLED_WARNINGS_clang_Log.cpp := unused-const-variable, \
CFLAGS_FILTER_OUT := -MD, \
CXXFLAGS_FILTER_OUT := -MD, \
CFLAGS_macosx := -Wno-format-nonliteral, \
@@ -89,6 +90,7 @@ ifeq ($(call isTargetOs, linux), true)
EXCLUDE_FILES := LinuxLauncher.c LinuxPackage.c, \
LINK_TYPE := C++, \
OPTIMIZATION := LOW, \
+ DISABLED_WARNINGS_gcc_Log.cpp := unused-const-variable, \
DISABLED_WARNINGS_clang_JvmLauncherLib.c := format-nonliteral, \
DISABLED_WARNINGS_clang_tstrings.cpp := format-nonliteral, \
LD_SET_ORIGIN := false, \
diff --git a/make/modules/jdk.management/Lib.gmk b/make/modules/jdk.management/Lib.gmk
index 8d7fae64872..cb65b37bda8 100644
--- a/make/modules/jdk.management/Lib.gmk
+++ b/make/modules/jdk.management/Lib.gmk
@@ -44,10 +44,12 @@ endif
$(eval $(call SetupJdkLibrary, BUILD_LIBMANAGEMENT_EXT, \
NAME := management_ext, \
OPTIMIZATION := $(LIBMANAGEMENT_EXT_OPTIMIZATION), \
+ DISABLED_WARNINGS_gcc_DiagnosticCommandImpl.c := unused-variable, \
+ DISABLED_WARNINGS_clang_DiagnosticCommandImpl.c := unused-variable, \
DISABLED_WARNINGS_clang_UnixOperatingSystem.c := format-nonliteral, \
CFLAGS := $(LIBMANAGEMENT_EXT_CFLAGS), \
JDK_LIBS := java.base:libjava java.base:libjvm, \
- LIBS_aix := -lperfstat,\
+ LIBS_aix := -lperfstat, \
LIBS_windows := advapi32.lib psapi.lib, \
))
diff --git a/make/test/BuildMicrobenchmark.gmk b/make/test/BuildMicrobenchmark.gmk
index 32d26be2270..700aac3c9c6 100644
--- a/make/test/BuildMicrobenchmark.gmk
+++ b/make/test/BuildMicrobenchmark.gmk
@@ -94,6 +94,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \
TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \
SMALL_JAVA := false, \
CLASSPATH := $(JMH_COMPILE_JARS), \
+ CREATE_API_DIGEST := true, \
DISABLED_WARNINGS := restricted this-escape processing rawtypes removal cast \
serial preview dangling-doc-comments, \
SRC := $(MICROBENCHMARK_SRC), \
@@ -148,7 +149,7 @@ $(eval $(call SetupJarArchive, BUILD_JDK_JAR, \
SRCS := $(MICROBENCHMARK_CLASSES) $(JMH_UNPACKED_DIR), \
BIN := $(MICROBENCHMARK_JAR_BIN), \
SUFFIXES := .*, \
- EXCLUDE_FILES:= _the.BUILD_JDK_MICROBENCHMARK_batch \
+ EXCLUDE_FILES := _the.BUILD_JDK_MICROBENCHMARK_batch \
_the.BUILD_JDK_MICROBENCHMARK.vardeps _unpacked.marker, \
EXTRA_MANIFEST_ATTR := $(MICROBENCHMARK_MANIFEST), \
JARMAIN := org.openjdk.jmh.Main, \
diff --git a/make/test/BuildTestLib.gmk b/make/test/BuildTestLib.gmk
index d48f263f6f9..dceae073ff3 100644
--- a/make/test/BuildTestLib.gmk
+++ b/make/test/BuildTestLib.gmk
@@ -64,7 +64,7 @@ $(eval $(call SetupJavaCompilation, BUILD_TEST_LIB_JAR, \
BIN := $(TEST_LIB_SUPPORT)/test-lib_classes, \
HEADERS := $(TEST_LIB_SUPPORT)/test-lib_headers, \
JAR := $(TEST_LIB_SUPPORT)/test-lib.jar, \
- DISABLED_WARNINGS := try deprecation rawtypes unchecked serial cast removal preview dangling-doc-comments, \
+ DISABLED_WARNINGS := try deprecation rawtypes unchecked serial cast removal preview restricted dangling-doc-comments, \
JAVAC_FLAGS := --add-exports java.base/sun.security.util=ALL-UNNAMED \
--add-exports java.base/jdk.internal.classfile=ALL-UNNAMED \
--add-exports java.base/jdk.internal.classfile.attribute=ALL-UNNAMED \
diff --git a/make/test/JtregNativeHotspot.gmk b/make/test/JtregNativeHotspot.gmk
index ecc7e34c917..97f2f12cb76 100644
--- a/make/test/JtregNativeHotspot.gmk
+++ b/make/test/JtregNativeHotspot.gmk
@@ -59,77 +59,93 @@ VM_TESTBASE_DIR := $(TOPDIR)/test/hotspot/jtreg/vmTestbase
VM_SHARE_INCLUDES := \
-I$(VM_TESTBASE_DIR)/vm/share \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
- -I$(VM_TESTBASE_DIR)/nsk/share/jni
+ -I$(VM_TESTBASE_DIR)/nsk/share/jni \
+ #
NSK_MONITORING_INCLUDES := \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
- -I$(VM_TESTBASE_DIR)/nsk/share/jni
+ -I$(VM_TESTBASE_DIR)/nsk/share/jni \
+ #
NSK_JDI_INCLUDES := \
- -I$(VM_TESTBASE_DIR)/nsk/share/native
+ -I$(VM_TESTBASE_DIR)/nsk/share/native \
+ #
NSK_SHARE_JDI_INCLUDES := \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
- -I$(VM_TESTBASE_DIR)/nsk/share/jdi
+ -I$(VM_TESTBASE_DIR)/nsk/share/jdi \
+ #
NSK_SHARE_JNI_INCLUDES := \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
- -I$(VM_TESTBASE_DIR)/nsk/share/jni
+ -I$(VM_TESTBASE_DIR)/nsk/share/jni \
+ #
RUNTIME_DEFMETH_INCLUDES := \
-I$(TOPDIR)/test/hotspot/jtreg/vmTestbase/nsk/share/jni \
-I$(TOPDIR)/test/hotspot/jtreg/vmTestbase/nsk/share/native \
- -I$(TOPDIR)/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti
+ -I$(TOPDIR)/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti \
+ #
NSK_SHARE_LOCKS_INCLUDES := \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
- -I$(VM_TESTBASE_DIR)/nsk/share/locks
+ -I$(VM_TESTBASE_DIR)/nsk/share/locks \
+ #
MLVM_JVMTI_INCLUDES := \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
-I$(VM_TESTBASE_DIR)/nsk/share/jni \
-I$(VM_TESTBASE_DIR)/nsk/share/jvmti \
-I$(VM_TESTBASE_DIR)/nsk/share/jvmti/agent_common \
- -I$(VM_TESTBASE_DIR)/vm/mlvm/share
+ -I$(VM_TESTBASE_DIR)/vm/mlvm/share \
+ #
MLVM_STRESS_INCLUDES := \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
- -I$(VM_TESTBASE_DIR)/nsk/share/jni
+ -I$(VM_TESTBASE_DIR)/nsk/share/jni \
+ #
NSK_GC_LOCK_JNI_INCLUDES := \
-I$(VM_TESTBASE_DIR)/nsk/share/gc/lock/jni \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
- -I$(VM_TESTBASE_DIR)/nsk/share/jni
+ -I$(VM_TESTBASE_DIR)/nsk/share/jni \
+ #
NSK_GC_LOCK_REF_INCLUDES := \
-I$(VM_TESTBASE_DIR)/nsk/share/gc/lock/jniref \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
- -I$(VM_TESTBASE_DIR)/nsk/share/jni
+ -I$(VM_TESTBASE_DIR)/nsk/share/jni \
+ #
NSK_STRACE_INCLUDES := \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
- -I$(VM_TESTBASE_DIR)/nsk/share/jni
+ -I$(VM_TESTBASE_DIR)/nsk/share/jni \
+ #
NSK_STRESS_JNI_INCLUDES := \
- -I$(VM_TESTBASE_DIR)/nsk/stress/jni
+ -I$(VM_TESTBASE_DIR)/nsk/stress/jni \
+ #
NSK_JVMTI_AGENT_INCLUDES := \
-I$(VM_TESTBASE_DIR)/nsk/share/jni \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
-I$(VM_TESTBASE_DIR)/nsk/share/jvmti \
- -I$(VM_TESTBASE_DIR)/nsk/share/jvmti/agent_common
+ -I$(VM_TESTBASE_DIR)/nsk/share/jvmti/agent_common \
+ #
NSK_JVMTI_AOD_INCLUDES := \
-I$(VM_TESTBASE_DIR)/nsk/share/jni \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
-I$(VM_TESTBASE_DIR)/nsk/share/aod \
-I$(VM_TESTBASE_DIR)/nsk/share/jvmti \
- -I$(VM_TESTBASE_DIR)/nsk/share/jvmti/aod
+ -I$(VM_TESTBASE_DIR)/nsk/share/jvmti/aod \
+ #
NSK_AOD_INCLUDES := \
-I$(VM_TESTBASE_DIR)/nsk/share/aod \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
- -I$(VM_TESTBASE_DIR)/nsk/share/jni
+ -I$(VM_TESTBASE_DIR)/nsk/share/jni \
+ #
NO_FRAMEPOINTER_CFLAGS :=
ifeq ($(call isTargetOs, linux), true)
@@ -140,7 +156,7 @@ BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libNoFramePointer := $(NO_FRAMEPOINTER_CFLA
# Optimization -O3 needed, HIGH == -O3
BUILD_HOTSPOT_JTREG_LIBRARIES_OPTIMIZATION_libNoFramePointer := HIGH
-JVMTI_COMMON_INCLUDES=-I$(TOPDIR)/test/lib/jdk/test/lib/jvmti
+JVMTI_COMMON_INCLUDES = -I$(TOPDIR)/test/lib/jdk/test/lib/jvmti
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libProcessUtils := $(VM_SHARE_INCLUDES)
@@ -762,7 +778,7 @@ BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libretransform002 := $(NSK_JVMTI_AGENT_INCL
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libretransform004 := $(NSK_JVMTI_AGENT_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libretransform003 := $(NSK_JVMTI_AGENT_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libgetclmdf007 := $(NSK_JVMTI_AGENT_INCLUDES)
-BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libgetclmdf006 :=$(NSK_JVMTI_AGENT_INCLUDES)
+BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libgetclmdf006 := $(NSK_JVMTI_AGENT_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libgetclmdf004 := $(NSK_JVMTI_AGENT_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libgetclmdf005 := $(NSK_JVMTI_AGENT_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libsetlocal001 := $(NSK_JVMTI_AGENT_INCLUDES)
@@ -869,8 +885,9 @@ BUILD_HOTSPOT_JTREG_EXECUTABLES_JDK_LIBS_exedaemonDestroy := java.base:libjvm
ifeq ($(call isTargetOs, windows), true)
BUILD_HOTSPOT_JTREG_EXECUTABLES_CFLAGS_exeFPRegs := -MT
- BUILD_HOTSPOT_JTREG_EXCLUDE += exesigtest.c libterminatedThread.c libTestJNI.c libCompleteExit.c libMonitorWithDeadObjectTest.c libTestPsig.c exeGetCreatedJavaVMs.c
+ BUILD_HOTSPOT_JTREG_EXCLUDE += exesigtest.c libterminatedThread.c libTestJNI.c libCompleteExit.c libMonitorWithDeadObjectTest.c libTestPsig.c exeGetCreatedJavaVMs.c libTestUnloadedClass.cpp
BUILD_HOTSPOT_JTREG_LIBRARIES_JDK_LIBS_libnativeStack := java.base:libjvm
+ BUILD_HOTSPOT_JTREG_LIBRARIES_JDK_LIBS_libVThreadEventTest := java.base:libjvm
else
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libbootclssearch_agent += -lpthread
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libsystemclssearch_agent += -lpthread
@@ -1509,6 +1526,8 @@ else
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libCompleteExit += -lpthread
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libMonitorWithDeadObjectTest += -lpthread
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libnativeStack += -lpthread
+ BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libTestUnloadedClass += -lpthread
+ BUILD_HOTSPOT_JTREG_LIBRARIES_JDK_LIBS_libVThreadEventTest := java.base:libjvm
BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exeGetCreatedJavaVMs := -lpthread
BUILD_HOTSPOT_JTREG_EXECUTABLES_JDK_LIBS_exeGetCreatedJavaVMs := java.base:libjvm
@@ -1557,7 +1576,7 @@ build-test-hotspot-jtreg-native: $(BUILD_HOTSPOT_JTREG_LIBRARIES) $(BUILD_HOTSPO
################################################################################
# Copy to hotspot jtreg test image
-$(eval $(call SetupCopyFiles,COPY_HOTSPOT_JTREG_NATIVE, \
+$(eval $(call SetupCopyFiles, COPY_HOTSPOT_JTREG_NATIVE, \
SRC := $(BUILD_HOTSPOT_JTREG_OUTPUT_DIR), \
DEST := $(TEST_IMAGE_DIR)/hotspot/jtreg/native, \
FILES := $(wildcard $(addprefix $(BUILD_HOTSPOT_JTREG_OUTPUT_DIR), /bin/* /lib/*)), \
diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk
index 46eeb7684b6..90055cb5c01 100644
--- a/make/test/JtregNativeJdk.gmk
+++ b/make/test/JtregNativeJdk.gmk
@@ -53,7 +53,8 @@ BUILD_JDK_JTREG_IMAGE_DIR := $(TEST_IMAGE_DIR)/jdk/jtreg
BUILD_JDK_JTREG_EXECUTABLES_CFLAGS_exeJliLaunchTest := \
-I$(TOPDIR)/src/java.base/share/native/libjli \
-I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjli \
- -I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libjli
+ -I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libjli \
+ #
BUILD_JDK_JTREG_EXECUTABLES_JDK_LIBS_exeJliLaunchTest := java.base:libjli
BUILD_JDK_JTREG_EXECUTABLES_JDK_LIBS_exeCallerAccessTest := java.base:libjvm
@@ -114,6 +115,8 @@ ifeq ($(call isTargetOs, linux), true)
# stripping during the test libraries' build.
BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libFib := -g
BUILD_JDK_JTREG_LIBRARIES_STRIP_SYMBOLS_libFib := false
+ # nio tests' libCreationTimeHelper native needs -ldl linker flag
+ BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libCreationTimeHelper := -ldl
endif
ifeq ($(ASAN_ENABLED), true)
@@ -154,7 +157,7 @@ build-test-jdk-jtreg-native: $(BUILD_JDK_JTREG_LIBRARIES) $(BUILD_JDK_JTREG_EXEC
################################################################################
# Copy to jdk jtreg test image
-$(eval $(call SetupCopyFiles,COPY_JDK_JTREG_NATIVE, \
+$(eval $(call SetupCopyFiles, COPY_JDK_JTREG_NATIVE, \
SRC := $(BUILD_JDK_JTREG_OUTPUT_DIR), \
DEST := $(TEST_IMAGE_DIR)/jdk/jtreg/native, \
FILES := $(wildcard $(addprefix $(BUILD_JDK_JTREG_OUTPUT_DIR), /bin/* /lib/*)), \
diff --git a/src/demo/share/jfc/SwingSet2/SwingSet2.java b/src/demo/share/jfc/SwingSet2/SwingSet2.java
index 13b3d63a693..75eeb4e3657 100644
--- a/src/demo/share/jfc/SwingSet2/SwingSet2.java
+++ b/src/demo/share/jfc/SwingSet2/SwingSet2.java
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -848,7 +848,14 @@ private void updateThisSwingSet() {
if (frame == null) {
SwingUtilities.updateComponentTreeUI(this);
} else {
+ if (currentLookAndFeel.name.contains("GTK")) {
+ this.setPreferredSize(new Dimension(PREFERRED_WIDTH + 260, PREFERRED_HEIGHT + 80));
+ } else {
+ this.setPreferredSize(new Dimension(PREFERRED_WIDTH, PREFERRED_HEIGHT));
+ }
+
SwingUtilities.updateComponentTreeUI(frame);
+ frame.pack();
}
SwingUtilities.updateComponentTreeUI(popupMenu);
diff --git a/src/demo/share/jfc/SwingSet2/resources/images/About.jpg b/src/demo/share/jfc/SwingSet2/resources/images/About.jpg
index 272173c6746..c6c8e22970b 100644
Binary files a/src/demo/share/jfc/SwingSet2/resources/images/About.jpg and b/src/demo/share/jfc/SwingSet2/resources/images/About.jpg differ
diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad
index d4b3d634438..d9c77a2f529 100644
--- a/src/hotspot/cpu/aarch64/aarch64.ad
+++ b/src/hotspot/cpu/aarch64/aarch64.ad
@@ -1244,7 +1244,7 @@ source %{
// r27 is not allocatable when compressed oops is on and heapbase is not
// zero, compressed klass pointers doesn't use r27 after JDK-8234794
- if (UseCompressedOops && (CompressedOops::ptrs_base() != nullptr)) {
+ if (UseCompressedOops && (CompressedOops::base() != nullptr)) {
_NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg()));
_NO_SPECIAL_REG_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg()));
_NO_SPECIAL_PTR_REG_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg()));
@@ -2307,10 +2307,6 @@ const RegMask* Matcher::predicate_reg_mask(void) {
return &_PR_REG_mask;
}
-const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) {
- return new TypeVectMask(elemTy, length);
-}
-
// Vector calling convention not yet implemented.
bool Matcher::supports_vector_calling_convention(void) {
return false;
@@ -2334,7 +2330,7 @@ bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) {
// Vector width in bytes.
int Matcher::vector_width_in_bytes(BasicType bt) {
// The MaxVectorSize should have been set by detecting SVE max vector register size.
- int size = MIN2((UseSVE > 0) ? 256 : 16, (int)MaxVectorSize);
+ int size = MIN2((UseSVE > 0) ? (int)FloatRegister::sve_vl_max : (int)FloatRegister::neon_vl, (int)MaxVectorSize);
// Minimum 2 values in vector
if (size < 2*type2aelembytes(bt)) size = 0;
// But never < 4
@@ -2373,7 +2369,7 @@ int Matcher::scalable_vector_reg_size(const BasicType bt) {
// Vector ideal reg.
uint Matcher::vector_ideal_reg(int len) {
- if (UseSVE > 0 && 16 < len && len <= 256) {
+ if (UseSVE > 0 && FloatRegister::neon_vl < len && len <= FloatRegister::sve_vl_max) {
return Op_VecA;
}
switch(len) {
@@ -2620,7 +2616,8 @@ static bool is_vector_bitwise_not_pattern(Node* n, Node* m) {
bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) {
if (is_vshift_con_pattern(n, m) ||
is_vector_bitwise_not_pattern(n, m) ||
- is_valid_sve_arith_imm_pattern(n, m)) {
+ is_valid_sve_arith_imm_pattern(n, m) ||
+ is_encode_and_store_pattern(n, m)) {
mstack.push(m, Visit);
return true;
}
@@ -2745,10 +2742,7 @@ typedef void (MacroAssembler::* mem_vector_insn)(FloatRegister Rt,
}
if (index == -1) {
- /* If we get an out-of-range offset it is a bug in the compiler,
- so we assert here. */
- assert(Address::offset_ok_for_immed(disp, exact_log2(size_in_memory)), "c2 compiler bug");
- /* Fix up any out-of-range offsets. */
+ // Fix up any out-of-range offsets.
assert_different_registers(rscratch1, base);
Address addr = Address(base, disp);
addr = __ legitimize_address(addr, size_in_memory, rscratch1);
@@ -3348,7 +3342,11 @@ encode %{
int scale = $mem$$scale;
int disp = $mem$$disp;
if (index == -1) {
- __ prfm(Address(base, disp), PSTL1KEEP);
+ // Fix up any out-of-range offsets.
+ assert_different_registers(rscratch1, base);
+ Address addr = Address(base, disp);
+ addr = __ legitimize_address(addr, 8, rscratch1);
+ __ prfm(addr, PSTL1KEEP);
} else {
Register index_reg = as_Register(index);
if (disp == 0) {
@@ -4229,9 +4227,9 @@ operand immIOffset16()
interface(CONST_INTER);
%}
-operand immLoffset()
+operand immLOffset()
%{
- predicate(Address::offset_ok_for_immed(n->get_long(), 0));
+ predicate(n->get_long() >= -256 && n->get_long() <= 65520);
match(ConL);
op_cost(0);
@@ -5341,6 +5339,34 @@ operand indOffL16(iRegP reg, immLoffset16 off)
%}
%}
+operand indirectX2P(iRegL reg)
+%{
+ constraint(ALLOC_IN_RC(ptr_reg));
+ match(CastX2P reg);
+ op_cost(0);
+ format %{ "[$reg]\t# long -> ptr" %}
+ interface(MEMORY_INTER) %{
+ base($reg);
+ index(0xffffffff);
+ scale(0x0);
+ disp(0x0);
+ %}
+%}
+
+operand indOffX2P(iRegL reg, immLOffset off)
+%{
+ constraint(ALLOC_IN_RC(ptr_reg));
+ match(AddP (CastX2P reg) off);
+ op_cost(0);
+ format %{ "[$reg, $off]\t# long -> ptr" %}
+ interface(MEMORY_INTER) %{
+ base($reg);
+ index(0xffffffff);
+ scale(0x0);
+ disp($off);
+ %}
+%}
+
operand indirectN(iRegN reg)
%{
predicate(CompressedOops::shift() == 0);
@@ -5431,7 +5457,7 @@ operand indOffIN(iRegN reg, immIOffset off)
%}
%}
-operand indOffLN(iRegN reg, immLoffset off)
+operand indOffLN(iRegN reg, immLOffset off)
%{
predicate(CompressedOops::shift() == 0);
constraint(ALLOC_IN_RC(ptr_reg));
@@ -5664,6 +5690,17 @@ operand iRegL2I(iRegL reg) %{
interface(REG_INTER)
%}
+operand iRegL2P(iRegL reg) %{
+
+ op_cost(0);
+
+ match(CastX2P reg);
+
+ format %{ "l2p($reg)" %}
+
+ interface(REG_INTER)
+%}
+
opclass vmem2(indirect, indIndex, indOffI2, indOffL2);
opclass vmem4(indirect, indIndex, indOffI4, indOffL4);
opclass vmem8(indirect, indIndex, indOffI8, indOffL8);
@@ -5680,21 +5717,21 @@ opclass vmem16(indirect, indIndex, indOffI16, indOffL16);
// instruction defs. we can turn a memory op into an Address
opclass memory1(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI1, indOffL1,
- indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN);
+ indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indirectX2P, indOffX2P);
opclass memory2(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI2, indOffL2,
- indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN);
+ indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indirectX2P, indOffX2P);
opclass memory4(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI4, indOffL4,
- indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN);
+ indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P);
opclass memory8(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI8, indOffL8,
- indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN);
+ indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P);
// All of the memory operands. For the pipeline description.
opclass memory(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex,
indOffI1, indOffL1, indOffI2, indOffL2, indOffI4, indOffL4, indOffI8, indOffL8,
- indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN);
+ indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P);
// iRegIorL2I is used for src inputs in rules for 32 bit int (I)
@@ -5711,6 +5748,7 @@ opclass memory(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indInde
// movw is actually redundant but its not too costly.
opclass iRegIorL2I(iRegI, iRegL2I);
+opclass iRegPorL2P(iRegP, iRegL2P);
//----------PIPELINE-----------------------------------------------------------
// Rules which define the behavior of the target architectures pipeline.
@@ -6594,7 +6632,7 @@ instruct loadP(iRegPNoSp dst, memory8 mem)
instruct loadN(iRegNNoSp dst, memory4 mem)
%{
match(Set dst (LoadN mem));
- predicate(!needs_acquiring_load(n));
+ predicate(!needs_acquiring_load(n) && n->as_Load()->barrier_data() == 0);
ins_cost(4 * INSN_COST);
format %{ "ldrw $dst, $mem\t# compressed ptr" %}
@@ -6850,36 +6888,6 @@ instruct loadConD(vRegD dst, immD con) %{
// Store Instructions
-// Store CMS card-mark Immediate
-instruct storeimmCM0(immI0 zero, memory1 mem)
-%{
- match(Set mem (StoreCM mem zero));
-
- ins_cost(INSN_COST);
- format %{ "storestore (elided)\n\t"
- "strb zr, $mem\t# byte" %}
-
- ins_encode(aarch64_enc_strb0(mem));
-
- ins_pipe(istore_mem);
-%}
-
-// Store CMS card-mark Immediate with intervening StoreStore
-// needed when using CMS with no conditional card marking
-instruct storeimmCM0_ordered(immI0 zero, memory1 mem)
-%{
- match(Set mem (StoreCM mem zero));
-
- ins_cost(INSN_COST * 2);
- format %{ "storestore\n\t"
- "dmb ishst"
- "\n\tstrb zr, $mem\t# byte" %}
-
- ins_encode(aarch64_enc_strb0_ordered(mem));
-
- ins_pipe(istore_mem);
-%}
-
// Store Byte
instruct storeB(iRegIorL2I src, memory1 mem)
%{
@@ -7023,7 +7031,7 @@ instruct storeimmP0(immP0 zero, memory8 mem)
instruct storeN(iRegN src, memory4 mem)
%{
match(Set mem (StoreN mem src));
- predicate(!needs_releasing_store(n));
+ predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0);
ins_cost(INSN_COST);
format %{ "strw $src, $mem\t# compressed ptr" %}
@@ -7036,7 +7044,7 @@ instruct storeN(iRegN src, memory4 mem)
instruct storeImmN0(immN0 zero, memory4 mem)
%{
match(Set mem (StoreN mem zero));
- predicate(!needs_releasing_store(n));
+ predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0);
ins_cost(INSN_COST);
format %{ "strw zr, $mem\t# compressed ptr" %}
@@ -7270,6 +7278,7 @@ instruct loadP_volatile(iRegPNoSp dst, /* sync_memory*/indirect mem)
instruct loadN_volatile(iRegNNoSp dst, /* sync_memory*/indirect mem)
%{
match(Set dst (LoadN mem));
+ predicate(n->as_Load()->barrier_data() == 0);
ins_cost(VOLATILE_REF_COST);
format %{ "ldarw $dst, $mem\t# compressed ptr" %}
@@ -7437,6 +7446,7 @@ instruct storeimmP0_volatile(immP0 zero, /* sync_memory*/indirect mem)
instruct storeN_volatile(iRegN src, /* sync_memory*/indirect mem)
%{
match(Set mem (StoreN mem src));
+ predicate(n->as_Store()->barrier_data() == 0);
ins_cost(VOLATILE_REF_COST);
format %{ "stlrw $src, $mem\t# compressed ptr" %}
@@ -7449,6 +7459,7 @@ instruct storeN_volatile(iRegN src, /* sync_memory*/indirect mem)
instruct storeimmN0_volatile(immN0 zero, /* sync_memory*/indirect mem)
%{
match(Set mem (StoreN mem zero));
+ predicate(n->as_Store()->barrier_data() == 0);
ins_cost(VOLATILE_REF_COST);
format %{ "stlrw zr, $mem\t# compressed ptr" %}
@@ -8245,6 +8256,7 @@ instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval
instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{
match(Set res (CompareAndSwapN mem (Binary oldval newval)));
+ predicate(n->as_LoadStore()->barrier_data() == 0);
ins_cost(2 * VOLATILE_REF_COST);
effect(KILL cr);
@@ -8359,7 +8371,7 @@ instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP new
instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{
- predicate(needs_acquiring_load_exclusive(n));
+ predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);
match(Set res (CompareAndSwapN mem (Binary oldval newval)));
ins_cost(VOLATILE_REF_COST);
@@ -8464,6 +8476,7 @@ instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL ne
// This pattern is generated automatically from cas.m4.
// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
+ predicate(n->as_LoadStore()->barrier_data() == 0);
match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
ins_cost(2 * VOLATILE_REF_COST);
effect(TEMP_DEF res, KILL cr);
@@ -8573,7 +8586,7 @@ instruct compareAndExchangeLAcq(iRegLNoSp res, indirect mem, iRegL oldval, iRegL
// This pattern is generated automatically from cas.m4.
// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
instruct compareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
- predicate(needs_acquiring_load_exclusive(n));
+ predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);
match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
ins_cost(VOLATILE_REF_COST);
effect(TEMP_DEF res, KILL cr);
@@ -8685,6 +8698,7 @@ instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL ne
// This pattern is generated automatically from cas.m4.
// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
+ predicate(n->as_LoadStore()->barrier_data() == 0);
match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
ins_cost(2 * VOLATILE_REF_COST);
effect(KILL cr);
@@ -8804,7 +8818,7 @@ instruct weakCompareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL
// This pattern is generated automatically from cas.m4.
// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
instruct weakCompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
- predicate(needs_acquiring_load_exclusive(n));
+ predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);
match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
ins_cost(VOLATILE_REF_COST);
effect(KILL cr);
@@ -8865,6 +8879,7 @@ instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev) %{
%}
instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev) %{
+ predicate(n->as_LoadStore()->barrier_data() == 0);
match(Set prev (GetAndSetN mem newv));
ins_cost(2 * VOLATILE_REF_COST);
format %{ "atomic_xchgw $prev, $newv, [$mem]" %}
@@ -8908,7 +8923,7 @@ instruct get_and_setLAcq(indirect mem, iRegL newv, iRegLNoSp prev) %{
%}
instruct get_and_setNAcq(indirect mem, iRegN newv, iRegINoSp prev) %{
- predicate(needs_acquiring_load_exclusive(n));
+ predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);
match(Set prev (GetAndSetN mem newv));
ins_cost(VOLATILE_REF_COST);
format %{ "atomic_xchgw_acq $prev, $newv, [$mem]" %}
@@ -9811,7 +9826,7 @@ instruct addI_reg_imm_i2l(iRegINoSp dst, iRegL src1, immIAddSub src2) %{
%}
// Pointer Addition
-instruct addP_reg_reg(iRegPNoSp dst, iRegP src1, iRegL src2) %{
+instruct addP_reg_reg(iRegPNoSp dst, iRegPorL2P src1, iRegL src2) %{
match(Set dst (AddP src1 src2));
ins_cost(INSN_COST);
@@ -9826,7 +9841,7 @@ instruct addP_reg_reg(iRegPNoSp dst, iRegP src1, iRegL src2) %{
ins_pipe(ialu_reg_reg);
%}
-instruct addP_reg_reg_ext(iRegPNoSp dst, iRegP src1, iRegIorL2I src2) %{
+instruct addP_reg_reg_ext(iRegPNoSp dst, iRegPorL2P src1, iRegIorL2I src2) %{
match(Set dst (AddP src1 (ConvI2L src2)));
ins_cost(1.9 * INSN_COST);
@@ -9841,7 +9856,7 @@ instruct addP_reg_reg_ext(iRegPNoSp dst, iRegP src1, iRegIorL2I src2) %{
ins_pipe(ialu_reg_reg);
%}
-instruct addP_reg_reg_lsl(iRegPNoSp dst, iRegP src1, iRegL src2, immIScale scale) %{
+instruct addP_reg_reg_lsl(iRegPNoSp dst, iRegPorL2P src1, iRegL src2, immIScale scale) %{
match(Set dst (AddP src1 (LShiftL src2 scale)));
ins_cost(1.9 * INSN_COST);
@@ -9856,7 +9871,7 @@ instruct addP_reg_reg_lsl(iRegPNoSp dst, iRegP src1, iRegL src2, immIScale scale
ins_pipe(ialu_reg_reg_shift);
%}
-instruct addP_reg_reg_ext_shift(iRegPNoSp dst, iRegP src1, iRegIorL2I src2, immIScale scale) %{
+instruct addP_reg_reg_ext_shift(iRegPNoSp dst, iRegPorL2P src1, iRegIorL2I src2, immIScale scale) %{
match(Set dst (AddP src1 (LShiftL (ConvI2L src2) scale)));
ins_cost(1.9 * INSN_COST);
@@ -9889,7 +9904,7 @@ instruct lshift_ext(iRegLNoSp dst, iRegIorL2I src, immI scale, rFlagsReg cr) %{
// Pointer Immediate Addition
// n.b. this needs to be more expensive than using an indirect memory
// operand
-instruct addP_reg_imm(iRegPNoSp dst, iRegP src1, immLAddSub src2) %{
+instruct addP_reg_imm(iRegPNoSp dst, iRegPorL2P src1, immLAddSub src2) %{
match(Set dst (AddP src1 src2));
ins_cost(INSN_COST);
@@ -15977,7 +15992,7 @@ instruct cmpFastLockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp
format %{ "fastlock $object,$box\t! kills $tmp,$tmp2,$tmp3" %}
ins_encode %{
- __ fast_lock_lightweight($object$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register);
+ __ fast_lock_lightweight($object$$Register, $box$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register);
%}
ins_pipe(pipe_serial);
@@ -15993,7 +16008,7 @@ instruct cmpFastUnlockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNo
format %{ "fastunlock $object,$box\t! kills $tmp, $tmp2, $tmp3" %}
ins_encode %{
- __ fast_unlock_lightweight($object$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register);
+ __ fast_unlock_lightweight($object$$Register, $box$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register);
%}
ins_pipe(pipe_serial);
@@ -16143,6 +16158,19 @@ instruct TailjmpInd(iRegPNoSpNoRfp jump_target, iRegP_R0 ex_oop)
ins_pipe(pipe_class_call);
%}
+// Forward exception.
+instruct ForwardExceptionjmp()
+%{
+ match(ForwardException);
+ ins_cost(CALL_COST);
+
+ format %{ "b forward_exception_stub" %}
+ ins_encode %{
+ __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
+ %}
+ ins_pipe(pipe_class_call);
+%}
+
// Create exception oop: created by stack-crawling runtime code.
// Created exception is now available to this handler, and is setup
// just prior to jumping to this handler. No code emitted.
diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad
index 1ebc6408a60..0d3a240cecf 100644
--- a/src/hotspot/cpu/aarch64/aarch64_vector.ad
+++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad
@@ -155,7 +155,7 @@ source %{
}
int length_in_bytes = vlen * type2aelembytes(bt);
- if (UseSVE == 0 && length_in_bytes > 16) {
+ if (UseSVE == 0 && length_in_bytes > FloatRegister::neon_vl) {
return false;
}
diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4
index 29f92772368..99708e9ef31 100644
--- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4
+++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4
@@ -145,7 +145,7 @@ source %{
}
int length_in_bytes = vlen * type2aelembytes(bt);
- if (UseSVE == 0 && length_in_bytes > 16) {
+ if (UseSVE == 0 && length_in_bytes > FloatRegister::neon_vl) {
return false;
}
diff --git a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp
index ca175fe1c47..89a97a4984f 100644
--- a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -57,7 +57,7 @@ void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
__ mov_metadata(rscratch1, m);
ce->store_parameter(rscratch1, 1);
ce->store_parameter(_bci, 0);
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::counter_overflow_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::counter_overflow_id)));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
__ b(_continuation);
@@ -66,7 +66,7 @@ void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
void RangeCheckStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
if (_info->deoptimize_on_exception()) {
- address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ address a = Runtime1::entry_for(C1StubId::predicate_failed_trap_id);
__ far_call(RuntimeAddress(a));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
@@ -79,13 +79,13 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
} else {
__ mov(rscratch1, _index->as_jint());
}
- Runtime1::StubID stub_id;
+ C1StubId stub_id;
if (_throw_index_out_of_bounds_exception) {
- stub_id = Runtime1::throw_index_exception_id;
+ stub_id = C1StubId::throw_index_exception_id;
} else {
assert(_array != LIR_Opr::nullOpr(), "sanity");
__ mov(rscratch2, _array->as_pointer_register());
- stub_id = Runtime1::throw_range_check_failed_id;
+ stub_id = C1StubId::throw_range_check_failed_id;
}
__ lea(lr, RuntimeAddress(Runtime1::entry_for(stub_id)));
__ blr(lr);
@@ -100,7 +100,7 @@ PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ address a = Runtime1::entry_for(C1StubId::predicate_failed_trap_id);
__ far_call(RuntimeAddress(a));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
@@ -112,7 +112,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) {
ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
}
__ bind(_entry);
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::throw_div0_exception_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::throw_div0_exception_id)));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
#ifdef ASSERT
@@ -124,14 +124,14 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) {
// Implementation of NewInstanceStub
-NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) {
+NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, C1StubId stub_id) {
_result = result;
_klass = klass;
_klass_reg = klass_reg;
_info = new CodeEmitInfo(info);
- assert(stub_id == Runtime1::new_instance_id ||
- stub_id == Runtime1::fast_new_instance_id ||
- stub_id == Runtime1::fast_new_instance_init_check_id,
+ assert(stub_id == C1StubId::new_instance_id ||
+ stub_id == C1StubId::fast_new_instance_id ||
+ stub_id == C1StubId::fast_new_instance_init_check_id,
"need new_instance id");
_stub_id = stub_id;
}
@@ -167,7 +167,7 @@ void NewTypeArrayStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
assert(_length->as_register() == r19, "length must in r19,");
assert(_klass_reg->as_register() == r3, "klass_reg must in r3");
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_type_array_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::new_type_array_id)));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
assert(_result->as_register() == r0, "result must in r0");
@@ -190,7 +190,7 @@ void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
assert(_length->as_register() == r19, "length must in r19,");
assert(_klass_reg->as_register() == r3, "klass_reg must in r3");
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_object_array_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::new_object_array_id)));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
assert(_result->as_register() == r0, "result must in r0");
@@ -202,11 +202,11 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
ce->store_parameter(_obj_reg->as_register(), 1);
ce->store_parameter(_lock_reg->as_register(), 0);
- Runtime1::StubID enter_id;
+ C1StubId enter_id;
if (ce->compilation()->has_fpu_code()) {
- enter_id = Runtime1::monitorenter_id;
+ enter_id = C1StubId::monitorenter_id;
} else {
- enter_id = Runtime1::monitorenter_nofpu_id;
+ enter_id = C1StubId::monitorenter_nofpu_id;
}
__ far_call(RuntimeAddress(Runtime1::entry_for(enter_id)));
ce->add_call_info_here(_info);
@@ -223,11 +223,11 @@ void MonitorExitStub::emit_code(LIR_Assembler* ce) {
}
ce->store_parameter(_lock_reg->as_register(), 0);
// note: non-blocking leaf routine => no call info needed
- Runtime1::StubID exit_id;
+ C1StubId exit_id;
if (ce->compilation()->has_fpu_code()) {
- exit_id = Runtime1::monitorexit_id;
+ exit_id = C1StubId::monitorexit_id;
} else {
- exit_id = Runtime1::monitorexit_nofpu_id;
+ exit_id = C1StubId::monitorexit_nofpu_id;
}
__ adr(lr, _continuation);
__ far_jump(RuntimeAddress(Runtime1::entry_for(exit_id)));
@@ -255,7 +255,7 @@ void PatchingStub::emit_code(LIR_Assembler* ce) {
void DeoptimizeStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
ce->store_parameter(_trap_request, 0);
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::deoptimize_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::deoptimize_id)));
ce->add_call_info_here(_info);
DEBUG_ONLY(__ should_not_reach_here());
}
@@ -265,9 +265,9 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
address a;
if (_info->deoptimize_on_exception()) {
// Deoptimize, do not throw the exception, because it is probably wrong to do it here.
- a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ a = Runtime1::entry_for(C1StubId::predicate_failed_trap_id);
} else {
- a = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id);
+ a = Runtime1::entry_for(C1StubId::throw_null_pointer_exception_id);
}
ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
index 615c8e19ac8..ebd83027151 100644
--- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
@@ -275,14 +275,14 @@ void LIR_Assembler::osr_entry() {
// verify the interpreter's monitor has a non-null object
{
Label L;
- __ ldr(rscratch1, Address(OSR_buf, slot_offset + 1*BytesPerWord));
+ __ ldr(rscratch1, __ form_address(rscratch1, OSR_buf, slot_offset + 1*BytesPerWord, 0));
__ cbnz(rscratch1, L);
__ stop("locked object is null");
__ bind(L);
}
#endif
- __ ldr(r19, Address(OSR_buf, slot_offset));
- __ ldr(r20, Address(OSR_buf, slot_offset + BytesPerWord));
+ __ ldr(r19, __ form_address(rscratch1, OSR_buf, slot_offset, 0));
+ __ ldr(r20, __ form_address(rscratch1, OSR_buf, slot_offset + BytesPerWord, 0));
__ str(r19, frame_map()->address_for_monitor_lock(i));
__ str(r20, frame_map()->address_for_monitor_object(i));
}
@@ -321,19 +321,19 @@ void LIR_Assembler::deoptimize_trap(CodeEmitInfo *info) {
switch (patching_id(info)) {
case PatchingStub::access_field_id:
- target = Runtime1::entry_for(Runtime1::access_field_patching_id);
+ target = Runtime1::entry_for(C1StubId::access_field_patching_id);
reloc_type = relocInfo::section_word_type;
break;
case PatchingStub::load_klass_id:
- target = Runtime1::entry_for(Runtime1::load_klass_patching_id);
+ target = Runtime1::entry_for(C1StubId::load_klass_patching_id);
reloc_type = relocInfo::metadata_type;
break;
case PatchingStub::load_mirror_id:
- target = Runtime1::entry_for(Runtime1::load_mirror_patching_id);
+ target = Runtime1::entry_for(C1StubId::load_mirror_patching_id);
reloc_type = relocInfo::oop_type;
break;
case PatchingStub::load_appendix_id:
- target = Runtime1::entry_for(Runtime1::load_appendix_patching_id);
+ target = Runtime1::entry_for(C1StubId::load_appendix_patching_id);
reloc_type = relocInfo::oop_type;
break;
default: ShouldNotReachHere();
@@ -375,7 +375,7 @@ int LIR_Assembler::emit_exception_handler() {
__ verify_not_null_oop(r0);
// search an exception handler (r0: exception oop, r3: throwing pc)
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::handle_exception_from_callee_id)));
__ should_not_reach_here();
guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
__ end_a_stub();
@@ -432,7 +432,7 @@ int LIR_Assembler::emit_unwind_handler() {
// remove the activation and dispatch to the unwind handler
__ block_comment("remove_frame and dispatch to the unwind handler");
__ remove_frame(initial_frame_size_in_bytes());
- __ far_jump(RuntimeAddress(Runtime1::entry_for(Runtime1::unwind_exception_id)));
+ __ far_jump(RuntimeAddress(Runtime1::entry_for(C1StubId::unwind_exception_id)));
// Emit the slow path assembly
if (stub != nullptr) {
@@ -647,7 +647,7 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi
break;
case T_OBJECT:
case T_ARRAY:
- assert(c->as_jobject() == 0, "should be");
+ assert(c->as_jobject() == nullptr, "should be");
if (UseCompressedOops && !wide) {
insn = &Assembler::strw;
} else {
@@ -875,19 +875,19 @@ void LIR_Assembler::klass2reg_with_patching(Register reg, CodeEmitInfo* info) {
switch (patching_id(info)) {
case PatchingStub::access_field_id:
- target = Runtime1::entry_for(Runtime1::access_field_patching_id);
+ target = Runtime1::entry_for(C1StubId::access_field_patching_id);
reloc_type = relocInfo::section_word_type;
break;
case PatchingStub::load_klass_id:
- target = Runtime1::entry_for(Runtime1::load_klass_patching_id);
+ target = Runtime1::entry_for(C1StubId::load_klass_patching_id);
reloc_type = relocInfo::metadata_type;
break;
case PatchingStub::load_mirror_id:
- target = Runtime1::entry_for(Runtime1::load_mirror_patching_id);
+ target = Runtime1::entry_for(C1StubId::load_mirror_patching_id);
reloc_type = relocInfo::oop_type;
break;
case PatchingStub::load_appendix_id:
- target = Runtime1::entry_for(Runtime1::load_appendix_patching_id);
+ target = Runtime1::entry_for(C1StubId::load_appendix_patching_id);
reloc_type = relocInfo::oop_type;
break;
default: ShouldNotReachHere();
@@ -1168,8 +1168,8 @@ void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) {
void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) {
if (op->init_check()) {
- __ ldrb(rscratch1, Address(op->klass()->as_register(),
- InstanceKlass::init_state_offset()));
+ __ lea(rscratch1, Address(op->klass()->as_register(), InstanceKlass::init_state_offset()));
+ __ ldarb(rscratch1, rscratch1);
__ cmpw(rscratch1, InstanceKlass::fully_initialized);
add_debug_info_for_null_check_here(op->stub()->info());
__ br(Assembler::NE, *op->stub()->entry());
@@ -1356,7 +1356,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L
__ br(Assembler::EQ, *success_target);
__ stp(klass_RInfo, k_RInfo, Address(__ pre(sp, -2 * wordSize)));
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::slow_subtype_check_id)));
__ ldr(klass_RInfo, Address(__ post(sp, 2 * wordSize)));
// result is a boolean
__ cbzw(klass_RInfo, *failure_target);
@@ -1367,7 +1367,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L
__ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, success_target, failure_target, nullptr);
// call out-of-line instance of __ check_klass_subtype_slow_path(...):
__ stp(klass_RInfo, k_RInfo, Address(__ pre(sp, -2 * wordSize)));
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::slow_subtype_check_id)));
__ ldp(k_RInfo, klass_RInfo, Address(__ post(sp, 2 * wordSize)));
// result is a boolean
__ cbz(k_RInfo, *failure_target);
@@ -1446,7 +1446,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
__ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, success_target, failure_target, nullptr);
// call out-of-line instance of __ check_klass_subtype_slow_path(...):
__ stp(klass_RInfo, k_RInfo, Address(__ pre(sp, -2 * wordSize)));
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::slow_subtype_check_id)));
__ ldp(k_RInfo, klass_RInfo, Address(__ post(sp, 2 * wordSize)));
// result is a boolean
__ cbzw(k_RInfo, *failure_target);
@@ -2035,7 +2035,7 @@ void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmit
// exception object is not added to oop map by LinearScan
// (LinearScan assumes that no oops are in fixed registers)
info->add_register_oop(exceptionOop);
- Runtime1::StubID unwind_id;
+ C1StubId unwind_id;
// get current pc information
// pc is only needed if the method has an exception handler, the unwind code does not need it.
@@ -2054,9 +2054,9 @@ void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmit
__ verify_not_null_oop(r0);
// search an exception handler (r0: exception oop, r3: throwing pc)
if (compilation()->has_fpu_code()) {
- unwind_id = Runtime1::handle_exception_id;
+ unwind_id = C1StubId::handle_exception_id;
} else {
- unwind_id = Runtime1::handle_exception_nofpu_id;
+ unwind_id = C1StubId::handle_exception_nofpu_id;
}
__ far_call(RuntimeAddress(Runtime1::entry_for(unwind_id)));
@@ -2337,7 +2337,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
__ check_klass_subtype_fast_path(src, dst, tmp, &cont, &slow, nullptr);
__ PUSH(src, dst);
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::slow_subtype_check_id)));
__ POP(src, dst);
__ cbnz(src, cont);
diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp
index ef1b5fe2703..77edbd7bc0a 100644
--- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp
@@ -60,8 +60,6 @@ friend class ArrayCopyStub;
void casw(Register addr, Register newval, Register cmpval);
void casl(Register addr, Register newval, Register cmpval);
- void poll_for_safepoint(relocInfo::relocType rtype, CodeEmitInfo* info = nullptr);
-
static const int max_tableswitches = 20;
struct tableswitch switches[max_tableswitches];
int tableswitch_count;
diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp
index 8f1260feba3..4acac65ad5b 100644
--- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp
@@ -1246,7 +1246,7 @@ void LIRGenerator::do_NewMultiArray(NewMultiArray* x) {
args->append(rank);
args->append(varargs);
LIR_Opr reg = result_register_for(x->type());
- __ call_runtime(Runtime1::entry_for(Runtime1::new_multi_array_id),
+ __ call_runtime(Runtime1::entry_for(C1StubId::new_multi_array_id),
LIR_OprFact::illegalOpr,
reg, args, info);
@@ -1277,14 +1277,14 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
CodeStub* stub;
if (x->is_incompatible_class_change_check()) {
assert(patching_info == nullptr, "can't patch this");
- stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception);
+ stub = new SimpleExceptionStub(C1StubId::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception);
} else if (x->is_invokespecial_receiver_check()) {
assert(patching_info == nullptr, "can't patch this");
stub = new DeoptimizeStub(info_for_exception,
Deoptimization::Reason_class_check,
Deoptimization::Action_none);
} else {
- stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception);
+ stub = new SimpleExceptionStub(C1StubId::throw_class_cast_exception_id, obj.result(), info_for_exception);
}
LIR_Opr reg = rlock_result(x);
LIR_Opr tmp3 = LIR_OprFact::illegalOpr;
diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp
index c0455ad1bff..8d1b3902ce4 100644
--- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp
@@ -75,13 +75,13 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(hdr, obj);
- ldrw(hdr, Address(hdr, Klass::access_flags_offset()));
- tstw(hdr, JVM_ACC_IS_VALUE_BASED_CLASS);
+ ldrb(hdr, Address(hdr, Klass::misc_flags_offset()));
+ tst(hdr, KlassFlags::_misc_is_value_based_class);
br(Assembler::NE, slow_case);
}
if (LockingMode == LM_LIGHTWEIGHT) {
- lightweight_lock(obj, hdr, temp, rscratch2, slow_case);
+ lightweight_lock(disp_hdr, obj, hdr, temp, rscratch2, slow_case);
} else if (LockingMode == LM_LEGACY) {
Label done;
// Load object header
@@ -267,7 +267,7 @@ void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register
if (CURRENT_ENV->dtrace_alloc_probes()) {
assert(obj == r0, "must be");
- far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)));
+ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::dtrace_object_alloc_id)));
}
verify_oop(obj);
@@ -308,7 +308,7 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1,
if (CURRENT_ENV->dtrace_alloc_probes()) {
assert(obj == r0, "must be");
- far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)));
+ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::dtrace_object_alloc_id)));
}
verify_oop(obj);
diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp
index 63a32e714e3..0b9acc0f3a8 100644
--- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -100,10 +100,10 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre
if (frame_size() == no_frame_size) {
leave();
far_jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
- } else if (_stub_id == Runtime1::forward_exception_id) {
+ } else if (_stub_id == (int)C1StubId::forward_exception_id) {
should_not_reach_here();
} else {
- far_jump(RuntimeAddress(Runtime1::entry_for(Runtime1::forward_exception_id)));
+ far_jump(RuntimeAddress(Runtime1::entry_for(C1StubId::forward_exception_id)));
}
bind(L);
}
@@ -358,7 +358,7 @@ OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address targe
}
-OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
+OopMapSet* Runtime1::generate_handle_exception(C1StubId id, StubAssembler *sasm) {
__ block_comment("generate_handle_exception");
// incoming parameters
@@ -370,7 +370,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
OopMapSet* oop_maps = new OopMapSet();
OopMap* oop_map = nullptr;
switch (id) {
- case forward_exception_id:
+ case C1StubId::forward_exception_id:
// We're handling an exception in the context of a compiled frame.
// The registers have been saved in the standard places. Perform
// an exception lookup in the caller and dispatch to the handler
@@ -390,12 +390,12 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
__ str(zr, Address(rthread, JavaThread::vm_result_offset()));
__ str(zr, Address(rthread, JavaThread::vm_result_2_offset()));
break;
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
// At this point all registers MAY be live.
- oop_map = save_live_registers(sasm, id != handle_exception_nofpu_id);
+ oop_map = save_live_registers(sasm, id != C1StubId::handle_exception_nofpu_id);
break;
- case handle_exception_from_callee_id: {
+ case C1StubId::handle_exception_from_callee_id: {
// At this point all registers except exception oop (r0) and
// exception pc (lr) are dead.
const int frame_size = 2 /*fp, return address*/;
@@ -453,13 +453,13 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
__ str(r0, Address(rfp, 1*BytesPerWord));
switch (id) {
- case forward_exception_id:
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::forward_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
// Restore the registers that were saved at the beginning.
- restore_live_registers(sasm, id != handle_exception_nofpu_id);
+ restore_live_registers(sasm, id != C1StubId::handle_exception_nofpu_id);
break;
- case handle_exception_from_callee_id:
+ case C1StubId::handle_exception_from_callee_id:
break;
default: ShouldNotReachHere();
}
@@ -611,7 +611,7 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
}
-OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
+OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) {
const Register exception_oop = r0;
const Register exception_pc = r3;
@@ -628,7 +628,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
OopMap* oop_map = nullptr;
switch (id) {
{
- case forward_exception_id:
+ case C1StubId::forward_exception_id:
{
oop_maps = generate_handle_exception(id, sasm);
__ leave();
@@ -636,31 +636,31 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case throw_div0_exception_id:
+ case C1StubId::throw_div0_exception_id:
{ StubFrame f(sasm, "throw_div0_exception", dont_gc_arguments, does_not_return);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false);
}
break;
- case throw_null_pointer_exception_id:
+ case C1StubId::throw_null_pointer_exception_id:
{ StubFrame f(sasm, "throw_null_pointer_exception", dont_gc_arguments, does_not_return);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false);
}
break;
- case new_instance_id:
- case fast_new_instance_id:
- case fast_new_instance_init_check_id:
+ case C1StubId::new_instance_id:
+ case C1StubId::fast_new_instance_id:
+ case C1StubId::fast_new_instance_init_check_id:
{
Register klass = r3; // Incoming
Register obj = r0; // Result
- if (id == new_instance_id) {
+ if (id == C1StubId::new_instance_id) {
__ set_info("new_instance", dont_gc_arguments);
- } else if (id == fast_new_instance_id) {
+ } else if (id == C1StubId::fast_new_instance_id) {
__ set_info("fast new_instance", dont_gc_arguments);
} else {
- assert(id == fast_new_instance_init_check_id, "bad StubID");
+ assert(id == C1StubId::fast_new_instance_init_check_id, "bad C1StubId");
__ set_info("fast new_instance init check", dont_gc_arguments);
}
@@ -679,7 +679,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
break;
- case counter_overflow_id:
+ case C1StubId::counter_overflow_id:
{
Register bci = r0, method = r1;
__ enter();
@@ -697,14 +697,14 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case new_type_array_id:
- case new_object_array_id:
+ case C1StubId::new_type_array_id:
+ case C1StubId::new_object_array_id:
{
Register length = r19; // Incoming
Register klass = r3; // Incoming
Register obj = r0; // Result
- if (id == new_type_array_id) {
+ if (id == C1StubId::new_type_array_id) {
__ set_info("new_type_array", dont_gc_arguments);
} else {
__ set_info("new_object_array", dont_gc_arguments);
@@ -717,7 +717,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
Register t0 = obj;
__ ldrw(t0, Address(klass, Klass::layout_helper_offset()));
__ asrw(t0, t0, Klass::_lh_array_tag_shift);
- int tag = ((id == new_type_array_id)
+ int tag = ((id == C1StubId::new_type_array_id)
? Klass::_lh_array_tag_type_value
: Klass::_lh_array_tag_obj_value);
__ mov(rscratch1, tag);
@@ -732,7 +732,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
__ enter();
OopMap* map = save_live_registers(sasm);
int call_offset;
- if (id == new_type_array_id) {
+ if (id == C1StubId::new_type_array_id) {
call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_type_array), klass, length);
} else {
call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length);
@@ -750,7 +750,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case new_multi_array_id:
+ case C1StubId::new_multi_array_id:
{ StubFrame f(sasm, "new_multi_array", dont_gc_arguments);
// r0,: klass
// r19,: rank
@@ -770,7 +770,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case register_finalizer_id:
+ case C1StubId::register_finalizer_id:
{
__ set_info("register_finalizer", dont_gc_arguments);
@@ -783,8 +783,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
Label register_finalizer;
Register t = r5;
__ load_klass(t, r0);
- __ ldrw(t, Address(t, Klass::access_flags_offset()));
- __ tbnz(t, exact_log2(JVM_ACC_HAS_FINALIZER), register_finalizer);
+ __ ldrb(t, Address(t, Klass::misc_flags_offset()));
+ __ tbnz(t, exact_log2(KlassFlags::_misc_has_finalizer), register_finalizer);
__ ret(lr);
__ bind(register_finalizer);
@@ -802,19 +802,19 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case throw_class_cast_exception_id:
+ case C1StubId::throw_class_cast_exception_id:
{ StubFrame f(sasm, "throw_class_cast_exception", dont_gc_arguments, does_not_return);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true);
}
break;
- case throw_incompatible_class_change_error_id:
+ case C1StubId::throw_incompatible_class_change_error_id:
{ StubFrame f(sasm, "throw_incompatible_class_cast_exception", dont_gc_arguments, does_not_return);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false);
}
break;
- case slow_subtype_check_id:
+ case C1StubId::slow_subtype_check_id:
{
// Typical calling sequence:
// __ push(klass_RInfo); // object klass or other subclass
@@ -857,10 +857,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case monitorenter_nofpu_id:
+ case C1StubId::monitorenter_nofpu_id:
save_fpu_registers = false;
// fall through
- case monitorenter_id:
+ case C1StubId::monitorenter_id:
{
StubFrame f(sasm, "monitorenter", dont_gc_arguments);
OopMap* map = save_live_registers(sasm, save_fpu_registers);
@@ -878,10 +878,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case monitorexit_nofpu_id:
+ case C1StubId::monitorexit_nofpu_id:
save_fpu_registers = false;
// fall through
- case monitorexit_id:
+ case C1StubId::monitorexit_id:
{
StubFrame f(sasm, "monitorexit", dont_gc_arguments);
OopMap* map = save_live_registers(sasm, save_fpu_registers);
@@ -901,7 +901,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case deoptimize_id:
+ case C1StubId::deoptimize_id:
{
StubFrame f(sasm, "deoptimize", dont_gc_arguments, does_not_return);
OopMap* oop_map = save_live_registers(sasm);
@@ -918,13 +918,13 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case throw_range_check_failed_id:
+ case C1StubId::throw_range_check_failed_id:
{ StubFrame f(sasm, "range_check_failed", dont_gc_arguments, does_not_return);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), true);
}
break;
- case unwind_exception_id:
+ case C1StubId::unwind_exception_id:
{ __ set_info("unwind_exception", dont_gc_arguments);
// note: no stubframe since we are about to leave the current
// activation and we are calling a leaf VM function only.
@@ -932,54 +932,54 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case access_field_patching_id:
+ case C1StubId::access_field_patching_id:
{ StubFrame f(sasm, "access_field_patching", dont_gc_arguments, does_not_return);
// we should set up register map
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching));
}
break;
- case load_klass_patching_id:
+ case C1StubId::load_klass_patching_id:
{ StubFrame f(sasm, "load_klass_patching", dont_gc_arguments, does_not_return);
// we should set up register map
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching));
}
break;
- case load_mirror_patching_id:
+ case C1StubId::load_mirror_patching_id:
{ StubFrame f(sasm, "load_mirror_patching", dont_gc_arguments, does_not_return);
// we should set up register map
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_mirror_patching));
}
break;
- case load_appendix_patching_id:
+ case C1StubId::load_appendix_patching_id:
{ StubFrame f(sasm, "load_appendix_patching", dont_gc_arguments, does_not_return);
// we should set up register map
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching));
}
break;
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
{ StubFrame f(sasm, "handle_exception", dont_gc_arguments);
oop_maps = generate_handle_exception(id, sasm);
}
break;
- case handle_exception_from_callee_id:
+ case C1StubId::handle_exception_from_callee_id:
{ StubFrame f(sasm, "handle_exception_from_callee", dont_gc_arguments);
oop_maps = generate_handle_exception(id, sasm);
}
break;
- case throw_index_exception_id:
+ case C1StubId::throw_index_exception_id:
{ StubFrame f(sasm, "index_range_check_failed", dont_gc_arguments, does_not_return);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true);
}
break;
- case throw_array_store_exception_id:
+ case C1StubId::throw_array_store_exception_id:
{ StubFrame f(sasm, "throw_array_store_exception", dont_gc_arguments, does_not_return);
// tos + 0: link
// + 1: return address
@@ -987,7 +987,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case predicate_failed_trap_id:
+ case C1StubId::predicate_failed_trap_id:
{
StubFrame f(sasm, "predicate_failed_trap", dont_gc_arguments, does_not_return);
@@ -1005,7 +1005,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case dtrace_object_alloc_id:
+ case C1StubId::dtrace_object_alloc_id:
{ // c_rarg0: object
StubFrame f(sasm, "dtrace_object_alloc", dont_gc_arguments);
save_live_registers(sasm);
@@ -1029,4 +1029,4 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
#undef __
-const char *Runtime1::pd_name_for_address(address entry) { Unimplemented(); return 0; }
+const char *Runtime1::pd_name_for_address(address entry) { Unimplemented(); }
diff --git a/src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp
index dabafb9288b..4bd509880f2 100644
--- a/src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp
@@ -64,31 +64,4 @@ void C2EntryBarrierStub::emit(C2_MacroAssembler& masm) {
__ emit_int32(0); // nmethod guard value
}
-int C2HandleAnonOMOwnerStub::max_size() const {
- // Max size of stub has been determined by testing with 0, in which case
- // C2CodeStubList::emit() will throw an assertion and report the actual size that
- // is needed.
- return 24;
-}
-
-void C2HandleAnonOMOwnerStub::emit(C2_MacroAssembler& masm) {
- __ bind(entry());
- Register mon = monitor();
- Register t = tmp();
- assert(t != noreg, "need tmp register");
-
- // Fix owner to be the current thread.
- __ str(rthread, Address(mon, ObjectMonitor::owner_offset()));
-
- // Pop owner object from lock-stack.
- __ ldrw(t, Address(rthread, JavaThread::lock_stack_top_offset()));
- __ subw(t, t, oopSize);
-#ifdef ASSERT
- __ str(zr, Address(rthread, t));
-#endif
- __ strw(t, Address(rthread, JavaThread::lock_stack_top_offset()));
-
- __ b(continuation());
-}
-
#undef __
diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
index 251ea3813ff..62831ee72ba 100644
--- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
@@ -64,8 +64,8 @@ void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg, Register
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp, oop);
- ldrw(tmp, Address(tmp, Klass::access_flags_offset()));
- tstw(tmp, JVM_ACC_IS_VALUE_BASED_CLASS);
+ ldrb(tmp, Address(tmp, Klass::misc_flags_offset()));
+ tst(tmp, KlassFlags::_misc_is_value_based_class);
br(Assembler::NE, cont);
}
@@ -150,10 +150,12 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, Registe
Register oop = objectReg;
Register box = boxReg;
Register disp_hdr = tmpReg;
+ Register owner_addr = tmpReg;
Register tmp = tmp2Reg;
Label cont;
Label object_has_monitor;
Label count, no_count;
+ Label unlocked;
assert(LockingMode != LM_LIGHTWEIGHT, "lightweight locking should use fast_unlock_lightweight");
assert_different_registers(oop, box, tmp, disp_hdr);
@@ -204,14 +206,40 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, Registe
b(cont);
bind(notRecursive);
+
+ // Compute owner address.
+ lea(owner_addr, Address(tmp, ObjectMonitor::owner_offset()));
+
+ // Set owner to null.
+ // Release to satisfy the JMM
+ stlr(zr, owner_addr);
+ // We need a full fence after clearing owner to avoid stranding.
+ // StoreLoad achieves this.
+ membar(StoreLoad);
+
+ // Check if the entry lists are empty.
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
+ ldr(tmpReg, Address(tmp, ObjectMonitor::cxq_offset()));
+ orr(rscratch1, rscratch1, tmpReg);
+ cmp(rscratch1, zr);
+ br(Assembler::EQ, cont); // If so we are done.
+
+ // Check if there is a successor.
+ ldr(rscratch1, Address(tmp, ObjectMonitor::succ_offset()));
+ cmp(rscratch1, zr);
+ br(Assembler::NE, unlocked); // If so we are done.
+
+ // Save the monitor pointer in the current thread, so we can try to
+ // reacquire the lock in SharedRuntime::monitor_exit_helper().
+ str(tmp, Address(rthread, JavaThread::unlocked_inflated_monitor_offset()));
+
+ cmp(zr, rthread); // Set Flag to NE => slow path
+ b(cont);
+
+ bind(unlocked);
+ cmp(zr, zr); // Set Flag to EQ => fast path
+
+ // Intentional fall-through
bind(cont);
// flag == EQ indicates success
@@ -224,10 +252,10 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, Registe
bind(no_count);
}
-void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1,
+void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Register t1,
Register t2, Register t3) {
assert(LockingMode == LM_LIGHTWEIGHT, "must be");
- assert_different_registers(obj, t1, t2, t3);
+ assert_different_registers(obj, box, t1, t2, t3);
// Handle inflated monitor.
Label inflated;
@@ -236,14 +264,20 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1,
// Finish fast lock unsuccessfully. MUST branch to with flag == NE
Label slow_path;
+ if (UseObjectMonitorTable) {
+ // Clear cache in case fast locking succeeds.
+ str(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
+ }
+
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(t1, obj);
- ldrw(t1, Address(t1, Klass::access_flags_offset()));
- tstw(t1, JVM_ACC_IS_VALUE_BASED_CLASS);
+ ldrb(t1, Address(t1, Klass::misc_flags_offset()));
+ tst(t1, KlassFlags::_misc_is_value_based_class);
br(Assembler::NE, slow_path);
}
const Register t1_mark = t1;
+ const Register t3_t = t3;
{ // Lightweight locking
@@ -251,7 +285,6 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1,
Label push;
const Register t2_top = t2;
- const Register t3_t = t3;
// Check if lock-stack is full.
ldrw(t2_top, Address(rthread, JavaThread::lock_stack_top_offset()));
@@ -289,26 +322,71 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1,
{ // Handle inflated monitor.
bind(inflated);
- // mark contains the tagged ObjectMonitor*.
- const Register t1_tagged_monitor = t1_mark;
- const uintptr_t monitor_tag = markWord::monitor_value;
+ const Register t1_monitor = t1;
+
+ if (!UseObjectMonitorTable) {
+ assert(t1_monitor == t1_mark, "should be the same here");
+ } else {
+ Label monitor_found;
+
+ // Load cache address
+ lea(t3_t, Address(rthread, JavaThread::om_cache_oops_offset()));
+
+ const int num_unrolled = 2;
+ for (int i = 0; i < num_unrolled; i++) {
+ ldr(t1, Address(t3_t));
+ cmp(obj, t1);
+ br(Assembler::EQ, monitor_found);
+ increment(t3_t, in_bytes(OMCache::oop_to_oop_difference()));
+ }
+
+ Label loop;
+
+ // Search for obj in cache.
+ bind(loop);
+
+ // Check for match.
+ ldr(t1, Address(t3_t));
+ cmp(obj, t1);
+ br(Assembler::EQ, monitor_found);
+
+ // Search until null encountered, guaranteed _null_sentinel at end.
+ increment(t3_t, in_bytes(OMCache::oop_to_oop_difference()));
+ cbnz(t1, loop);
+ // Cache Miss, NE set from cmp above, cbnz does not set flags
+ b(slow_path);
+
+ bind(monitor_found);
+ ldr(t1_monitor, Address(t3_t, OMCache::oop_to_monitor_difference()));
+ }
+
const Register t2_owner_addr = t2;
const Register t3_owner = t3;
+ const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value));
+ const Address owner_address(t1_monitor, ObjectMonitor::owner_offset() - monitor_tag);
+ const Address recursions_address(t1_monitor, ObjectMonitor::recursions_offset() - monitor_tag);
+
+ Label monitor_locked;
// Compute owner address.
- lea(t2_owner_addr, Address(t1_tagged_monitor, (in_bytes(ObjectMonitor::owner_offset()) - monitor_tag)));
+ lea(t2_owner_addr, owner_address);
// CAS owner (null => current thread).
cmpxchg(t2_owner_addr, zr, rthread, Assembler::xword, /*acquire*/ true,
/*release*/ false, /*weak*/ false, t3_owner);
- br(Assembler::EQ, locked);
+ br(Assembler::EQ, monitor_locked);
// Check if recursive.
cmp(t3_owner, rthread);
br(Assembler::NE, slow_path);
// Recursive.
- increment(Address(t1_tagged_monitor, in_bytes(ObjectMonitor::recursions_offset()) - monitor_tag), 1);
+ increment(recursions_address, 1);
+
+ bind(monitor_locked);
+ if (UseObjectMonitorTable) {
+ str(t1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
+ }
}
bind(locked);
@@ -331,13 +409,13 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1,
// C2 uses the value of Flags (NE vs EQ) to determine the continuation.
}
-void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Register t2,
- Register t3) {
+void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, Register t1,
+ Register t2, Register t3) {
assert(LockingMode == LM_LIGHTWEIGHT, "must be");
- assert_different_registers(obj, t1, t2, t3);
+ assert_different_registers(obj, box, t1, t2, t3);
// Handle inflated monitor.
- Label inflated, inflated_load_monitor;
+ Label inflated, inflated_load_mark;
// Finish fast unlock successfully. MUST branch to with flag == EQ
Label unlocked;
// Finish fast unlock unsuccessfully. MUST branch to with flag == NE
@@ -349,13 +427,15 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis
{ // Lightweight unlock
+ Label push_and_slow_path;
+
// Check if obj is top of lock-stack.
ldrw(t2_top, Address(rthread, JavaThread::lock_stack_top_offset()));
subw(t2_top, t2_top, oopSize);
ldr(t3_t, Address(rthread, t2_top));
cmp(obj, t3_t);
// Top of lock stack was not obj. Must be monitor.
- br(Assembler::NE, inflated_load_monitor);
+ br(Assembler::NE, inflated_load_mark);
// Pop lock-stack.
DEBUG_ONLY(str(zr, Address(rthread, t2_top));)
@@ -372,7 +452,10 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis
ldr(t1_mark, Address(obj, oopDesc::mark_offset_in_bytes()));
// Check header for monitor (0b10).
- tbnz(t1_mark, exact_log2(markWord::monitor_value), inflated);
+ // Because we got here by popping (meaning we pushed in locked)
+ // there will be no monitor in the box. So we need to push back the obj
+ // so that the runtime can fix any potential anonymous owner.
+ tbnz(t1_mark, exact_log2(markWord::monitor_value), UseObjectMonitorTable ? push_and_slow_path : inflated);
// Try to unlock. Transition lock bits 0b00 => 0b01
assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid lea");
@@ -381,6 +464,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis
/*acquire*/ false, /*release*/ true, /*weak*/ false, noreg);
br(Assembler::EQ, unlocked);
+ bind(push_and_slow_path);
// Compare and exchange failed.
// Restore lock-stack and handle the unlock in runtime.
DEBUG_ONLY(str(obj, Address(rthread, t2_top));)
@@ -391,7 +475,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis
{ // Handle inflated monitor.
- bind(inflated_load_monitor);
+ bind(inflated_load_mark);
ldr(t1_mark, Address(obj, oopDesc::mark_offset_in_bytes()));
#ifdef ASSERT
tbnz(t1_mark, exact_log2(markWord::monitor_value), inflated);
@@ -412,12 +496,19 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis
bind(check_done);
#endif
- // mark contains the tagged ObjectMonitor*.
- const Register t1_monitor = t1_mark;
- const uintptr_t monitor_tag = markWord::monitor_value;
+ const Register t1_monitor = t1;
+
+ if (!UseObjectMonitorTable) {
+ assert(t1_monitor == t1_mark, "should be the same here");
- // Untag the monitor.
- sub(t1_monitor, t1_mark, monitor_tag);
+ // Untag the monitor.
+ add(t1_monitor, t1_mark, -(int)markWord::monitor_value);
+ } else {
+ ldr(t1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
+ // null check with Flags == NE, no valid pointer below alignof(ObjectMonitor*)
+ cmp(t1_monitor, checked_cast(alignof(ObjectMonitor*)));
+ br(Assembler::LO, slow_path);
+ }
const Register t2_recursions = t2;
Label not_recursive;
@@ -435,33 +526,41 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis
bind(not_recursive);
- Label release;
const Register t2_owner_addr = t2;
// Compute owner address.
lea(t2_owner_addr, Address(t1_monitor, ObjectMonitor::owner_offset()));
+ // Set owner to null.
+ // Release to satisfy the JMM
+ stlr(zr, t2_owner_addr);
+ // We need a full fence after clearing owner to avoid stranding.
+ // StoreLoad achieves this.
+ membar(StoreLoad);
+
// Check if the entry lists are empty.
ldr(rscratch1, Address(t1_monitor, ObjectMonitor::EntryList_offset()));
ldr(t3_t, Address(t1_monitor, ObjectMonitor::cxq_offset()));
orr(rscratch1, rscratch1, t3_t);
cmp(rscratch1, zr);
- br(Assembler::EQ, release);
+ br(Assembler::EQ, unlocked); // If so we are done.
- // The owner may be anonymous and we removed the last obj entry in
- // the lock-stack. This loses the information about the owner.
- // Write the thread to the owner field so the runtime knows the owner.
- str(rthread, Address(t2_owner_addr));
- b(slow_path);
+ // Check if there is a successor.
+ ldr(rscratch1, Address(t1_monitor, ObjectMonitor::succ_offset()));
+ cmp(rscratch1, zr);
+ br(Assembler::NE, unlocked); // If so we are done.
- bind(release);
- // Set owner to null.
- // Release to satisfy the JMM
- stlr(zr, t2_owner_addr);
+ // Save the monitor pointer in the current thread, so we can try to
+ // reacquire the lock in SharedRuntime::monitor_exit_helper().
+ str(t1_monitor, Address(rthread, JavaThread::unlocked_inflated_monitor_offset()));
+
+ cmp(zr, rthread); // Set Flag to NE => slow path
+ b(slow_path);
}
bind(unlocked);
decrement(Address(rthread, JavaThread::held_monitor_count_offset()));
+ cmp(zr, zr); // Set Flags to EQ => fast path
#ifdef ASSERT
// Check that unlocked label is reached with Flags == EQ.
diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
index 1481f975020..43e60ae5a48 100644
--- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
@@ -39,8 +39,8 @@
void fast_lock(Register object, Register box, Register tmp, Register tmp2, Register tmp3);
void fast_unlock(Register object, Register box, Register tmp, Register tmp2);
// Code used by cmpFastLockLightweight and cmpFastUnlockLightweight mach instructions in .ad file.
- void fast_lock_lightweight(Register object, Register t1, Register t2, Register t3);
- void fast_unlock_lightweight(Register object, Register t1, Register t2, Register t3);
+ void fast_lock_lightweight(Register object, Register box, Register t1, Register t2, Register t3);
+ void fast_unlock_lightweight(Register object, Register box, Register t1, Register t2, Register t3);
void string_compare(Register str1, Register str2,
Register cnt1, Register cnt2, Register result,
diff --git a/src/hotspot/cpu/aarch64/cas.m4 b/src/hotspot/cpu/aarch64/cas.m4
index f8aac0c4939..7e13e153db1 100644
--- a/src/hotspot/cpu/aarch64/cas.m4
+++ b/src/hotspot/cpu/aarch64/cas.m4
@@ -45,7 +45,9 @@ define(`CAS_INSN',
// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
instruct compareAndExchange$1$6(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{
ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));),
+ $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);),
$1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);),
+ $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);),
$6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),
`dnl')
match(Set res (CompareAndExchange$1 mem (Binary oldval newval)));
@@ -122,7 +124,9 @@ define(`CAS_INSN3',
// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
instruct weakCompareAndSwap$1$6(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{
ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));),
+ $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);),
$1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);),
+ $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);),
$6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),
`dnl')
match(Set res (WeakCompareAndSwap$1 mem (Binary oldval newval)));
diff --git a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp
index 54af69ffaba..fc78813c161 100644
--- a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp
@@ -129,5 +129,7 @@ void CompressedKlassPointers::initialize(address addr, size_t len) {
address const end = addr + len;
_base = (end <= (address)unscaled_max) ? nullptr : addr;
- _range = end - _base;
+ // Remember the Klass range:
+ _klass_range_start = addr;
+ _klass_range_end = addr + len;
}
diff --git a/src/hotspot/cpu/aarch64/copy_aarch64.hpp b/src/hotspot/cpu/aarch64/copy_aarch64.hpp
index 0ff9ace59cc..5ccf2cd835e 100644
--- a/src/hotspot/cpu/aarch64/copy_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/copy_aarch64.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -64,28 +64,34 @@ static void pd_zero_to_bytes(void* to, size_t count) {
" br %[t0];\n" \
" .align 5;\n" \
"0:" \
+" hint #0x24; // bti j\n" \
" b 1f;\n" \
" .align 5;\n" \
+" hint #0x24; // bti j\n" \
" ldr %[t0], [%[s], #0];\n" \
" str %[t0], [%[d], #0];\n" \
" b 1f;\n" \
" .align 5;\n" \
+" hint #0x24; // bti j\n" \
" ldp %[t0], %[t1], [%[s], #0];\n" \
" stp %[t0], %[t1], [%[d], #0];\n" \
" b 1f;\n" \
" .align 5;\n" \
+" hint #0x24; // bti j\n" \
" ldp %[t0], %[t1], [%[s], #0];\n" \
" ldr %[t2], [%[s], #16];\n" \
" stp %[t0], %[t1], [%[d], #0];\n" \
" str %[t2], [%[d], #16];\n" \
" b 1f;\n" \
" .align 5;\n" \
+" hint #0x24; // bti j\n" \
" ldp %[t0], %[t1], [%[s], #0];\n" \
" ldp %[t2], %[t3], [%[s], #16];\n" \
" stp %[t0], %[t1], [%[d], #0];\n" \
" stp %[t2], %[t3], [%[d], #16];\n" \
" b 1f;\n" \
" .align 5;\n" \
+" hint #0x24; // bti j\n" \
" ldp %[t0], %[t1], [%[s], #0];\n" \
" ldp %[t2], %[t3], [%[s], #16];\n" \
" ldr %[t4], [%[s], #32];\n" \
@@ -94,6 +100,7 @@ static void pd_zero_to_bytes(void* to, size_t count) {
" str %[t4], [%[d], #32];\n" \
" b 1f;\n" \
" .align 5;\n" \
+" hint #0x24; // bti j\n" \
" ldp %[t0], %[t1], [%[s], #0];\n" \
" ldp %[t2], %[t3], [%[s], #16];\n" \
" ldp %[t4], %[t5], [%[s], #32];\n" \
@@ -103,6 +110,7 @@ static void pd_zero_to_bytes(void* to, size_t count) {
" stp %[t4], %[t5], [%[d], #32];\n" \
" b 1f;\n" \
" .align 5;\n" \
+" hint #0x24; // bti j\n" \
" ldr %[t6], [%[s], #0];\n" \
" ldp %[t0], %[t1], [%[s], #8];\n" \
" ldp %[t2], %[t3], [%[s], #24];\n" \
@@ -110,6 +118,7 @@ static void pd_zero_to_bytes(void* to, size_t count) {
" str %[t6], [%[d]], #8;\n" \
" b 2b;\n" \
" .align 5;\n" \
+" hint #0x24; // bti j\n" \
" ldp %[t0], %[t1], [%[s], #0];\n" \
" ldp %[t2], %[t3], [%[s], #16];\n" \
" ldp %[t4], %[t5], [%[s], #32];\n" \
diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp
index 0387f763bbd..c2b127f31bb 100644
--- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp
@@ -293,7 +293,7 @@ void frame::patch_pc(Thread* thread, address pc) {
// Either the return address is the original one or we are going to
// patch in the same address that's already there.
- assert(_pc == pc_old || pc == pc_old || pc_old == 0, "");
+ assert(_pc == pc_old || pc == pc_old || pc_old == nullptr, "");
DEBUG_ONLY(address old_pc = _pc;)
*pc_addr = signed_pc;
_pc = pc; // must be set before call to get_deopt_original_pc
@@ -497,10 +497,10 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
assert(is_interpreted_frame(), "Not an interpreted frame");
// These are reasonable sanity checks
- if (fp() == 0 || (intptr_t(fp()) & (wordSize-1)) != 0) {
+ if (fp() == nullptr || (intptr_t(fp()) & (wordSize-1)) != 0) {
return false;
}
- if (sp() == 0 || (intptr_t(sp()) & (wordSize-1)) != 0) {
+ if (sp() == nullptr || (intptr_t(sp()) & (wordSize-1)) != 0) {
return false;
}
if (fp() + interpreter_frame_initial_sp_offset < sp()) {
diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp
index d02038b6e91..b978c350ce1 100644
--- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp
@@ -38,7 +38,10 @@
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "gc/g1/c1/g1BarrierSetC1.hpp"
-#endif
+#endif // COMPILER1
+#ifdef COMPILER2
+#include "gc/g1/c2/g1BarrierSetC2.hpp"
+#endif // COMPILER2
#define __ masm->
@@ -95,6 +98,54 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas
__ pop(saved_regs, sp);
}
+static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime,
+ const Register thread, const Register value, const Register temp1, const Register temp2) {
+ // Can we store a value in the given thread's buffer?
+ // (The index field is typed as size_t.)
+ __ ldr(temp1, Address(thread, in_bytes(index_offset))); // temp1 := *(index address)
+ __ cbz(temp1, runtime); // jump to runtime if index == 0 (full buffer)
+ // The buffer is not full, store value into it.
+ __ sub(temp1, temp1, wordSize); // temp1 := next index
+ __ str(temp1, Address(thread, in_bytes(index_offset))); // *(index address) := next index
+ __ ldr(temp2, Address(thread, in_bytes(buffer_offset))); // temp2 := buffer address
+ __ str(value, Address(temp2, temp1)); // *(buffer address + next index) := value
+}
+
+static void generate_pre_barrier_fast_path(MacroAssembler* masm,
+ const Register thread,
+ const Register tmp1) {
+ Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
+ // Is marking active?
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ ldrw(tmp1, in_progress);
+ } else {
+ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ ldrb(tmp1, in_progress);
+ }
+}
+
+static void generate_pre_barrier_slow_path(MacroAssembler* masm,
+ const Register obj,
+ const Register pre_val,
+ const Register thread,
+ const Register tmp1,
+ const Register tmp2,
+ Label& done,
+ Label& runtime) {
+ // Do we need to load the previous value?
+ if (obj != noreg) {
+ __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);
+ }
+ // Is the previous value null?
+ __ cbz(pre_val, done);
+ generate_queue_test_and_insertion(masm,
+ G1ThreadLocalData::satb_mark_queue_index_offset(),
+ G1ThreadLocalData::satb_mark_queue_buffer_offset(),
+ runtime,
+ thread, pre_val, tmp1, tmp2);
+ __ b(done);
+}
+
void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
Register obj,
Register pre_val,
@@ -115,43 +166,10 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
assert_different_registers(obj, pre_val, tmp1, tmp2);
assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register");
- Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
- Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
- Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
-
- // Is marking active?
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- __ ldrw(tmp1, in_progress);
- } else {
- assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- __ ldrb(tmp1, in_progress);
- }
+ generate_pre_barrier_fast_path(masm, thread, tmp1);
+ // If marking is not active (*(mark queue active address) == 0), jump to done
__ cbzw(tmp1, done);
-
- // Do we need to load the previous value?
- if (obj != noreg) {
- __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);
- }
-
- // Is the previous value null?
- __ cbz(pre_val, done);
-
- // Can we store original value in the thread's buffer?
- // Is index == 0?
- // (The index field is typed as size_t.)
-
- __ ldr(tmp1, index); // tmp := *index_adr
- __ cbz(tmp1, runtime); // tmp == 0?
- // If yes, goto runtime
-
- __ sub(tmp1, tmp1, wordSize); // tmp := tmp - wordSize
- __ str(tmp1, index); // *index_adr := tmp
- __ ldr(tmp2, buffer);
- __ add(tmp1, tmp1, tmp2); // tmp := tmp + *buffer_adr
-
- // Record the previous value
- __ str(pre_val, Address(tmp1, 0));
- __ b(done);
+ generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, done, runtime);
__ bind(runtime);
@@ -182,6 +200,50 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
}
+static void generate_post_barrier_fast_path(MacroAssembler* masm,
+ const Register store_addr,
+ const Register new_val,
+ const Register tmp1,
+ const Register tmp2,
+ Label& done,
+ bool new_val_may_be_null) {
+ // Does store cross heap regions?
+ __ eor(tmp1, store_addr, new_val); // tmp1 := store address ^ new value
+ __ lsr(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
+ __ cbz(tmp1, done);
+ // Crosses regions, storing null?
+ if (new_val_may_be_null) {
+ __ cbz(new_val, done);
+ }
+ // Storing region crossing non-null, is card young?
+ __ lsr(tmp1, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base
+ __ load_byte_map_base(tmp2); // tmp2 := card table base address
+ __ add(tmp1, tmp1, tmp2); // tmp1 := card address
+ __ ldrb(tmp2, Address(tmp1)); // tmp2 := card
+ __ cmpw(tmp2, (int)G1CardTable::g1_young_card_val()); // tmp2 := card == young_card_val?
+}
+
+static void generate_post_barrier_slow_path(MacroAssembler* masm,
+ const Register thread,
+ const Register tmp1,
+ const Register tmp2,
+ Label& done,
+ Label& runtime) {
+ __ membar(Assembler::StoreLoad); // StoreLoad membar
+ __ ldrb(tmp2, Address(tmp1)); // tmp2 := card
+ __ cbzw(tmp2, done);
+ // Storing a region crossing, non-null oop, card is clean.
+ // Dirty card and log.
+ STATIC_ASSERT(CardTable::dirty_card_val() == 0);
+ __ strb(zr, Address(tmp1)); // *(card address) := dirty_card_val
+ generate_queue_test_and_insertion(masm,
+ G1ThreadLocalData::dirty_card_queue_index_offset(),
+ G1ThreadLocalData::dirty_card_queue_buffer_offset(),
+ runtime,
+ thread, tmp1, tmp2, rscratch1);
+ __ b(done);
+}
+
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
Register store_addr,
Register new_val,
@@ -194,70 +256,116 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
assert(store_addr != noreg && new_val != noreg && tmp1 != noreg
&& tmp2 != noreg, "expecting a register");
- Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
- Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
-
- BarrierSet* bs = BarrierSet::barrier_set();
- CardTableBarrierSet* ctbs = barrier_set_cast(bs);
- CardTable* ct = ctbs->card_table();
-
Label done;
Label runtime;
- // Does store cross heap regions?
+ generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */);
+ // If card is young, jump to done
+ __ br(Assembler::EQ, done);
+ generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, done, runtime);
- __ eor(tmp1, store_addr, new_val);
- __ lsr(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes);
- __ cbz(tmp1, done);
+ __ bind(runtime);
+ // save the live input values
+ RegSet saved = RegSet::of(store_addr);
+ __ push(saved, sp);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp1, thread);
+ __ pop(saved, sp);
- // crosses regions, storing null?
+ __ bind(done);
+}
- __ cbz(new_val, done);
+#if defined(COMPILER2)
- // storing region crossing non-null, is card already dirty?
+static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) {
+ SaveLiveRegisters save_registers(masm, stub);
+ if (c_rarg0 != arg) {
+ __ mov(c_rarg0, arg);
+ }
+ __ mov(c_rarg1, rthread);
+ __ mov(rscratch1, runtime_path);
+ __ blr(rscratch1);
+}
- const Register card_addr = tmp1;
+void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2,
+ G1PreBarrierStubC2* stub) {
+ assert(thread == rthread, "must be");
+ assert_different_registers(obj, pre_val, tmp1, tmp2);
+ assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register");
- __ lsr(card_addr, store_addr, CardTable::card_shift());
+ stub->initialize_registers(obj, pre_val, thread, tmp1, tmp2);
- // get the address of the card
- __ load_byte_map_base(tmp2);
- __ add(card_addr, card_addr, tmp2);
- __ ldrb(tmp2, Address(card_addr));
- __ cmpw(tmp2, (int)G1CardTable::g1_young_card_val());
- __ br(Assembler::EQ, done);
+ generate_pre_barrier_fast_path(masm, thread, tmp1);
+ // If marking is active (*(mark queue active address) != 0), jump to stub (slow path)
+ __ cbnzw(tmp1, *stub->entry());
- assert((int)CardTable::dirty_card_val() == 0, "must be 0");
+ __ bind(*stub->continuation());
+}
- __ membar(Assembler::StoreLoad);
+void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
+ G1PreBarrierStubC2* stub) const {
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ Label runtime;
+ Register obj = stub->obj();
+ Register pre_val = stub->pre_val();
+ Register thread = stub->thread();
+ Register tmp1 = stub->tmp1();
+ Register tmp2 = stub->tmp2();
- __ ldrb(tmp2, Address(card_addr));
- __ cbzw(tmp2, done);
+ __ bind(*stub->entry());
+ generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, *stub->continuation(), runtime);
- // storing a region crossing, non-null oop, card is clean.
- // dirty card and log.
+ __ bind(runtime);
+ generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry));
+ __ b(*stub->continuation());
+}
- __ strb(zr, Address(card_addr));
+void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2,
+ G1PostBarrierStubC2* stub) {
+ assert(thread == rthread, "must be");
+ assert_different_registers(store_addr, new_val, thread, tmp1, tmp2,
+ rscratch1);
+ assert(store_addr != noreg && new_val != noreg && tmp1 != noreg
+ && tmp2 != noreg, "expecting a register");
- __ ldr(rscratch1, queue_index);
- __ cbz(rscratch1, runtime);
- __ sub(rscratch1, rscratch1, wordSize);
- __ str(rscratch1, queue_index);
+ stub->initialize_registers(thread, tmp1, tmp2);
- __ ldr(tmp2, buffer);
- __ str(card_addr, Address(tmp2, rscratch1));
- __ b(done);
+ bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0;
+ generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null);
+ // If card is not young, jump to stub (slow path)
+ __ br(Assembler::NE, *stub->entry());
- __ bind(runtime);
- // save the live input values
- RegSet saved = RegSet::of(store_addr);
- __ push(saved, sp);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread);
- __ pop(saved, sp);
+ __ bind(*stub->continuation());
+}
- __ bind(done);
+void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
+ G1PostBarrierStubC2* stub) const {
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ Label runtime;
+ Register thread = stub->thread();
+ Register tmp1 = stub->tmp1(); // tmp1 holds the card address.
+ Register tmp2 = stub->tmp2();
+ assert(stub->tmp3() == noreg, "not needed in this platform");
+
+ __ bind(*stub->entry());
+ generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, *stub->continuation(), runtime);
+
+ __ bind(runtime);
+ generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry));
+ __ b(*stub->continuation());
}
+#endif // COMPILER2
+
void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Address src, Register tmp1, Register tmp2) {
bool on_oop = is_reference_type(type);
diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp
index 7b4bc8cdc49..4baa18cb945 100644
--- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp
@@ -33,6 +33,8 @@ class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
class G1PostBarrierStub;
+class G1PreBarrierStubC2;
+class G1PostBarrierStubC2;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@@ -69,6 +71,27 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
#endif
+#ifdef COMPILER2
+ void g1_write_barrier_pre_c2(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2,
+ G1PreBarrierStubC2* c2_stub);
+ void generate_c2_pre_barrier_stub(MacroAssembler* masm,
+ G1PreBarrierStubC2* stub) const;
+ void g1_write_barrier_post_c2(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2,
+ G1PostBarrierStubC2* c2_stub);
+ void generate_c2_post_barrier_stub(MacroAssembler* masm,
+ G1PostBarrierStubC2* stub) const;
+#endif
+
void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Address src, Register tmp1, Register tmp2);
};
diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad b/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad
new file mode 100644
index 00000000000..081a67d6880
--- /dev/null
+++ b/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad
@@ -0,0 +1,680 @@
+//
+// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+//
+// This code is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 2 only, as
+// published by the Free Software Foundation.
+//
+// This code is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// version 2 for more details (a copy is included in the LICENSE file that
+// accompanied this code).
+//
+// You should have received a copy of the GNU General Public License version
+// 2 along with this work; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+// or visit www.oracle.com if you need additional information or have any
+// questions.
+//
+
+source_hpp %{
+
+#include "gc/g1/c2/g1BarrierSetC2.hpp"
+#include "gc/shared/gc_globals.hpp"
+
+%}
+
+source %{
+
+#include "gc/g1/g1BarrierSetAssembler_aarch64.hpp"
+#include "gc/g1/g1BarrierSetRuntime.hpp"
+
+static void write_barrier_pre(MacroAssembler* masm,
+ const MachNode* node,
+ Register obj,
+ Register pre_val,
+ Register tmp1,
+ Register tmp2,
+ RegSet preserve = RegSet(),
+ RegSet no_preserve = RegSet()) {
+ if (!G1PreBarrierStubC2::needs_barrier(node)) {
+ return;
+ }
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
+ G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node);
+ for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) {
+ stub->preserve(*reg);
+ }
+ for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) {
+ stub->dont_preserve(*reg);
+ }
+ g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, rthread, tmp1, tmp2, stub);
+}
+
+static void write_barrier_post(MacroAssembler* masm,
+ const MachNode* node,
+ Register store_addr,
+ Register new_val,
+ Register tmp1,
+ Register tmp2) {
+ if (!G1PostBarrierStubC2::needs_barrier(node)) {
+ return;
+ }
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
+ G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
+ g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, rthread, tmp1, tmp2, stub);
+}
+
+%}
+
+// BEGIN This section of the file is automatically generated. Do not edit --------------
+
+// This section is generated from g1_aarch64.m4
+
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1StoreP(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && !needs_releasing_store(n) && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreP mem src));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(INSN_COST);
+ format %{ "str $src, $mem\t# ptr" %}
+ ins_encode %{
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ __ str($src$$Register, $mem$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $src$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(istore_reg_mem);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1StorePVolatile(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_releasing_store(n) && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreP mem src));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "stlr $src, $mem\t# ptr" %}
+ ins_encode %{
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ __ stlr($src$$Register, $mem$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $src$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_class_memory);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1StoreN(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && !needs_releasing_store(n) && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreN mem src));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(INSN_COST);
+ format %{ "strw $src, $mem\t# compressed ptr" %}
+ ins_encode %{
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ __ strw($src$$Register, $mem$$Register);
+ if ((barrier_data() & G1C2BarrierPost) != 0) {
+ if ((barrier_data() & G1C2BarrierPostNotNull) == 0) {
+ __ decode_heap_oop($tmp1$$Register, $src$$Register);
+ } else {
+ __ decode_heap_oop_not_null($tmp1$$Register, $src$$Register);
+ }
+ }
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(istore_reg_mem);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1StoreNVolatile(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_releasing_store(n) && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreN mem src));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "stlrw $src, $mem\t# compressed ptr" %}
+ ins_encode %{
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ __ stlrw($src$$Register, $mem$$Register);
+ if ((barrier_data() & G1C2BarrierPost) != 0) {
+ if ((barrier_data() & G1C2BarrierPostNotNull) == 0) {
+ __ decode_heap_oop($tmp1$$Register, $src$$Register);
+ } else {
+ __ decode_heap_oop_not_null($tmp1$$Register, $src$$Register);
+ }
+ }
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_class_memory);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1EncodePAndStoreN(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && !needs_releasing_store(n) && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreN mem (EncodeP src)));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(INSN_COST);
+ format %{ "encode_heap_oop $tmp1, $src\n\t"
+ "strw $tmp1, $mem\t# compressed ptr" %}
+ ins_encode %{
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ if ((barrier_data() & G1C2BarrierPostNotNull) == 0) {
+ __ encode_heap_oop($tmp1$$Register, $src$$Register);
+ } else {
+ __ encode_heap_oop_not_null($tmp1$$Register, $src$$Register);
+ }
+ __ strw($tmp1$$Register, $mem$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $src$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(istore_reg_mem);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1EncodePAndStoreNVolatile(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_releasing_store(n) && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreN mem (EncodeP src)));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "encode_heap_oop $tmp1, $src\n\t"
+ "stlrw $tmp1, $mem\t# compressed ptr" %}
+ ins_encode %{
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ if ((barrier_data() & G1C2BarrierPostNotNull) == 0) {
+ __ encode_heap_oop($tmp1$$Register, $src$$Register);
+ } else {
+ __ encode_heap_oop_not_null($tmp1$$Register, $src$$Register);
+ }
+ __ stlrw($tmp1$$Register, $mem$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $src$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_class_memory);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1CompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr)
+%{
+ predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(2 * VOLATILE_REF_COST);
+ format %{ "cmpxchg $res = $mem, $oldval, $newval\t# ptr" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ // Pass $oldval to the pre-barrier (instead of loading from $mem), because
+ // $oldval is the only value that can be overwritten.
+ // The same holds for g1CompareAndSwapP and its Acq variant.
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $oldval$$Register /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword,
+ false /* acquire */, true /* release */, false /* weak */, $res$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1CompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# ptr" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ // Pass $oldval to the pre-barrier (instead of loading from $mem), because
+ // $oldval is the only value that can be overwritten.
+ // The same holds for g1CompareAndSwapP and its Acq variant.
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $oldval$$Register /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword,
+ true /* acquire */, true /* release */, false /* weak */, $res$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1CompareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(2 * VOLATILE_REF_COST);
+ format %{ "cmpxchg $res = $mem, $oldval, $newval\t# narrow oop" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word,
+ false /* acquire */, true /* release */, false /* weak */, $res$$Register);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1CompareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# narrow oop" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word,
+ true /* acquire */, true /* release */, false /* weak */, $res$$Register);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1CompareAndSwapP(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapP mem (Binary oldval newval)));
+ match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(2 * VOLATILE_REF_COST);
+ format %{ "cmpxchg $mem, $oldval, $newval\t# (ptr)\n\t"
+ "cset $res, EQ" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $oldval$$Register /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword,
+ false /* acquire */, true /* release */, false /* weak */, noreg);
+ __ cset($res$$Register, Assembler::EQ);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1CompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapP mem (Binary oldval newval)));
+ match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (ptr)\n\t"
+ "cset $res, EQ" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $oldval$$Register /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword,
+ true /* acquire */, true /* release */, false /* weak */, noreg);
+ __ cset($res$$Register, Assembler::EQ);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1CompareAndSwapN(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapN mem (Binary oldval newval)));
+ match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(2 * VOLATILE_REF_COST);
+ format %{ "cmpxchg $mem, $oldval, $newval\t# (narrow oop)\n\t"
+ "cset $res, EQ" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word,
+ false /* acquire */, true /* release */, false /* weak */, noreg);
+ __ cset($res$$Register, Assembler::EQ);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1CompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapN mem (Binary oldval newval)));
+ match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (narrow oop)\n\t"
+ "cset $res, EQ" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word,
+ true /* acquire */, true /* release */, false /* weak */, noreg);
+ __ cset($res$$Register, Assembler::EQ);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1GetAndSetP(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set preval (GetAndSetP mem newval));
+ effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(2 * VOLATILE_REF_COST);
+ format %{ "atomic_xchg $preval, $newval, [$mem]" %}
+ ins_encode %{
+ assert_different_registers($mem$$Register, $newval$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $preval$$Register /* pre_val (as a temporary register) */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */);
+ __ atomic_xchg($preval$$Register, $newval$$Register, $mem$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_serial);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1GetAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set preval (GetAndSetP mem newval));
+ effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "atomic_xchg_acq $preval, $newval, [$mem]" %}
+ ins_encode %{
+ assert_different_registers($mem$$Register, $newval$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $preval$$Register /* pre_val (as a temporary register) */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */);
+ __ atomic_xchgal($preval$$Register, $newval$$Register, $mem$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_serial);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1GetAndSetN(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set preval (GetAndSetN mem newval));
+ effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(2 * VOLATILE_REF_COST);
+ format %{ "atomic_xchgw $preval, $newval, [$mem]" %}
+ ins_encode %{
+ assert_different_registers($mem$$Register, $newval$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */);
+ __ atomic_xchgw($preval$$Register, $newval$$Register, $mem$$Register);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_serial);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1GetAndSetNAcq(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set preval (GetAndSetN mem newval));
+ effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "atomic_xchgw_acq $preval, $newval, [$mem]" %}
+ ins_encode %{
+ assert_different_registers($mem$$Register, $newval$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */);
+ __ atomic_xchgalw($preval$$Register, $newval$$Register, $mem$$Register);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_serial);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1LoadP(iRegPNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr)
+%{
+ // This instruction does not need an acquiring counterpart because it is only
+ // used for reference loading (Reference::get()). The same holds for g1LoadN.
+ predicate(UseG1GC && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0);
+ match(Set dst (LoadP mem));
+ effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(4 * INSN_COST);
+ format %{ "ldr $dst, $mem\t# ptr" %}
+ ins_encode %{
+ __ ldr($dst$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $dst$$Register /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(iload_reg_mem);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1LoadN(iRegNNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0);
+ match(Set dst (LoadN mem));
+ effect(TEMP dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(4 * INSN_COST);
+ format %{ "ldrw $dst, $mem\t# compressed ptr" %}
+ ins_encode %{
+ __ ldrw($dst$$Register, $mem$$Register);
+ if ((barrier_data() & G1C2BarrierPre) != 0) {
+ __ decode_heap_oop($tmp1$$Register, $dst$$Register);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ }
+ %}
+ ins_pipe(iload_reg_mem);
+%}
+
+// END This section of the file is automatically generated. Do not edit --------------
diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.m4 b/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.m4
new file mode 100644
index 00000000000..8fb1f7e8e42
--- /dev/null
+++ b/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.m4
@@ -0,0 +1,384 @@
+dnl Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+dnl DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+dnl
+dnl This code is free software; you can redistribute it and/or modify it
+dnl under the terms of the GNU General Public License version 2 only, as
+dnl published by the Free Software Foundation.
+dnl
+dnl This code is distributed in the hope that it will be useful, but WITHOUT
+dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+dnl version 2 for more details (a copy is included in the LICENSE file that
+dnl accompanied this code).
+dnl
+dnl You should have received a copy of the GNU General Public License version
+dnl 2 along with this work; if not, write to the Free Software Foundation,
+dnl Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+dnl
+dnl Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+dnl or visit www.oracle.com if you need additional information or have any
+dnl questions.
+dnl
+// BEGIN This section of the file is automatically generated. Do not edit --------------
+
+// This section is generated from g1_aarch64.m4
+
+define(`STOREP_INSN',
+`
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1StoreP$1(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && ifelse($1,Volatile,'needs_releasing_store(n)`,'!needs_releasing_store(n)`) && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreP mem src));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(ifelse($1,Volatile,VOLATILE_REF_COST,INSN_COST));
+ format %{ "$2 $src, $mem\t# ptr" %}
+ ins_encode %{
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ __ $2($src$$Register, $mem$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $src$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(ifelse($1,Volatile,pipe_class_memory,istore_reg_mem));
+%}')dnl
+STOREP_INSN(,str)
+STOREP_INSN(Volatile,stlr)
+dnl
+define(`STOREN_INSN',
+`
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1StoreN$1(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && ifelse($1,Volatile,'needs_releasing_store(n)`,'!needs_releasing_store(n)`) && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreN mem src));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(ifelse($1,Volatile,VOLATILE_REF_COST,INSN_COST));
+ format %{ "$2 $src, $mem\t# compressed ptr" %}
+ ins_encode %{
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ __ $2($src$$Register, $mem$$Register);
+ if ((barrier_data() & G1C2BarrierPost) != 0) {
+ if ((barrier_data() & G1C2BarrierPostNotNull) == 0) {
+ __ decode_heap_oop($tmp1$$Register, $src$$Register);
+ } else {
+ __ decode_heap_oop_not_null($tmp1$$Register, $src$$Register);
+ }
+ }
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(ifelse($1,Volatile,pipe_class_memory,istore_reg_mem));
+%}')dnl
+STOREN_INSN(,strw)
+STOREN_INSN(Volatile,stlrw)
+dnl
+define(`ENCODESTOREN_INSN',
+`
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1EncodePAndStoreN$1(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && ifelse($1,Volatile,'needs_releasing_store(n)`,'!needs_releasing_store(n)`) && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreN mem (EncodeP src)));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(ifelse($1,Volatile,VOLATILE_REF_COST,INSN_COST));
+ format %{ "encode_heap_oop $tmp1, $src\n\t"
+ "$2 $tmp1, $mem\t# compressed ptr" %}
+ ins_encode %{
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ if ((barrier_data() & G1C2BarrierPostNotNull) == 0) {
+ __ encode_heap_oop($tmp1$$Register, $src$$Register);
+ } else {
+ __ encode_heap_oop_not_null($tmp1$$Register, $src$$Register);
+ }
+ __ $2($tmp1$$Register, $mem$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $src$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(ifelse($1,Volatile,pipe_class_memory,istore_reg_mem));
+%}')dnl
+ENCODESTOREN_INSN(,strw)
+ENCODESTOREN_INSN(Volatile,stlrw)
+dnl
+define(`CAEP_INSN',
+`
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1CompareAndExchangeP$1(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr)
+%{
+ predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST));
+ format %{ "cmpxchg$2 $res = $mem, $oldval, $newval\t# ptr" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ // Pass $oldval to the pre-barrier (instead of loading from $mem), because
+ // $oldval is the only value that can be overwritten.
+ // The same holds for g1CompareAndSwapP and its Acq variant.
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $oldval$$Register /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword,
+ $3 /* acquire */, true /* release */, false /* weak */, $res$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}')dnl
+CAEP_INSN(,,false)
+CAEP_INSN(Acq,_acq,true)
+dnl
+define(`CAEN_INSN',
+`
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1CompareAndExchangeN$1(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST));
+ format %{ "cmpxchg$2 $res = $mem, $oldval, $newval\t# narrow oop" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word,
+ $3 /* acquire */, true /* release */, false /* weak */, $res$$Register);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}')dnl
+CAEN_INSN(,,false)
+CAEN_INSN(Acq,_acq,true)
+dnl
+define(`CASP_INSN',
+`
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1CompareAndSwapP$1(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapP mem (Binary oldval newval)));
+ match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST));
+ format %{ "cmpxchg$2 $mem, $oldval, $newval\t# (ptr)\n\t"
+ "cset $res, EQ" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $oldval$$Register /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword,
+ $3 /* acquire */, true /* release */, false /* weak */, noreg);
+ __ cset($res$$Register, Assembler::EQ);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}')dnl
+CASP_INSN(,,false)
+CASP_INSN(Acq,_acq,true)
+dnl
+define(`CASN_INSN',
+`
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1CompareAndSwapN$1(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapN mem (Binary oldval newval)));
+ match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST));
+ format %{ "cmpxchg$2 $mem, $oldval, $newval\t# (narrow oop)\n\t"
+ "cset $res, EQ" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word,
+ $3 /* acquire */, true /* release */, false /* weak */, noreg);
+ __ cset($res$$Register, Assembler::EQ);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}')dnl
+CASN_INSN(,,false)
+CASN_INSN(Acq,_acq,true)
+dnl
+define(`XCHGP_INSN',
+`
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1GetAndSetP$1(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set preval (GetAndSetP mem newval));
+ effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST));
+ format %{ "atomic_xchg$2 $preval, $newval, [$mem]" %}
+ ins_encode %{
+ assert_different_registers($mem$$Register, $newval$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $preval$$Register /* pre_val (as a temporary register) */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */);
+ __ $3($preval$$Register, $newval$$Register, $mem$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_serial);
+%}')dnl
+XCHGP_INSN(,,atomic_xchg)
+XCHGP_INSN(Acq,_acq,atomic_xchgal)
+dnl
+define(`XCHGN_INSN',
+`
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1GetAndSetN$1(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set preval (GetAndSetN mem newval));
+ effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST));
+ format %{ "$2 $preval, $newval, [$mem]" %}
+ ins_encode %{
+ assert_different_registers($mem$$Register, $newval$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */);
+ __ $3($preval$$Register, $newval$$Register, $mem$$Register);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_serial);
+%}')dnl
+XCHGN_INSN(,atomic_xchgw,atomic_xchgw)
+XCHGN_INSN(Acq,atomic_xchgw_acq,atomic_xchgalw)
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1LoadP(iRegPNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr)
+%{
+ // This instruction does not need an acquiring counterpart because it is only
+ // used for reference loading (Reference::get()). The same holds for g1LoadN.
+ predicate(UseG1GC && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0);
+ match(Set dst (LoadP mem));
+ effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(4 * INSN_COST);
+ format %{ "ldr $dst, $mem\t# ptr" %}
+ ins_encode %{
+ __ ldr($dst$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $dst$$Register /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(iload_reg_mem);
+%}
+
+// This pattern is generated automatically from g1_aarch64.m4.
+// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
+instruct g1LoadN(iRegNNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0);
+ match(Set dst (LoadN mem));
+ effect(TEMP dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(4 * INSN_COST);
+ format %{ "ldrw $dst, $mem\t# compressed ptr" %}
+ ins_encode %{
+ __ ldrw($dst$$Register, $mem$$Register);
+ if ((barrier_data() & G1C2BarrierPre) != 0) {
+ __ decode_heap_oop($tmp1$$Register, $dst$$Register);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ }
+ %}
+ ins_pipe(iload_reg_mem);
+%}
+
+// END This section of the file is automatically generated. Do not edit --------------
diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp
index 073d9922355..0161843036b 100644
--- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -375,7 +375,7 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) {
__ load_method_holder_cld(rscratch1, rmethod);
// Is it a strong CLD?
- __ ldrw(rscratch2, Address(rscratch1, ClassLoaderData::keep_alive_offset()));
+ __ ldrw(rscratch2, Address(rscratch1, ClassLoaderData::keep_alive_ref_count_offset()));
__ cbnz(rscratch2, method_live);
// Is it a weak but alive CLD?
diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp
index c02f93313b3..261502d5823 100644
--- a/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp
@@ -41,8 +41,6 @@ void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler* masm) {
Register tmp2 = _tmp2->as_register();
Register result = result_opr()->as_register();
- ShenandoahBarrierSet::assembler()->iu_barrier(masm->masm(), newval, rscratch2);
-
if (UseCompressedOops) {
__ encode_heap_oop(tmp1, cmpval);
cmpval = tmp1;
@@ -102,10 +100,6 @@ LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRIt
value.load_item();
LIR_Opr value_opr = value.result();
- if (access.is_oop()) {
- value_opr = iu_barrier(access.gen(), value_opr, access.access_emit_info(), access.decorators());
- }
-
assert(type == T_INT || is_reference_type(type) LP64_ONLY( || type == T_LONG ), "unexpected type");
LIR_Opr tmp = gen->new_register(T_INT);
__ xchg(access.resolved_addr(), value_opr, result, tmp);
diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp
index 5db29729239..84d06dbcc7b 100644
--- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp
@@ -47,7 +47,7 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec
Register src, Register dst, Register count, RegSet saved_regs) {
if (is_oop) {
bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
- if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahIUBarrier || ShenandoahLoadRefBarrier) {
+ if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) {
Label done;
@@ -67,9 +67,9 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec
__ push(saved_regs, sp);
if (UseCompressedOops) {
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry), src, dst, count);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop), src, dst, count);
} else {
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry), src, dst, count);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop), src, dst, count);
}
__ pop(saved_regs, sp);
__ bind(done);
@@ -164,9 +164,9 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
if (expand_call) {
assert(pre_val != c_rarg1, "smashed arg");
- __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread);
+ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
} else {
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
}
__ pop(saved, sp);
@@ -300,14 +300,6 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
__ leave();
}
-void ShenandoahBarrierSetAssembler::iu_barrier(MacroAssembler* masm, Register dst, Register tmp) {
- if (ShenandoahIUBarrier) {
- __ push_call_clobbered_registers();
- satb_write_barrier_pre(masm, noreg, dst, rthread, tmp, rscratch1, true, false);
- __ pop_call_clobbered_registers();
- }
-}
-
//
// Arguments:
//
@@ -398,8 +390,7 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet
if (val == noreg) {
BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), noreg, noreg, noreg, noreg);
} else {
- iu_barrier(masm, val, tmp1);
- // G1 barrier needs uncompressed oop for region cross check.
+ // Barrier needs uncompressed oop for region cross check.
Register new_val = val;
if (UseCompressedOops) {
new_val = rscratch2;
@@ -707,7 +698,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss
__ bind(runtime);
__ push_call_clobbered_registers();
__ load_parameter(0, pre_val);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
__ pop_call_clobbered_registers();
__ bind(done);
diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp
index 375893702e1..ee11b2e73f7 100644
--- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp
@@ -60,9 +60,6 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler {
void load_reference_barrier(MacroAssembler* masm, Register dst, Address load_addr, DecoratorSet decorators);
public:
-
- void iu_barrier(MacroAssembler* masm, Register dst, Register tmp);
-
virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_data_patch; }
#ifdef COMPILER1
diff --git a/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad b/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad
index c7c7165affb..6e401724baa 100644
--- a/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad
+++ b/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This code is free software; you can redistribute it and/or modify it
@@ -62,7 +62,13 @@ instruct xLoadP(iRegPNoSp dst, memory8 mem, rFlagsReg cr)
format %{ "ldr $dst, $mem" %}
ins_encode %{
- const Address ref_addr = mem2address($mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
+ Address ref_addr = mem2address($mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
+ if (ref_addr.getMode() == Address::base_plus_offset) {
+ // Fix up any out-of-range offsets.
+ assert_different_registers(rscratch1, as_Register($mem$$base));
+ assert_different_registers(rscratch1, $dst$$Register);
+ ref_addr = __ legitimize_address(ref_addr, 8, rscratch1);
+ }
__ ldr($dst$$Register, ref_addr);
x_load_barrier(masm, this, ref_addr, $dst$$Register, rscratch2 /* tmp */, barrier_data());
%}
diff --git a/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp
index cd834969e1a..fcec3ae64fd 100644
--- a/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp
@@ -93,7 +93,7 @@ static size_t probe_valid_max_address_bit() {
}
size_t ZPlatformAddressOffsetBits() {
- const static size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1;
+ static const size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1;
const size_t max_address_offset_bits = valid_max_address_offset_bits - 3;
const size_t min_address_offset_bits = max_address_offset_bits - 2;
const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio);
diff --git a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp
index 466e77a4460..3f1898b6742 100644
--- a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp
@@ -1189,6 +1189,8 @@ void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm,
__ lea(rscratch1, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr()));
} else if (stub->is_atomic()) {
__ lea(rscratch1, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr()));
+ } else if (stub->is_nokeepalive()) {
+ __ lea(rscratch1, RuntimeAddress(ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr()));
} else {
__ lea(rscratch1, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr()));
}
@@ -1307,11 +1309,11 @@ Label* ZLoadBarrierStubC2Aarch64::entry() {
return ZBarrierStubC2::entry();
}
-ZStoreBarrierStubC2Aarch64::ZStoreBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic)
- : ZStoreBarrierStubC2(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic), _deferred_emit(false) {}
+ZStoreBarrierStubC2Aarch64::ZStoreBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive)
+ : ZStoreBarrierStubC2(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic, is_nokeepalive), _deferred_emit(false) {}
-ZStoreBarrierStubC2Aarch64* ZStoreBarrierStubC2Aarch64::create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic) {
- ZStoreBarrierStubC2Aarch64* const stub = new (Compile::current()->comp_arena()) ZStoreBarrierStubC2Aarch64(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic);
+ZStoreBarrierStubC2Aarch64* ZStoreBarrierStubC2Aarch64::create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive) {
+ ZStoreBarrierStubC2Aarch64* const stub = new (Compile::current()->comp_arena()) ZStoreBarrierStubC2Aarch64(node, ref_addr, new_zaddress, new_zpointer, is_native, is_atomic, is_nokeepalive);
register_stub(stub);
return stub;
}
diff --git a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp
index 2f716140ed1..ad3a171c103 100644
--- a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp
@@ -280,10 +280,10 @@ class ZStoreBarrierStubC2Aarch64 : public ZStoreBarrierStubC2 {
private:
bool _deferred_emit;
- ZStoreBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic);
+ ZStoreBarrierStubC2Aarch64(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive);
public:
- static ZStoreBarrierStubC2Aarch64* create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic);
+ static ZStoreBarrierStubC2Aarch64* create(const MachNode* node, Address ref_addr, Register new_zaddress, Register new_zpointer, bool is_native, bool is_atomic, bool is_nokeepalive);
virtual void emit_code(MacroAssembler& masm);
};
diff --git a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad
index 92181e2b6b9..088f92a0157 100644
--- a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad
+++ b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This code is free software; you can redistribute it and/or modify it
@@ -91,7 +91,8 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address
z_color(masm, node, rnew_zpointer, rnew_zaddress);
} else {
bool is_native = (node->barrier_data() & ZBarrierNative) != 0;
- ZStoreBarrierStubC2Aarch64* const stub = ZStoreBarrierStubC2Aarch64::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic);
+ bool is_nokeepalive = (node->barrier_data() & ZBarrierNoKeepalive) != 0;
+ ZStoreBarrierStubC2Aarch64* const stub = ZStoreBarrierStubC2Aarch64::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic, is_nokeepalive);
ZBarrierSetAssembler* bs_asm = ZBarrierSet::assembler();
bs_asm->store_barrier_fast(masm, ref_addr, rnew_zaddress, rnew_zpointer, tmp, true /* in_nmethod */, is_atomic, *stub->entry(), *stub->continuation());
}
@@ -111,7 +112,13 @@ instruct zLoadP(iRegPNoSp dst, memory8 mem, rFlagsReg cr)
format %{ "ldr $dst, $mem" %}
ins_encode %{
- const Address ref_addr = mem2address($mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
+ Address ref_addr = mem2address($mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
+ if (ref_addr.getMode() == Address::base_plus_offset) {
+ // Fix up any out-of-range offsets.
+ assert_different_registers(rscratch2, as_Register($mem$$base));
+ assert_different_registers(rscratch2, $dst$$Register);
+ ref_addr = __ legitimize_address(ref_addr, 8, rscratch2);
+ }
__ ldr($dst$$Register, ref_addr);
z_load_barrier(masm, this, ref_addr, $dst$$Register, rscratch1);
%}
diff --git a/src/hotspot/cpu/aarch64/immediate_aarch64.cpp b/src/hotspot/cpu/aarch64/immediate_aarch64.cpp
index 7caafc19fbd..9c67a0dfead 100644
--- a/src/hotspot/cpu/aarch64/immediate_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/immediate_aarch64.cpp
@@ -295,7 +295,7 @@ static int expandLogicalImmediate(uint32_t immN, uint32_t immr,
uint64_t and_bits_sub = replicate(and_bit, 1, nbits);
uint64_t or_bits_sub = replicate(or_bit, 1, nbits);
uint64_t and_bits_top = (and_bits_sub << nbits) | ones(nbits);
- uint64_t or_bits_top = (0 << nbits) | or_bits_sub;
+ uint64_t or_bits_top = (UCONST64(0) << nbits) | or_bits_sub;
tmask = ((tmask
& (replicate(and_bits_top, 2 * nbits, 32 / nbits)))
diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp
index ca359fea9da..c6af74c3dcd 100644
--- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp
@@ -690,13 +690,13 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg)
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp, obj_reg);
- ldrw(tmp, Address(tmp, Klass::access_flags_offset()));
- tstw(tmp, JVM_ACC_IS_VALUE_BASED_CLASS);
+ ldrb(tmp, Address(tmp, Klass::misc_flags_offset()));
+ tst(tmp, KlassFlags::_misc_is_value_based_class);
br(Assembler::NE, slow_case);
}
if (LockingMode == LM_LIGHTWEIGHT) {
- lightweight_lock(obj_reg, tmp, tmp2, tmp3, slow_case);
+ lightweight_lock(lock_reg, obj_reg, tmp, tmp2, tmp3, slow_case);
b(count);
} else if (LockingMode == LM_LEGACY) {
// Load (object->mark() | 1) into swap_reg
@@ -752,15 +752,9 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg)
bind(slow_case);
// Call the runtime routine for slow case
- if (LockingMode == LM_LIGHTWEIGHT) {
- call_VM(noreg,
- CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj),
- obj_reg);
- } else {
- call_VM(noreg,
- CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter),
- lock_reg);
- }
+ call_VM(noreg,
+ CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter),
+ lock_reg);
b(done);
bind(count);
diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp
index f0f032409d3..34dca56eaf7 100644
--- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -35,8 +35,6 @@
typedef ByteSize (*OffsetFunction)(uint);
class InterpreterMacroAssembler: public MacroAssembler {
- protected:
-
protected:
// Interpreter specific version of call_VM_base
using MacroAssembler::call_VM_leaf_base;
@@ -112,8 +110,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
void get_dispatch();
- // Helpers for runtime call arguments/results
-
// Helpers for runtime call arguments/results
void get_method(Register reg) {
ldr(reg, Address(rfp, frame::interpreter_frame_method_offset * wordSize));
@@ -181,7 +177,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
void load_ptr(int n, Register val);
void store_ptr(int n, Register val);
-// Load float value from 'address'. The value is loaded onto the FPU register v0.
+ // Load float value from 'address'. The value is loaded onto the FPU register v0.
void load_float(Address src);
void load_double(Address src);
diff --git a/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp b/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp
index e79b93651b0..aea268ea944 100644
--- a/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -201,7 +201,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
{
__ enter();
- __ lea(rscratch1, ExternalAddress(slow_case_addr));
+ __ lea(rscratch1, RuntimeAddress(slow_case_addr));
__ blr(rscratch1);
__ leave();
__ ret(lr);
diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
index f90aefc8fd3..9835fb5aca1 100644
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
@@ -215,7 +215,7 @@ class RelocActions {
break;
} else {
// nothing to do
- assert(target == 0, "did not expect to relocate target for polling page load");
+ assert(target == nullptr, "did not expect to relocate target for polling page load");
}
break;
}
@@ -736,7 +736,7 @@ void MacroAssembler::reserved_stack_check() {
br(Assembler::LO, no_reserved_zone_enabling);
enter(); // LR and FP are live.
- lea(rscratch1, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone));
+ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone)));
mov(c_rarg0, rthread);
blr(rscratch1);
leave();
@@ -744,7 +744,7 @@ void MacroAssembler::reserved_stack_check() {
// We have already removed our own frame.
// throw_delayed_StackOverflowError will think that it's been
// called by our caller.
- lea(rscratch1, RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry()));
+ lea(rscratch1, RuntimeAddress(SharedRuntime::throw_delayed_StackOverflowError_entry()));
br(rscratch1);
should_not_reach_here();
@@ -1730,8 +1730,8 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl
// The bitmap is full to bursting.
// Implicit invariant: BITMAP_FULL implies (length > 0)
assert(Klass::SECONDARY_SUPERS_BITMAP_FULL == ~uintx(0), "");
- cmn(r_bitmap, (u1)1);
- br(EQ, L_huge);
+ cmpw(r_array_length, (u1)(Klass::SECONDARY_SUPERS_TABLE_SIZE - 2));
+ br(GT, L_huge);
// NB! Our caller has checked bits 0 and 1 in the bitmap. The
// current slot (at secondary_supers[r_array_index]) has not yet
@@ -1838,7 +1838,8 @@ void MacroAssembler::clinit_barrier(Register klass, Register scratch, Label* L_f
L_slow_path = &L_fallthrough;
}
// Fast path check: class is fully initialized
- ldrb(scratch, Address(klass, InstanceKlass::init_state_offset()));
+ lea(scratch, Address(klass, InstanceKlass::init_state_offset()));
+ ldarb(scratch, scratch);
subs(zr, scratch, InstanceKlass::fully_initialized);
br(Assembler::EQ, *L_fast_path);
@@ -1879,7 +1880,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file,
movptr(rscratch1, (uintptr_t)(address)b);
// call indirectly to solve generation ordering problem
- lea(rscratch2, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address()));
+ lea(rscratch2, RuntimeAddress(StubRoutines::verify_oop_subroutine_entry_address()));
ldr(rscratch2, Address(rscratch2));
blr(rscratch2);
@@ -1918,7 +1919,7 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f
movptr(rscratch1, (uintptr_t)(address)b);
// call indirectly to solve generation ordering problem
- lea(rscratch2, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address()));
+ lea(rscratch2, RuntimeAddress(StubRoutines::verify_oop_subroutine_entry_address()));
ldr(rscratch2, Address(rscratch2));
blr(rscratch2);
@@ -2967,7 +2968,7 @@ void MacroAssembler::verify_heapbase(const char* msg) {
if (CheckCompressedOops) {
Label ok;
push(1 << rscratch1->encoding(), sp); // cmpptr trashes rscratch1
- cmpptr(rheapbase, ExternalAddress(CompressedOops::ptrs_base_addr()));
+ cmpptr(rheapbase, ExternalAddress(CompressedOops::base_addr()));
br(Assembler::EQ, ok);
stop(msg);
bind(ok);
@@ -3133,9 +3134,9 @@ void MacroAssembler::reinit_heapbase()
{
if (UseCompressedOops) {
if (Universe::is_fully_initialized()) {
- mov(rheapbase, CompressedOops::ptrs_base());
+ mov(rheapbase, CompressedOops::base());
} else {
- lea(rheapbase, ExternalAddress(CompressedOops::ptrs_base_addr()));
+ lea(rheapbase, ExternalAddress(CompressedOops::base_addr()));
ldr(rheapbase, Address(rheapbase));
}
}
@@ -5010,8 +5011,10 @@ void MacroAssembler::decode_heap_oop(Register d, Register s) {
verify_heapbase("MacroAssembler::decode_heap_oop: heap base corrupted?");
#endif
if (CompressedOops::base() == nullptr) {
- if (CompressedOops::shift() != 0 || d != s) {
+ if (CompressedOops::shift() != 0) {
lsl(d, s, CompressedOops::shift());
+ } else if (d != s) {
+ mov(d, s);
}
} else {
Label done;
@@ -5082,8 +5085,8 @@ MacroAssembler::KlassDecodeMode MacroAssembler::klass_decode_mode() {
if (operand_valid_for_logical_immediate(
/*is32*/false, (uint64_t)CompressedKlassPointers::base())) {
- const uint64_t range_mask =
- (1ULL << log2i(CompressedKlassPointers::range())) - 1;
+ const size_t range = CompressedKlassPointers::klass_range_end() - CompressedKlassPointers::base();
+ const uint64_t range_mask = (1ULL << log2i(range)) - 1;
if (((uint64_t)CompressedKlassPointers::base() & range_mask) == 0) {
return (_klass_decode_mode = KlassDecodeXor);
}
@@ -6413,8 +6416,10 @@ void MacroAssembler::cache_wbsync(bool is_pre) {
}
void MacroAssembler::verify_sve_vector_length(Register tmp) {
+ if (!UseSVE || VM_Version::get_max_supported_sve_vector_length() == FloatRegister::sve_vl_min) {
+ return;
+ }
// Make sure that native code does not change SVE vector length.
- if (!UseSVE) return;
Label verify_ok;
movw(tmp, zr);
sve_inc(tmp, B);
@@ -6454,7 +6459,7 @@ void MacroAssembler::verify_cross_modify_fence_not_required() {
Label fence_not_required;
cbz(rscratch1, fence_not_required);
// If it does then fail.
- lea(rscratch1, CAST_FROM_FN_PTR(address, JavaThread::verify_cross_modify_fence_failure));
+ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::verify_cross_modify_fence_failure)));
mov(c_rarg0, rthread);
blr(rscratch1);
bind(fence_not_required);
@@ -6750,9 +6755,9 @@ void MacroAssembler::double_move(VMRegPair src, VMRegPair dst, Register tmp) {
// - obj: the object to be locked
// - t1, t2, t3: temporary registers, will be destroyed
// - slow: branched to if locking fails, absolute offset may larger than 32KB (imm14 encoding).
-void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, Register t3, Label& slow) {
+void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Register t1, Register t2, Register t3, Label& slow) {
assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking");
- assert_different_registers(obj, t1, t2, t3, rscratch1);
+ assert_different_registers(basic_lock, obj, t1, t2, t3, rscratch1);
Label push;
const Register top = t1;
@@ -6763,6 +6768,11 @@ void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, Re
// instruction emitted as it is part of C1's null check semantics.
ldr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
+ if (UseObjectMonitorTable) {
+ // Clear cache in case fast locking succeeds.
+ str(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))));
+ }
+
// Check if the lock-stack is full.
ldrw(top, Address(rthread, JavaThread::lock_stack_top_offset()));
cmpw(top, (unsigned)LockStack::end_offset());
diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
index 3bfd6e70872..e49f0c49ef6 100644
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
@@ -1639,7 +1639,7 @@ class MacroAssembler: public Assembler {
// Code for java.lang.Thread::onSpinWait() intrinsic.
void spin_wait();
- void lightweight_lock(Register obj, Register t1, Register t2, Register t3, Label& slow);
+ void lightweight_lock(Register basic_lock, Register obj, Register t1, Register t2, Register t3, Label& slow);
void lightweight_unlock(Register obj, Register t1, Register t2, Register t3, Label& slow);
private:
diff --git a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp
index ee19079db7d..aa6a9d14ff1 100644
--- a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -27,6 +27,7 @@
#include "asm/macroAssembler.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/vmClasses.hpp"
+#include "compiler/disassembler.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "memory/allocation.inline.hpp"
@@ -36,7 +37,7 @@
#include "runtime/frame.inline.hpp"
#include "runtime/stubRoutines.hpp"
-#define __ _masm->
+#define __ Disassembler::hook(__FILE__, __LINE__, _masm)->
#ifdef PRODUCT
#define BLOCK_COMMENT(str) /* nothing */
@@ -120,7 +121,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth
__ ldr(rscratch1,Address(method, entry_offset));
__ br(rscratch1);
__ bind(L_no_such_method);
- __ far_jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry()));
+ __ far_jump(RuntimeAddress(SharedRuntime::throw_AbstractMethodError_entry()));
}
void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm,
@@ -451,7 +452,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
jump_from_method_handle(_masm, rmethod, temp1, for_compiler_entry);
if (iid == vmIntrinsics::_linkToInterface) {
__ bind(L_incompatible_class_change_error);
- __ far_jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
+ __ far_jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry()));
}
}
}
diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp
index 5a3f9d228ca..1f6d7292389 100644
--- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp
@@ -78,7 +78,7 @@ address NativeCall::destination() const {
//
// Used in the runtime linkage of calls; see class CompiledIC.
void NativeCall::set_destination_mt_safe(address dest) {
- assert((Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
+ assert((CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
CompiledICLocker::is_safe(addr_at(0)),
"concurrent code patching");
@@ -228,7 +228,7 @@ address NativeJump::jump_destination() const {
// load
// return -1 if jump to self or to 0
- if ((dest == (address)this) || dest == 0) {
+ if ((dest == (address)this) || dest == nullptr) {
dest = (address) -1;
}
return dest;
@@ -256,7 +256,7 @@ address NativeGeneralJump::jump_destination() const {
// a general jump
// return -1 if jump to self or to 0
- if ((dest == (address)this) || dest == 0) {
+ if ((dest == (address)this) || dest == nullptr) {
dest = (address) -1;
}
return dest;
diff --git a/src/hotspot/cpu/aarch64/register_aarch64.hpp b/src/hotspot/cpu/aarch64/register_aarch64.hpp
index 8e340fefbb4..ab635e1be90 100644
--- a/src/hotspot/cpu/aarch64/register_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/register_aarch64.hpp
@@ -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, 2021, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -166,7 +166,13 @@ class FloatRegister {
max_slots_per_register = 4,
save_slots_per_register = 2,
slots_per_neon_register = 4,
- extra_save_slots_per_neon_register = slots_per_neon_register - save_slots_per_register
+ extra_save_slots_per_neon_register = slots_per_neon_register - save_slots_per_register,
+ neon_vl = 16,
+ // VLmax: The maximum sve vector length is determined by the hardware
+ // sve_vl_min <= VLmax <= sve_vl_max.
+ sve_vl_min = 16,
+ // Maximum supported vector length across all CPUs
+ sve_vl_max = 256
};
class FloatRegisterImpl: public AbstractRegisterImpl {
diff --git a/src/hotspot/cpu/aarch64/runtime_aarch64.cpp b/src/hotspot/cpu/aarch64/runtime_aarch64.cpp
index 61d27e32242..09bb370f210 100644
--- a/src/hotspot/cpu/aarch64/runtime_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/runtime_aarch64.cpp
@@ -36,6 +36,349 @@
#include "runtime/vframeArray.hpp"
#include "utilities/globalDefinitions.hpp"
#include "vmreg_aarch64.inline.hpp"
+
+class SimpleRuntimeFrame {
+
+ public:
+
+ // Most of the runtime stubs have this simple frame layout.
+ // This class exists to make the layout shared in one place.
+ // Offsets are for compiler stack slots, which are jints.
+ enum layout {
+ // The frame sender code expects that rbp will be in the "natural" place and
+ // will override any oopMap setting for it. We must therefore force the layout
+ // so that it agrees with the frame sender code.
+ // we don't expect any arg reg save area so aarch64 asserts that
+ // frame::arg_reg_save_area_bytes == 0
+ rfp_off = 0,
+ rfp_off2,
+ return_off, return_off2,
+ framesize
+ };
+};
+
+#define __ masm->
+
+//------------------------------generate_uncommon_trap_blob--------------------
+void OptoRuntime::generate_uncommon_trap_blob() {
+ // Allocate space for the code
+ ResourceMark rm;
+ // Setup code generation tools
+ CodeBuffer buffer("uncommon_trap_blob", 2048, 1024);
+ MacroAssembler* masm = new MacroAssembler(&buffer);
+
+ assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
+
+ address start = __ pc();
+
+ // Push self-frame. We get here with a return address in LR
+ // and sp should be 16 byte aligned
+ // push rfp and retaddr by hand
+ __ protect_return_address();
+ __ stp(rfp, lr, Address(__ pre(sp, -2 * wordSize)));
+ // we don't expect an arg reg save area
+#ifndef PRODUCT
+ assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area");
+#endif
+ // compiler left unloaded_class_index in j_rarg0 move to where the
+ // runtime expects it.
+ if (c_rarg1 != j_rarg0) {
+ __ movw(c_rarg1, j_rarg0);
+ }
+
+ // we need to set the past SP to the stack pointer of the stub frame
+ // and the pc to the address where this runtime call will return
+ // although actually any pc in this code blob will do).
+ Label retaddr;
+ __ set_last_Java_frame(sp, noreg, retaddr, rscratch1);
+
+ // Call C code. Need thread but NOT official VM entry
+ // crud. We cannot block on this call, no GC can happen. Call should
+ // capture callee-saved registers as well as return values.
+ //
+ // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index);
+ //
+ // n.b. 2 gp args, 0 fp args, integral return type
+
+ __ mov(c_rarg0, rthread);
+ __ movw(c_rarg2, (unsigned)Deoptimization::Unpack_uncommon_trap);
+ __ lea(rscratch1,
+ RuntimeAddress(CAST_FROM_FN_PTR(address,
+ Deoptimization::uncommon_trap)));
+ __ blr(rscratch1);
+ __ bind(retaddr);
+
+ // Set an oopmap for the call site
+ OopMapSet* oop_maps = new OopMapSet();
+ OopMap* map = new OopMap(SimpleRuntimeFrame::framesize, 0);
+
+ // location of rfp is known implicitly by the frame sender code
+
+ oop_maps->add_gc_map(__ pc() - start, map);
+
+ __ reset_last_Java_frame(false);
+
+ // move UnrollBlock* into r4
+ __ mov(r4, r0);
+
+#ifdef ASSERT
+ { Label L;
+ __ ldrw(rscratch1, Address(r4, Deoptimization::UnrollBlock::unpack_kind_offset()));
+ __ cmpw(rscratch1, (unsigned)Deoptimization::Unpack_uncommon_trap);
+ __ br(Assembler::EQ, L);
+ __ stop("OptoRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap");
+ __ bind(L);
+ }
+#endif
+
+ // Pop all the frames we must move/replace.
+ //
+ // Frame picture (youngest to oldest)
+ // 1: self-frame (no frame link)
+ // 2: deopting frame (no frame link)
+ // 3: caller of deopting frame (could be compiled/interpreted).
+
+ // Pop self-frame. We have no frame, and must rely only on r0 and sp.
+ __ add(sp, sp, (SimpleRuntimeFrame::framesize) << LogBytesPerInt); // Epilog!
+
+ // Pop deoptimized frame (int)
+ __ ldrw(r2, Address(r4,
+ Deoptimization::UnrollBlock::
+ size_of_deoptimized_frame_offset()));
+ __ sub(r2, r2, 2 * wordSize);
+ __ add(sp, sp, r2);
+ __ ldp(rfp, zr, __ post(sp, 2 * wordSize));
+
+#ifdef ASSERT
+ // Compilers generate code that bang the stack by as much as the
+ // interpreter would need. So this stack banging should never
+ // trigger a fault. Verify that it does not on non product builds.
+ __ ldrw(r1, Address(r4,
+ Deoptimization::UnrollBlock::
+ total_frame_sizes_offset()));
+ __ bang_stack_size(r1, r2);
+#endif
+
+ // Load address of array of frame pcs into r2 (address*)
+ __ ldr(r2, Address(r4,
+ Deoptimization::UnrollBlock::frame_pcs_offset()));
+
+ // Load address of array of frame sizes into r5 (intptr_t*)
+ __ ldr(r5, Address(r4,
+ Deoptimization::UnrollBlock::
+ frame_sizes_offset()));
+
+ // Counter
+ __ ldrw(r3, Address(r4,
+ Deoptimization::UnrollBlock::
+ number_of_frames_offset())); // (int)
+
+ // Now adjust the caller's stack to make up for the extra locals but
+ // record the original sp so that we can save it in the skeletal
+ // interpreter frame and the stack walking of interpreter_sender
+ // will get the unextended sp value and not the "real" sp value.
+
+ const Register sender_sp = r8;
+
+ __ mov(sender_sp, sp);
+ __ ldrw(r1, Address(r4,
+ Deoptimization::UnrollBlock::
+ caller_adjustment_offset())); // (int)
+ __ sub(sp, sp, r1);
+
+ // Push interpreter frames in a loop
+ Label loop;
+ __ bind(loop);
+ __ ldr(r1, Address(r5, 0)); // Load frame size
+ __ sub(r1, r1, 2 * wordSize); // We'll push pc and rfp by hand
+ __ ldr(lr, Address(r2, 0)); // Save return address
+ __ enter(); // and old rfp & set new rfp
+ __ sub(sp, sp, r1); // Prolog
+ __ str(sender_sp, Address(rfp, frame::interpreter_frame_sender_sp_offset * wordSize)); // Make it walkable
+ // This value is corrected by layout_activation_impl
+ __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
+ __ mov(sender_sp, sp); // Pass sender_sp to next frame
+ __ add(r5, r5, wordSize); // Bump array pointer (sizes)
+ __ add(r2, r2, wordSize); // Bump array pointer (pcs)
+ __ subsw(r3, r3, 1); // Decrement counter
+ __ br(Assembler::GT, loop);
+ __ ldr(lr, Address(r2, 0)); // save final return address
+ // Re-push self-frame
+ __ enter(); // & old rfp & set new rfp
+
+ // Use rfp because the frames look interpreted now
+ // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP.
+ // Don't need the precise return PC here, just precise enough to point into this code blob.
+ address the_pc = __ pc();
+ __ set_last_Java_frame(sp, rfp, the_pc, rscratch1);
+
+ // Call C code. Need thread but NOT official VM entry
+ // crud. We cannot block on this call, no GC can happen. Call should
+ // restore return values to their stack-slots with the new SP.
+ // Thread is in rdi already.
+ //
+ // BasicType unpack_frames(JavaThread* thread, int exec_mode);
+ //
+ // n.b. 2 gp args, 0 fp args, integral return type
+
+ // sp should already be aligned
+ __ mov(c_rarg0, rthread);
+ __ movw(c_rarg1, (unsigned)Deoptimization::Unpack_uncommon_trap);
+ __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)));
+ __ blr(rscratch1);
+
+ // Set an oopmap for the call site
+ // Use the same PC we used for the last java frame
+ oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0));
+
+ // Clear fp AND pc
+ __ reset_last_Java_frame(true);
+
+ // Pop self-frame.
+ __ leave(); // Epilog
+
+ // Jump to interpreter
+ __ ret(lr);
+
+ // Make sure all code is generated
+ masm->flush();
+
+ _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps,
+ SimpleRuntimeFrame::framesize >> 1);
+}
+
+//------------------------------generate_exception_blob---------------------------
+// creates exception blob at the end
+// Using exception blob, this code is jumped from a compiled method.
+// (see emit_exception_handler in aarch64.ad file)
+//
+// Given an exception pc at a call we call into the runtime for the
+// handler in this method. This handler might merely restore state
+// (i.e. callee save registers) unwind the frame and jump to the
+// exception handler for the nmethod if there is no Java level handler
+// for the nmethod.
+//
+// This code is entered with a jmp.
+//
+// Arguments:
+// r0: exception oop
+// r3: exception pc
+//
+// Results:
+// r0: exception oop
+// r3: exception pc in caller or ???
+// destination: exception handler of caller
+//
+// Note: the exception pc MUST be at a call (precise debug information)
+// Registers r0, r3, r2, r4, r5, r8-r11 are not callee saved.
+//
+
+void OptoRuntime::generate_exception_blob() {
+ assert(!OptoRuntime::is_callee_saved_register(R3_num), "");
+ assert(!OptoRuntime::is_callee_saved_register(R0_num), "");
+ assert(!OptoRuntime::is_callee_saved_register(R2_num), "");
+
+ assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
+
+ // Allocate space for the code
+ ResourceMark rm;
+ // Setup code generation tools
+ CodeBuffer buffer("exception_blob", 2048, 1024);
+ MacroAssembler* masm = new MacroAssembler(&buffer);
+
+ // TODO check various assumptions made here
+ //
+ // make sure we do so before running this
+
+ address start = __ pc();
+
+ // push rfp and retaddr by hand
+ // Exception pc is 'return address' for stack walker
+ __ protect_return_address();
+ __ stp(rfp, lr, Address(__ pre(sp, -2 * wordSize)));
+ // there are no callee save registers and we don't expect an
+ // arg reg save area
+#ifndef PRODUCT
+ assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area");
+#endif
+ // Store exception in Thread object. We cannot pass any arguments to the
+ // handle_exception call, since we do not want to make any assumption
+ // about the size of the frame where the exception happened in.
+ __ str(r0, Address(rthread, JavaThread::exception_oop_offset()));
+ __ str(r3, Address(rthread, JavaThread::exception_pc_offset()));
+
+ // This call does all the hard work. It checks if an exception handler
+ // exists in the method.
+ // If so, it returns the handler address.
+ // If not, it prepares for stack-unwinding, restoring the callee-save
+ // registers of the frame being removed.
+ //
+ // address OptoRuntime::handle_exception_C(JavaThread* thread)
+ //
+ // n.b. 1 gp arg, 0 fp args, integral return type
+
+ // the stack should always be aligned
+ address the_pc = __ pc();
+ __ set_last_Java_frame(sp, noreg, the_pc, rscratch1);
+ __ mov(c_rarg0, rthread);
+ __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C)));
+ __ blr(rscratch1);
+ // handle_exception_C is a special VM call which does not require an explicit
+ // instruction sync afterwards.
+
+ // May jump to SVE compiled code
+ __ reinitialize_ptrue();
+
+ // Set an oopmap for the call site. This oopmap will only be used if we
+ // are unwinding the stack. Hence, all locations will be dead.
+ // Callee-saved registers will be the same as the frame above (i.e.,
+ // handle_exception_stub), since they were restored when we got the
+ // exception.
+
+ OopMapSet* oop_maps = new OopMapSet();
+
+ oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0));
+
+ __ reset_last_Java_frame(false);
+
+ // Restore callee-saved registers
+
+ // rfp is an implicitly saved callee saved register (i.e. the calling
+ // convention will save restore it in prolog/epilog) Other than that
+ // there are no callee save registers now that adapter frames are gone.
+ // and we dont' expect an arg reg save area
+ __ ldp(rfp, r3, Address(__ post(sp, 2 * wordSize)));
+ __ authenticate_return_address(r3);
+
+ // r0: exception handler
+
+ // We have a handler in r0 (could be deopt blob).
+ __ mov(r8, r0);
+
+ // Get the exception oop
+ __ ldr(r0, Address(rthread, JavaThread::exception_oop_offset()));
+ // Get the exception pc in case we are deoptimized
+ __ ldr(r4, Address(rthread, JavaThread::exception_pc_offset()));
+#ifdef ASSERT
+ __ str(zr, Address(rthread, JavaThread::exception_handler_pc_offset()));
+ __ str(zr, Address(rthread, JavaThread::exception_pc_offset()));
#endif
+ // Clear the exception oop so GC no longer processes it as a root.
+ __ str(zr, Address(rthread, JavaThread::exception_oop_offset()));
+
+ // r0: exception oop
+ // r8: exception handler
+ // r4: exception pc
+ // Jump to handler
+
+ __ br(r8);
+
+ // Make sure all code is generated
+ masm->flush();
+
+ // Set exception blob
+ _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1);
+}
+#endif // COMPILER2
diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
index bb2554e65ce..52996f4c4a5 100644
--- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
@@ -49,6 +49,7 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/signature.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/timerTrace.hpp"
#include "runtime/vframeArray.hpp"
#include "utilities/align.hpp"
#include "utilities/formatBuffer.hpp"
@@ -66,27 +67,13 @@
#define __ masm->
-const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size;
-
-class SimpleRuntimeFrame {
-
- public:
+#ifdef PRODUCT
+#define BLOCK_COMMENT(str) /* nothing */
+#else
+#define BLOCK_COMMENT(str) __ block_comment(str)
+#endif
- // Most of the runtime stubs have this simple frame layout.
- // This class exists to make the layout shared in one place.
- // Offsets are for compiler stack slots, which are jints.
- enum layout {
- // The frame sender code expects that rbp will be in the "natural" place and
- // will override any oopMap setting for it. We must therefore force the layout
- // so that it agrees with the frame sender code.
- // we don't expect any arg reg save area so aarch64 asserts that
- // frame::arg_reg_save_area_bytes == 0
- rfp_off = 0,
- rfp_off2,
- return_off, return_off2,
- framesize
- };
-};
+const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size;
// FIXME -- this is used by C1
class RegisterSaver {
@@ -1831,7 +1818,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
__ br(Assembler::NE, slow_path_lock);
} else {
assert(LockingMode == LM_LIGHTWEIGHT, "must be");
- __ lightweight_lock(obj_reg, swap_reg, tmp, lock_tmp, slow_path_lock);
+ __ lightweight_lock(lock_reg, obj_reg, swap_reg, tmp, lock_tmp, slow_path_lock);
}
__ bind(count);
__ increment(Address(rthread, JavaThread::held_monitor_count_offset()));
@@ -1903,16 +1890,8 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
// Check for safepoint operation in progress and/or pending suspend requests.
{
- // We need an acquire here to ensure that any subsequent load of the
- // global SafepointSynchronize::_state flag is ordered after this load
- // of the thread-local polling word. We don't want this poll to
- // return false (i.e. not safepointing) and a later poll of the global
- // SafepointSynchronize::_state spuriously to return true.
- //
- // This is to avoid a race when we're in a native->Java transition
- // racing the code which wakes up from a safepoint.
-
- __ safepoint_poll(safepoint_in_progress, true /* at_return */, true /* acquire */, false /* in_nmethod */);
+ // No need for acquire as Java threads always disarm themselves.
+ __ safepoint_poll(safepoint_in_progress, true /* at_return */, false /* acquire */, false /* in_nmethod */);
__ ldrw(rscratch1, Address(rthread, JavaThread::suspend_flags_offset()));
__ cbnzw(rscratch1, safepoint_in_progress);
__ bind(safepoint_in_progress_done);
@@ -2203,7 +2182,8 @@ void SharedRuntime::generate_deopt_blob() {
pad += 512; // Increase the buffer size when compiling for JVMCI
}
#endif
- CodeBuffer buffer("deopt_blob", 2048+pad, 1024);
+ const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id);
+ CodeBuffer buffer(name, 2048+pad, 1024);
MacroAssembler* masm = new MacroAssembler(&buffer);
int frame_size_in_words;
OopMap* map = nullptr;
@@ -2254,7 +2234,7 @@ void SharedRuntime::generate_deopt_blob() {
int reexecute_offset = __ pc() - start;
#if INCLUDE_JVMCI && !defined(COMPILER1)
- if (EnableJVMCI && UseJVMCICompiler) {
+ if (UseJVMCICompiler) {
// JVMCI does not use this kind of deoptimization
__ should_not_reach_here();
}
@@ -2581,217 +2561,29 @@ uint SharedRuntime::out_preserve_stack_slots() {
return 0;
}
-#ifdef COMPILER2
-//------------------------------generate_uncommon_trap_blob--------------------
-void SharedRuntime::generate_uncommon_trap_blob() {
- // Allocate space for the code
- ResourceMark rm;
- // Setup code generation tools
- CodeBuffer buffer("uncommon_trap_blob", 2048, 1024);
- MacroAssembler* masm = new MacroAssembler(&buffer);
-
- assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
-
- address start = __ pc();
-
- // Push self-frame. We get here with a return address in LR
- // and sp should be 16 byte aligned
- // push rfp and retaddr by hand
- __ protect_return_address();
- __ stp(rfp, lr, Address(__ pre(sp, -2 * wordSize)));
- // we don't expect an arg reg save area
-#ifndef PRODUCT
- assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area");
-#endif
- // compiler left unloaded_class_index in j_rarg0 move to where the
- // runtime expects it.
- if (c_rarg1 != j_rarg0) {
- __ movw(c_rarg1, j_rarg0);
- }
-
- // we need to set the past SP to the stack pointer of the stub frame
- // and the pc to the address where this runtime call will return
- // although actually any pc in this code blob will do).
- Label retaddr;
- __ set_last_Java_frame(sp, noreg, retaddr, rscratch1);
-
- // Call C code. Need thread but NOT official VM entry
- // crud. We cannot block on this call, no GC can happen. Call should
- // capture callee-saved registers as well as return values.
- // Thread is in rdi already.
- //
- // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index);
- //
- // n.b. 2 gp args, 0 fp args, integral return type
-
- __ mov(c_rarg0, rthread);
- __ movw(c_rarg2, (unsigned)Deoptimization::Unpack_uncommon_trap);
- __ lea(rscratch1,
- RuntimeAddress(CAST_FROM_FN_PTR(address,
- Deoptimization::uncommon_trap)));
- __ blr(rscratch1);
- __ bind(retaddr);
-
- // Set an oopmap for the call site
- OopMapSet* oop_maps = new OopMapSet();
- OopMap* map = new OopMap(SimpleRuntimeFrame::framesize, 0);
-
- // location of rfp is known implicitly by the frame sender code
-
- oop_maps->add_gc_map(__ pc() - start, map);
-
- __ reset_last_Java_frame(false);
-
- // move UnrollBlock* into r4
- __ mov(r4, r0);
-
-#ifdef ASSERT
- { Label L;
- __ ldrw(rscratch1, Address(r4, Deoptimization::UnrollBlock::unpack_kind_offset()));
- __ cmpw(rscratch1, (unsigned)Deoptimization::Unpack_uncommon_trap);
- __ br(Assembler::EQ, L);
- __ stop("SharedRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap");
- __ bind(L);
- }
-#endif
-
- // Pop all the frames we must move/replace.
- //
- // Frame picture (youngest to oldest)
- // 1: self-frame (no frame link)
- // 2: deopting frame (no frame link)
- // 3: caller of deopting frame (could be compiled/interpreted).
-
- // Pop self-frame. We have no frame, and must rely only on r0 and sp.
- __ add(sp, sp, (SimpleRuntimeFrame::framesize) << LogBytesPerInt); // Epilog!
-
- // Pop deoptimized frame (int)
- __ ldrw(r2, Address(r4,
- Deoptimization::UnrollBlock::
- size_of_deoptimized_frame_offset()));
- __ sub(r2, r2, 2 * wordSize);
- __ add(sp, sp, r2);
- __ ldp(rfp, zr, __ post(sp, 2 * wordSize));
-
-#ifdef ASSERT
- // Compilers generate code that bang the stack by as much as the
- // interpreter would need. So this stack banging should never
- // trigger a fault. Verify that it does not on non product builds.
- __ ldrw(r1, Address(r4,
- Deoptimization::UnrollBlock::
- total_frame_sizes_offset()));
- __ bang_stack_size(r1, r2);
-#endif
-
- // Load address of array of frame pcs into r2 (address*)
- __ ldr(r2, Address(r4,
- Deoptimization::UnrollBlock::frame_pcs_offset()));
-
- // Load address of array of frame sizes into r5 (intptr_t*)
- __ ldr(r5, Address(r4,
- Deoptimization::UnrollBlock::
- frame_sizes_offset()));
-
- // Counter
- __ ldrw(r3, Address(r4,
- Deoptimization::UnrollBlock::
- number_of_frames_offset())); // (int)
-
- // Now adjust the caller's stack to make up for the extra locals but
- // record the original sp so that we can save it in the skeletal
- // interpreter frame and the stack walking of interpreter_sender
- // will get the unextended sp value and not the "real" sp value.
-
- const Register sender_sp = r8;
-
- __ mov(sender_sp, sp);
- __ ldrw(r1, Address(r4,
- Deoptimization::UnrollBlock::
- caller_adjustment_offset())); // (int)
- __ sub(sp, sp, r1);
-
- // Push interpreter frames in a loop
- Label loop;
- __ bind(loop);
- __ ldr(r1, Address(r5, 0)); // Load frame size
- __ sub(r1, r1, 2 * wordSize); // We'll push pc and rfp by hand
- __ ldr(lr, Address(r2, 0)); // Save return address
- __ enter(); // and old rfp & set new rfp
- __ sub(sp, sp, r1); // Prolog
- __ str(sender_sp, Address(rfp, frame::interpreter_frame_sender_sp_offset * wordSize)); // Make it walkable
- // This value is corrected by layout_activation_impl
- __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
- __ mov(sender_sp, sp); // Pass sender_sp to next frame
- __ add(r5, r5, wordSize); // Bump array pointer (sizes)
- __ add(r2, r2, wordSize); // Bump array pointer (pcs)
- __ subsw(r3, r3, 1); // Decrement counter
- __ br(Assembler::GT, loop);
- __ ldr(lr, Address(r2, 0)); // save final return address
- // Re-push self-frame
- __ enter(); // & old rfp & set new rfp
-
- // Use rfp because the frames look interpreted now
- // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP.
- // Don't need the precise return PC here, just precise enough to point into this code blob.
- address the_pc = __ pc();
- __ set_last_Java_frame(sp, rfp, the_pc, rscratch1);
-
- // Call C code. Need thread but NOT official VM entry
- // crud. We cannot block on this call, no GC can happen. Call should
- // restore return values to their stack-slots with the new SP.
- // Thread is in rdi already.
- //
- // BasicType unpack_frames(JavaThread* thread, int exec_mode);
- //
- // n.b. 2 gp args, 0 fp args, integral return type
-
- // sp should already be aligned
- __ mov(c_rarg0, rthread);
- __ movw(c_rarg1, (unsigned)Deoptimization::Unpack_uncommon_trap);
- __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)));
- __ blr(rscratch1);
-
- // Set an oopmap for the call site
- // Use the same PC we used for the last java frame
- oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0));
-
- // Clear fp AND pc
- __ reset_last_Java_frame(true);
-
- // Pop self-frame.
- __ leave(); // Epilog
-
- // Jump to interpreter
- __ ret(lr);
-
- // Make sure all code is generated
- masm->flush();
-
- _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps,
- SimpleRuntimeFrame::framesize >> 1);
-}
-#endif // COMPILER2
-
//------------------------------generate_handler_blob------
//
// Generate a special Compile2Runtime blob that saves all registers,
// and setup oopmap.
//
-SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) {
+SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) {
+ assert(is_polling_page_id(id), "expected a polling page stub id");
+
ResourceMark rm;
OopMapSet *oop_maps = new OopMapSet();
OopMap* map;
// Allocate space for the code. Setup code generation tools.
- CodeBuffer buffer("handler_blob", 2048, 1024);
+ const char* name = SharedRuntime::stub_name(id);
+ CodeBuffer buffer(name, 2048, 1024);
MacroAssembler* masm = new MacroAssembler(&buffer);
address start = __ pc();
address call_pc = nullptr;
int frame_size_in_words;
- bool cause_return = (poll_type == POLL_AT_RETURN);
- RegisterSaver reg_save(poll_type == POLL_AT_VECTOR_LOOP /* save_vectors */);
+ bool cause_return = (id == SharedStubId::polling_page_return_handler_id);
+ RegisterSaver reg_save(id == SharedStubId::polling_page_vectors_safepoint_handler_id /* save_vectors */);
// When the signal occurred, the LR was either signed and stored on the stack (in which
// case it will be restored from the stack before being used) or unsigned and not stored
@@ -2903,12 +2695,14 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
// but since this is generic code we don't know what they are and the caller
// must do any gc of the args.
//
-RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) {
+RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) {
assert (StubRoutines::forward_exception_entry() != nullptr, "must be generated before");
+ assert(is_resolve_id(id), "expected a resolve stub id");
// allocate space for the code
ResourceMark rm;
+ const char* name = SharedRuntime::stub_name(id);
CodeBuffer buffer(name, 1000, 512);
MacroAssembler* masm = new MacroAssembler(&buffer);
@@ -2984,140 +2778,198 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha
return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true);
}
-#ifdef COMPILER2
-// This is here instead of runtime_aarch64_64.cpp because it uses SimpleRuntimeFrame
-//
-//------------------------------generate_exception_blob---------------------------
-// creates exception blob at the end
-// Using exception blob, this code is jumped from a compiled method.
-// (see emit_exception_handler in x86_64.ad file)
-//
-// Given an exception pc at a call we call into the runtime for the
-// handler in this method. This handler might merely restore state
-// (i.e. callee save registers) unwind the frame and jump to the
-// exception handler for the nmethod if there is no Java level handler
-// for the nmethod.
-//
-// This code is entered with a jmp.
-//
-// Arguments:
-// r0: exception oop
-// r3: exception pc
-//
-// Results:
-// r0: exception oop
-// r3: exception pc in caller or ???
-// destination: exception handler of caller
-//
-// Note: the exception pc MUST be at a call (precise debug information)
-// Registers r0, r3, r2, r4, r5, r8-r11 are not callee saved.
-//
-
-void OptoRuntime::generate_exception_blob() {
- assert(!OptoRuntime::is_callee_saved_register(R3_num), "");
- assert(!OptoRuntime::is_callee_saved_register(R0_num), "");
- assert(!OptoRuntime::is_callee_saved_register(R2_num), "");
+// Continuation point for throwing of implicit exceptions that are
+// not handled in the current activation. Fabricates an exception
+// oop and initiates normal exception dispatching in this
+// frame. Since we need to preserve callee-saved values (currently
+// only for C2, but done for C1 as well) we need a callee-saved oop
+// map and therefore have to make these stubs into RuntimeStubs
+// rather than BufferBlobs. If the compiler needs all registers to
+// be preserved between the fault point and the exception handler
+// then it must assume responsibility for that in
+// AbstractCompiler::continuation_for_implicit_null_exception or
+// continuation_for_implicit_division_by_zero_exception. All other
+// implicit exceptions (e.g., NullPointerException or
+// AbstractMethodError on entry) are either at call sites or
+// otherwise assume that stack unwinding will be initiated, so
+// caller saved registers were assumed volatile in the compiler.
+
+RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) {
+ assert(is_throw_id(id), "expected a throw stub id");
+
+ const char* name = SharedRuntime::stub_name(id);
+
+ // Information about frame layout at time of blocking runtime call.
+ // Note that we only have to preserve callee-saved registers since
+ // the compilers are responsible for supplying a continuation point
+ // if they expect all registers to be preserved.
+ // n.b. aarch64 asserts that frame::arg_reg_save_area_bytes == 0
+ enum layout {
+ rfp_off = 0,
+ rfp_off2,
+ return_off,
+ return_off2,
+ framesize // inclusive of return address
+ };
- assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
+ int insts_size = 512;
+ int locs_size = 64;
- // Allocate space for the code
ResourceMark rm;
- // Setup code generation tools
- CodeBuffer buffer("exception_blob", 2048, 1024);
- MacroAssembler* masm = new MacroAssembler(&buffer);
+ const char* timer_msg = "SharedRuntime generate_throw_exception";
+ TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime));
- // TODO check various assumptions made here
- //
- // make sure we do so before running this
+ CodeBuffer code(name, insts_size, locs_size);
+ OopMapSet* oop_maps = new OopMapSet();
+ MacroAssembler* masm = new MacroAssembler(&code);
address start = __ pc();
- // push rfp and retaddr by hand
- // Exception pc is 'return address' for stack walker
- __ protect_return_address();
- __ stp(rfp, lr, Address(__ pre(sp, -2 * wordSize)));
- // there are no callee save registers and we don't expect an
- // arg reg save area
-#ifndef PRODUCT
- assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area");
-#endif
- // Store exception in Thread object. We cannot pass any arguments to the
- // handle_exception call, since we do not want to make any assumption
- // about the size of the frame where the exception happened in.
- __ str(r0, Address(rthread, JavaThread::exception_oop_offset()));
- __ str(r3, Address(rthread, JavaThread::exception_pc_offset()));
+ // This is an inlined and slightly modified version of call_VM
+ // which has the ability to fetch the return PC out of
+ // thread-local storage and also sets up last_Java_sp slightly
+ // differently than the real call_VM
- // This call does all the hard work. It checks if an exception handler
- // exists in the method.
- // If so, it returns the handler address.
- // If not, it prepares for stack-unwinding, restoring the callee-save
- // registers of the frame being removed.
- //
- // address OptoRuntime::handle_exception_C(JavaThread* thread)
- //
- // n.b. 1 gp arg, 0 fp args, integral return type
+ __ enter(); // Save FP and LR before call
+
+ assert(is_even(framesize/2), "sp not 16-byte aligned");
+
+ // lr and fp are already in place
+ __ sub(sp, rfp, ((uint64_t)framesize-4) << LogBytesPerInt); // prolog
- // the stack should always be aligned
+ int frame_complete = __ pc() - start;
+
+ // Set up last_Java_sp and last_Java_fp
address the_pc = __ pc();
- __ set_last_Java_frame(sp, noreg, the_pc, rscratch1);
+ __ set_last_Java_frame(sp, rfp, the_pc, rscratch1);
+
__ mov(c_rarg0, rthread);
- __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C)));
+ BLOCK_COMMENT("call runtime_entry");
+ __ mov(rscratch1, runtime_entry);
__ blr(rscratch1);
- // handle_exception_C is a special VM call which does not require an explicit
- // instruction sync afterwards.
- // May jump to SVE compiled code
+ // Generate oop map
+ OopMap* map = new OopMap(framesize, 0);
+
+ oop_maps->add_gc_map(the_pc - start, map);
+
+ __ reset_last_Java_frame(true);
+
+ // Reinitialize the ptrue predicate register, in case the external runtime
+ // call clobbers ptrue reg, as we may return to SVE compiled code.
__ reinitialize_ptrue();
- // Set an oopmap for the call site. This oopmap will only be used if we
- // are unwinding the stack. Hence, all locations will be dead.
- // Callee-saved registers will be the same as the frame above (i.e.,
- // handle_exception_stub), since they were restored when we got the
- // exception.
+ __ leave();
- OopMapSet* oop_maps = new OopMapSet();
+ // check for pending exceptions
+#ifdef ASSERT
+ Label L;
+ __ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset()));
+ __ cbnz(rscratch1, L);
+ __ should_not_reach_here();
+ __ bind(L);
+#endif // ASSERT
+ __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
- oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0));
+ // codeBlob framesize is in words (not VMRegImpl::slot_size)
+ RuntimeStub* stub =
+ RuntimeStub::new_runtime_stub(name,
+ &code,
+ frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps, false);
+ return stub;
+}
- __ reset_last_Java_frame(false);
+#if INCLUDE_JFR
- // Restore callee-saved registers
+static void jfr_prologue(address the_pc, MacroAssembler* masm, Register thread) {
+ __ set_last_Java_frame(sp, rfp, the_pc, rscratch1);
+ __ mov(c_rarg0, thread);
+}
- // rfp is an implicitly saved callee saved register (i.e. the calling
- // convention will save restore it in prolog/epilog) Other than that
- // there are no callee save registers now that adapter frames are gone.
- // and we dont' expect an arg reg save area
- __ ldp(rfp, r3, Address(__ post(sp, 2 * wordSize)));
- __ authenticate_return_address(r3);
+// The handle is dereferenced through a load barrier.
+static void jfr_epilogue(MacroAssembler* masm) {
+ __ reset_last_Java_frame(true);
+}
- // r0: exception handler
+// For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
+// It returns a jobject handle to the event writer.
+// The handle is dereferenced and the return value is the event writer oop.
+RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() {
+ enum layout {
+ rbp_off,
+ rbpH_off,
+ return_off,
+ return_off2,
+ framesize // inclusive of return address
+ };
- // We have a handler in r0 (could be deopt blob).
- __ mov(r8, r0);
+ int insts_size = 1024;
+ int locs_size = 64;
+ const char* name = SharedRuntime::stub_name(SharedStubId::jfr_write_checkpoint_id);
+ CodeBuffer code(name, insts_size, locs_size);
+ OopMapSet* oop_maps = new OopMapSet();
+ MacroAssembler* masm = new MacroAssembler(&code);
- // Get the exception oop
- __ ldr(r0, Address(rthread, JavaThread::exception_oop_offset()));
- // Get the exception pc in case we are deoptimized
- __ ldr(r4, Address(rthread, JavaThread::exception_pc_offset()));
-#ifdef ASSERT
- __ str(zr, Address(rthread, JavaThread::exception_handler_pc_offset()));
- __ str(zr, Address(rthread, JavaThread::exception_pc_offset()));
-#endif
- // Clear the exception oop so GC no longer processes it as a root.
- __ str(zr, Address(rthread, JavaThread::exception_oop_offset()));
+ address start = __ pc();
+ __ enter();
+ int frame_complete = __ pc() - start;
+ address the_pc = __ pc();
+ jfr_prologue(the_pc, masm, rthread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1);
+ jfr_epilogue(masm);
+ __ resolve_global_jobject(r0, rscratch1, rscratch2);
+ __ leave();
+ __ ret(lr);
- // r0: exception oop
- // r8: exception handler
- // r4: exception pc
- // Jump to handler
+ OopMap* map = new OopMap(framesize, 1); // rfp
+ oop_maps->add_gc_map(the_pc - start, map);
- __ br(r8);
+ RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
+ RuntimeStub::new_runtime_stub(name, &code, frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps, false);
+ return stub;
+}
- // Make sure all code is generated
- masm->flush();
+// For c2: call to return a leased buffer.
+RuntimeStub* SharedRuntime::generate_jfr_return_lease() {
+ enum layout {
+ rbp_off,
+ rbpH_off,
+ return_off,
+ return_off2,
+ framesize // inclusive of return address
+ };
+
+ int insts_size = 1024;
+ int locs_size = 64;
+
+ const char* name = SharedRuntime::stub_name(SharedStubId::jfr_return_lease_id);
+ CodeBuffer code(name, insts_size, locs_size);
+ OopMapSet* oop_maps = new OopMapSet();
+ MacroAssembler* masm = new MacroAssembler(&code);
+
+ address start = __ pc();
+ __ enter();
+ int frame_complete = __ pc() - start;
+ address the_pc = __ pc();
+ jfr_prologue(the_pc, masm, rthread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1);
+ jfr_epilogue(masm);
+
+ __ leave();
+ __ ret(lr);
+
+ OopMap* map = new OopMap(framesize, 1); // rfp
+ oop_maps->add_gc_map(the_pc - start, map);
- // Set exception blob
- _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1);
+ RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
+ RuntimeStub::new_runtime_stub(name, &code, frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps, false);
+ return stub;
}
-#endif // COMPILER2
+#endif // INCLUDE_JFR
diff --git a/src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp
index db38b9cf5df..dcba233c9dc 100644
--- a/src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp
+++ b/src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp
@@ -30,8 +30,15 @@
// Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap
class SmallRegisterMap {
+ constexpr SmallRegisterMap() = default;
+ ~SmallRegisterMap() = default;
+ NONCOPYABLE(SmallRegisterMap);
+
public:
- static constexpr SmallRegisterMap* instance = nullptr;
+ static const SmallRegisterMap* instance() {
+ static constexpr SmallRegisterMap the_instance{};
+ return &the_instance;
+ }
private:
static void assert_is_rfp(VMReg r) NOT_DEBUG_RETURN
DEBUG_ONLY({ assert (r == rfp->as_VMReg() || r == rfp->as_VMReg()->next(), "Reg: %s", r->name()); })
@@ -48,17 +55,6 @@ class SmallRegisterMap {
return map;
}
- SmallRegisterMap() {}
-
- SmallRegisterMap(const RegisterMap* map) {
- #ifdef ASSERT
- for(int i = 0; i < RegisterMap::reg_count; i++) {
- VMReg r = VMRegImpl::as_VMReg(i);
- if (map->location(r, (intptr_t*)nullptr) != nullptr) assert_is_rfp(r);
- }
- #endif
- }
-
inline address location(VMReg reg, intptr_t* sp) const {
assert_is_rfp(reg);
return (address)(sp - frame::sender_sp_offset);
diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
index 3f1a4423b5e..de7fc5b281b 100644
--- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
@@ -1374,7 +1374,9 @@ class StubGenerator: public StubCodeGenerator {
// r15 is the byte adjustment needed to align s.
__ cbz(r15, aligned);
int shift = exact_log2(granularity);
- if (shift) __ lsr(r15, r15, shift);
+ if (shift > 0) {
+ __ lsr(r15, r15, shift);
+ }
__ sub(count, count, r15);
#if 0
@@ -1402,9 +1404,15 @@ class StubGenerator: public StubCodeGenerator {
// s is now 2-word-aligned.
- // We have a count of units and some trailing bytes. Adjust the
- // count and do a bulk copy of words.
- __ lsr(r15, count, exact_log2(wordSize/granularity));
+ // We have a count of units and some trailing bytes. Adjust the
+ // count and do a bulk copy of words. If the shift is zero
+ // perform a move instead to benefit from zero latency moves.
+ int shift = exact_log2(wordSize/granularity);
+ if (shift > 0) {
+ __ lsr(r15, count, shift);
+ } else {
+ __ mov(r15, count);
+ }
if (direction == copy_forwards) {
if (type != T_OBJECT) {
__ bl(copy_f);
@@ -3417,15 +3425,15 @@ class StubGenerator: public StubCodeGenerator {
Register rscratch3 = r10;
Register rscratch4 = r11;
- __ andw(rscratch3, r2, r4);
- __ bicw(rscratch4, r3, r4);
reg_cache.extract_u32(rscratch1, k);
__ movw(rscratch2, t);
- __ orrw(rscratch3, rscratch3, rscratch4);
__ addw(rscratch4, r1, rscratch2);
__ addw(rscratch4, rscratch4, rscratch1);
- __ addw(rscratch3, rscratch3, rscratch4);
- __ rorw(rscratch2, rscratch3, 32 - s);
+ __ bicw(rscratch2, r3, r4);
+ __ andw(rscratch3, r2, r4);
+ __ addw(rscratch2, rscratch2, rscratch4);
+ __ addw(rscratch2, rscratch2, rscratch3);
+ __ rorw(rscratch2, rscratch2, 32 - s);
__ addw(r1, rscratch2, r2);
}
@@ -7045,7 +7053,7 @@ class StubGenerator: public StubCodeGenerator {
Label thaw_success;
// rscratch2 contains the size of the frames to thaw, 0 if overflow or no more frames
__ cbnz(rscratch2, thaw_success);
- __ lea(rscratch1, ExternalAddress(StubRoutines::throw_StackOverflowError_entry()));
+ __ lea(rscratch1, RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry()));
__ br(rscratch1);
__ bind(thaw_success);
@@ -7305,98 +7313,6 @@ class StubGenerator: public StubCodeGenerator {
return start;
}
-#if INCLUDE_JFR
-
- static void jfr_prologue(address the_pc, MacroAssembler* _masm, Register thread) {
- __ set_last_Java_frame(sp, rfp, the_pc, rscratch1);
- __ mov(c_rarg0, thread);
- }
-
- // The handle is dereferenced through a load barrier.
- static void jfr_epilogue(MacroAssembler* _masm) {
- __ reset_last_Java_frame(true);
- }
-
- // For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
- // It returns a jobject handle to the event writer.
- // The handle is dereferenced and the return value is the event writer oop.
- static RuntimeStub* generate_jfr_write_checkpoint() {
- enum layout {
- rbp_off,
- rbpH_off,
- return_off,
- return_off2,
- framesize // inclusive of return address
- };
-
- int insts_size = 1024;
- int locs_size = 64;
- CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size);
- OopMapSet* oop_maps = new OopMapSet();
- MacroAssembler* masm = new MacroAssembler(&code);
- MacroAssembler* _masm = masm;
-
- address start = __ pc();
- __ enter();
- int frame_complete = __ pc() - start;
- address the_pc = __ pc();
- jfr_prologue(the_pc, _masm, rthread);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1);
- jfr_epilogue(_masm);
- __ resolve_global_jobject(r0, rscratch1, rscratch2);
- __ leave();
- __ ret(lr);
-
- OopMap* map = new OopMap(framesize, 1); // rfp
- oop_maps->add_gc_map(the_pc - start, map);
-
- RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
- RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps, false);
- return stub;
- }
-
- // For c2: call to return a leased buffer.
- static RuntimeStub* generate_jfr_return_lease() {
- enum layout {
- rbp_off,
- rbpH_off,
- return_off,
- return_off2,
- framesize // inclusive of return address
- };
-
- int insts_size = 1024;
- int locs_size = 64;
- CodeBuffer code("jfr_return_lease", insts_size, locs_size);
- OopMapSet* oop_maps = new OopMapSet();
- MacroAssembler* masm = new MacroAssembler(&code);
- MacroAssembler* _masm = masm;
-
- address start = __ pc();
- __ enter();
- int frame_complete = __ pc() - start;
- address the_pc = __ pc();
- jfr_prologue(the_pc, _masm, rthread);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1);
- jfr_epilogue(_masm);
-
- __ leave();
- __ ret(lr);
-
- OopMap* map = new OopMap(framesize, 1); // rfp
- oop_maps->add_gc_map(the_pc - start, map);
-
- RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
- RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps, false);
- return stub;
- }
-
-#endif // INCLUDE_JFR
-
// exception handler for upcall stubs
address generate_upcall_stub_exception_handler() {
StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler");
@@ -7412,115 +7328,31 @@ class StubGenerator: public StubCodeGenerator {
return start;
}
- // Continuation point for throwing of implicit exceptions that are
- // not handled in the current activation. Fabricates an exception
- // oop and initiates normal exception dispatching in this
- // frame. Since we need to preserve callee-saved values (currently
- // only for C2, but done for C1 as well) we need a callee-saved oop
- // map and therefore have to make these stubs into RuntimeStubs
- // rather than BufferBlobs. If the compiler needs all registers to
- // be preserved between the fault point and the exception handler
- // then it must assume responsibility for that in
- // AbstractCompiler::continuation_for_implicit_null_exception or
- // continuation_for_implicit_division_by_zero_exception. All other
- // implicit exceptions (e.g., NullPointerException or
- // AbstractMethodError on entry) are either at call sites or
- // otherwise assume that stack unwinding will be initiated, so
- // caller saved registers were assumed volatile in the compiler.
-
-#undef __
-#define __ masm->
-
- address generate_throw_exception(const char* name,
- address runtime_entry,
- Register arg1 = noreg,
- Register arg2 = noreg) {
- // Information about frame layout at time of blocking runtime call.
- // Note that we only have to preserve callee-saved registers since
- // the compilers are responsible for supplying a continuation point
- // if they expect all registers to be preserved.
- // n.b. aarch64 asserts that frame::arg_reg_save_area_bytes == 0
- enum layout {
- rfp_off = 0,
- rfp_off2,
- return_off,
- return_off2,
- framesize // inclusive of return address
- };
-
- int insts_size = 512;
- int locs_size = 64;
-
- CodeBuffer code(name, insts_size, locs_size);
- OopMapSet* oop_maps = new OopMapSet();
- MacroAssembler* masm = new MacroAssembler(&code);
-
+ // load Method* target of MethodHandle
+ // j_rarg0 = jobject receiver
+ // rmethod = result
+ address generate_upcall_stub_load_target() {
+ StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target");
address start = __ pc();
- // This is an inlined and slightly modified version of call_VM
- // which has the ability to fetch the return PC out of
- // thread-local storage and also sets up last_Java_sp slightly
- // differently than the real call_VM
-
- __ enter(); // Save FP and LR before call
-
- assert(is_even(framesize/2), "sp not 16-byte aligned");
-
- // lr and fp are already in place
- __ sub(sp, rfp, ((uint64_t)framesize-4) << LogBytesPerInt); // prolog
-
- int frame_complete = __ pc() - start;
-
- // Set up last_Java_sp and last_Java_fp
- address the_pc = __ pc();
- __ set_last_Java_frame(sp, rfp, the_pc, rscratch1);
-
- // Call runtime
- if (arg1 != noreg) {
- assert(arg2 != c_rarg1, "clobbered");
- __ mov(c_rarg1, arg1);
- }
- if (arg2 != noreg) {
- __ mov(c_rarg2, arg2);
- }
- __ mov(c_rarg0, rthread);
- BLOCK_COMMENT("call runtime_entry");
- __ mov(rscratch1, runtime_entry);
- __ blr(rscratch1);
-
- // Generate oop map
- OopMap* map = new OopMap(framesize, 0);
-
- oop_maps->add_gc_map(the_pc - start, map);
-
- __ reset_last_Java_frame(true);
-
- // Reinitialize the ptrue predicate register, in case the external runtime
- // call clobbers ptrue reg, as we may return to SVE compiled code.
- __ reinitialize_ptrue();
+ __ resolve_global_jobject(j_rarg0, rscratch1, rscratch2);
+ // Load target method from receiver
+ __ load_heap_oop(rmethod, Address(j_rarg0, java_lang_invoke_MethodHandle::form_offset()), rscratch1, rscratch2);
+ __ load_heap_oop(rmethod, Address(rmethod, java_lang_invoke_LambdaForm::vmentry_offset()), rscratch1, rscratch2);
+ __ load_heap_oop(rmethod, Address(rmethod, java_lang_invoke_MemberName::method_offset()), rscratch1, rscratch2);
+ __ access_load_at(T_ADDRESS, IN_HEAP, rmethod,
+ Address(rmethod, java_lang_invoke_ResolvedMethodName::vmtarget_offset()),
+ noreg, noreg);
+ __ str(rmethod, Address(rthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized
- __ leave();
+ __ ret(lr);
- // check for pending exceptions
-#ifdef ASSERT
- Label L;
- __ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset()));
- __ cbnz(rscratch1, L);
- __ should_not_reach_here();
- __ bind(L);
-#endif // ASSERT
- __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
-
- // codeBlob framesize is in words (not VMRegImpl::slot_size)
- RuntimeStub* stub =
- RuntimeStub::new_runtime_stub(name,
- &code,
- frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps, false);
- return stub->entry_point();
+ return start;
}
+#undef __
+#define __ masm->
+
class MontgomeryMultiplyGenerator : public MacroAssembler {
Register Pa_base, Pb_base, Pn_base, Pm_base, inv, Rlen, Ra, Rb, Rm, Rn,
@@ -8363,16 +8195,6 @@ class StubGenerator: public StubCodeGenerator {
// is referenced by megamorphic call
StubRoutines::_catch_exception_entry = generate_catch_exception();
- // Build this early so it's available for the interpreter.
- StubRoutines::_throw_StackOverflowError_entry =
- generate_throw_exception("StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::throw_StackOverflowError));
- StubRoutines::_throw_delayed_StackOverflowError_entry =
- generate_throw_exception("delayed StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::throw_delayed_StackOverflowError));
-
// Initialize table for copy memory (arraycopy) check.
if (UnsafeMemoryAccess::_table == nullptr) {
UnsafeMemoryAccess::create_table(8 + 4); // 8 for copyMemory; 4 for setMemory
@@ -8408,41 +8230,13 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_cont_thaw = generate_cont_thaw();
StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier();
StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception();
-
- JFR_ONLY(generate_jfr_stubs();)
}
-#if INCLUDE_JFR
- void generate_jfr_stubs() {
- StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint();
- StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point();
- StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease();
- StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point();
- }
-#endif // INCLUDE_JFR
-
void generate_final_stubs() {
// support for verify_oop (must happen after universe_init)
if (VerifyOops) {
StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop();
}
- StubRoutines::_throw_AbstractMethodError_entry =
- generate_throw_exception("AbstractMethodError throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::
- throw_AbstractMethodError));
-
- StubRoutines::_throw_IncompatibleClassChangeError_entry =
- generate_throw_exception("IncompatibleClassChangeError throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::
- throw_IncompatibleClassChangeError));
-
- StubRoutines::_throw_NullPointerException_at_call_entry =
- generate_throw_exception("NullPointerException at call throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::
- throw_NullPointerException_at_call));
// arraycopy stubs used by compilers
generate_arraycopy_stubs();
@@ -8477,6 +8271,7 @@ class StubGenerator: public StubCodeGenerator {
#endif
StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler();
+ StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target();
StubRoutines::aarch64::set_completed(); // Inidicate that arraycopy and zero_blocks stubs are generated
}
diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp
index 89f5fbd281b..9894841e933 100644
--- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -26,6 +26,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "classfile/javaClasses.hpp"
+#include "compiler/disassembler.hpp"
#include "compiler/compiler_globals.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
@@ -67,13 +68,7 @@
// Max size with JVMTI
int TemplateInterpreter::InterpreterCodeSize = 200 * 1024;
-#define __ _masm->
-
-//-----------------------------------------------------------------------------
-
-extern "C" void entry(CodeBuffer*);
-
-//-----------------------------------------------------------------------------
+#define __ Disassembler::hook(__FILE__, __LINE__, _masm)->
address TemplateInterpreterGenerator::generate_slow_signature_handler() {
address entry = __ pc();
@@ -752,8 +747,8 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) {
// Note: the restored frame is not necessarily interpreted.
// Use the shared runtime version of the StackOverflowError.
- assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "stub not yet generated");
- __ far_jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry()));
+ assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "stub not yet generated");
+ __ far_jump(RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry()));
// all done with frame size check
__ bind(after_frame_check);
@@ -1337,8 +1332,8 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
{
Label L;
__ ldr(r10, Address(rmethod, Method::native_function_offset()));
- address unsatisfied = (SharedRuntime::native_method_throw_unsatisfied_link_error_entry());
- __ mov(rscratch2, unsatisfied);
+ ExternalAddress unsatisfied(SharedRuntime::native_method_throw_unsatisfied_link_error_entry());
+ __ lea(rscratch2, unsatisfied);
__ ldr(rscratch2, rscratch2);
__ cmp(r10, rscratch2);
__ br(Assembler::NE, L);
@@ -1413,15 +1408,8 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
{
Label L, Continue;
- // We need an acquire here to ensure that any subsequent load of the
- // global SafepointSynchronize::_state flag is ordered after this load
- // of the thread-local polling word. We don't want this poll to
- // return false (i.e. not safepointing) and a later poll of the global
- // SafepointSynchronize::_state spuriously to return true.
- //
- // This is to avoid a race when we're in a native->Java transition
- // racing the code which wakes up from a safepoint.
- __ safepoint_poll(L, true /* at_return */, true /* acquire */, false /* in_nmethod */);
+ // No need for acquire as Java threads always disarm themselves.
+ __ safepoint_poll(L, true /* at_return */, false /* acquire */, false /* in_nmethod */);
__ ldrw(rscratch2, Address(rthread, JavaThread::suspend_flags_offset()));
__ cbz(rscratch2, Continue);
__ bind(L);
@@ -1432,7 +1420,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
// hand.
//
__ mov(c_rarg0, rthread);
- __ mov(rscratch2, CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans));
+ __ lea(rscratch2, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)));
__ blr(rscratch2);
__ get_method(rmethod);
__ reinit_heapbase();
@@ -1482,7 +1470,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
__ push_call_clobbered_registers();
__ mov(c_rarg0, rthread);
- __ mov(rscratch2, CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages));
+ __ lea(rscratch2, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)));
__ blr(rscratch2);
__ pop_call_clobbered_registers();
@@ -2011,13 +1999,21 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t,
address& vep) {
assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
Label L;
- aep = __ pc(); __ push_ptr(); __ b(L);
- fep = __ pc(); __ push_f(); __ b(L);
- dep = __ pc(); __ push_d(); __ b(L);
- lep = __ pc(); __ push_l(); __ b(L);
- bep = cep = sep =
- iep = __ pc(); __ push_i();
- vep = __ pc();
+ aep = __ pc(); // atos entry point
+ __ push_ptr();
+ __ b(L);
+ fep = __ pc(); // ftos entry point
+ __ push_f();
+ __ b(L);
+ dep = __ pc(); // dtos entry point
+ __ push_d();
+ __ b(L);
+ lep = __ pc(); // ltos entry point
+ __ push_l();
+ __ b(L);
+ bep = cep = sep = iep = __ pc(); // [bcsi]tos entry point
+ __ push_i();
+ vep = __ pc(); // vtos entry point
__ bind(L);
generate_and_dispatch(t);
}
@@ -2085,7 +2081,7 @@ void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
assert(Interpreter::trace_code(t->tos_in()) != nullptr,
"entry must have been generated");
- __ bl(Interpreter::trace_code(t->tos_in()));
+ __ bl(RuntimeAddress(Interpreter::trace_code(t->tos_in())));
__ reinit_heapbase();
}
diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
index f7cf9938157..48ff356f9a5 100644
--- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
+#include "compiler/disassembler.hpp"
#include "compiler/compilerDefinitions.inline.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/collectedHeap.hpp"
@@ -49,7 +50,7 @@
#include "runtime/synchronizer.hpp"
#include "utilities/powerOfTwo.hpp"
-#define __ _masm->
+#define __ Disassembler::hook(__FILE__, __LINE__, _masm)->
// Address computation: local variables
@@ -2191,9 +2192,9 @@ void TemplateTable::_return(TosState state)
__ ldr(c_rarg1, aaddress(0));
__ load_klass(r3, c_rarg1);
- __ ldrw(r3, Address(r3, Klass::access_flags_offset()));
+ __ ldrb(r3, Address(r3, Klass::misc_flags_offset()));
Label skip_register_finalizer;
- __ tbz(r3, exact_log2(JVM_ACC_HAS_FINALIZER), skip_register_finalizer);
+ __ tbz(r3, exact_log2(KlassFlags::_misc_has_finalizer), skip_register_finalizer);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), c_rarg1);
diff --git a/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp b/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp
index 28ec07815be..517fccb2d1a 100644
--- a/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
+#include "classfile/javaClasses.hpp"
#include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
#include "prims/upcallLinker.hpp"
@@ -117,7 +118,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr
static const int upcall_stub_code_base_size = 1024;
static const int upcall_stub_size_per_arg = 16;
-address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
+address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
@@ -222,7 +223,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
__ block_comment("{ on_entry");
__ lea(c_rarg0, Address(sp, frame_data_offset));
- __ movptr(c_rarg1, (intptr_t)receiver);
__ movptr(rscratch1, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry));
__ blr(rscratch1);
__ mov(rthread, r0);
@@ -238,12 +238,10 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
arg_shuffle.generate(_masm, as_VMStorage(shuffle_reg), abi._shadow_space_bytes, 0);
__ block_comment("} argument shuffle");
- __ block_comment("{ receiver ");
- __ get_vm_result(j_rarg0, rthread);
- __ block_comment("} receiver ");
-
- __ mov_metadata(rmethod, entry);
- __ str(rmethod, Address(rthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized
+ __ block_comment("{ load target ");
+ __ movptr(j_rarg0, (intptr_t)receiver);
+ __ far_call(RuntimeAddress(StubRoutines::upcall_stub_load_target()), rscratch1); // puts target Method* in rmethod
+ __ block_comment("} load target ");
__ push_cont_fastpath(rthread);
@@ -318,7 +316,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
#ifndef PRODUCT
stringStream ss;
- ss.print("upcall_stub_%s", entry->signature()->as_C_string());
+ ss.print("upcall_stub_%s", signature->as_C_string());
const char* name = _masm->code_string(ss.as_string());
#else // PRODUCT
const char* name = "upcall_stub";
diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
index aa64f411dbf..d71162ac568 100644
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "pauth_aarch64.hpp"
+#include "register_aarch64.hpp"
#include "runtime/arguments.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/java.hpp"
@@ -44,6 +45,7 @@ int VM_Version::_zva_length;
int VM_Version::_dcache_line_size;
int VM_Version::_icache_line_size;
int VM_Version::_initial_sve_vector_length;
+int VM_Version::_max_supported_sve_vector_length;
bool VM_Version::_rop_protection;
uintptr_t VM_Version::_pac_mask;
@@ -507,30 +509,37 @@ void VM_Version::initialize() {
if (UseSVE > 0) {
if (FLAG_IS_DEFAULT(MaxVectorSize)) {
MaxVectorSize = _initial_sve_vector_length;
- } else if (MaxVectorSize < 16) {
- warning("SVE does not support vector length less than 16 bytes. Disabling SVE.");
+ } else if (MaxVectorSize < FloatRegister::sve_vl_min) {
+ warning("SVE does not support vector length less than %d bytes. Disabling SVE.",
+ FloatRegister::sve_vl_min);
UseSVE = 0;
- } else if ((MaxVectorSize % 16) == 0 && is_power_of_2(MaxVectorSize)) {
- int new_vl = set_and_get_current_sve_vector_length(MaxVectorSize);
- _initial_sve_vector_length = new_vl;
- // Update MaxVectorSize to the largest supported value.
- if (new_vl < 0) {
- vm_exit_during_initialization(
- err_msg("Current system does not support SVE vector length for MaxVectorSize: %d",
- (int)MaxVectorSize));
- } else if (new_vl != MaxVectorSize) {
- warning("Current system only supports max SVE vector length %d. Set MaxVectorSize to %d",
- new_vl, new_vl);
- }
- MaxVectorSize = new_vl;
- } else {
+ } else if (!((MaxVectorSize % FloatRegister::sve_vl_min) == 0 && is_power_of_2(MaxVectorSize))) {
vm_exit_during_initialization(err_msg("Unsupported MaxVectorSize: %d", (int)MaxVectorSize));
}
+
+ if (UseSVE > 0) {
+ // Acquire the largest supported vector length of this machine
+ _max_supported_sve_vector_length = set_and_get_current_sve_vector_length(FloatRegister::sve_vl_max);
+
+ if (MaxVectorSize != _max_supported_sve_vector_length) {
+ int new_vl = set_and_get_current_sve_vector_length(MaxVectorSize);
+ if (new_vl < 0) {
+ vm_exit_during_initialization(
+ err_msg("Current system does not support SVE vector length for MaxVectorSize: %d",
+ (int)MaxVectorSize));
+ } else if (new_vl != MaxVectorSize) {
+ warning("Current system only supports max SVE vector length %d. Set MaxVectorSize to %d",
+ new_vl, new_vl);
+ }
+ MaxVectorSize = new_vl;
+ }
+ _initial_sve_vector_length = MaxVectorSize;
+ }
}
if (UseSVE == 0) { // NEON
int min_vector_size = 8;
- int max_vector_size = 16;
+ int max_vector_size = FloatRegister::neon_vl;
if (!FLAG_IS_DEFAULT(MaxVectorSize)) {
if (!is_power_of_2(MaxVectorSize)) {
vm_exit_during_initialization(err_msg("Unsupported MaxVectorSize: %d", (int)MaxVectorSize));
@@ -542,11 +551,11 @@ void VM_Version::initialize() {
FLAG_SET_DEFAULT(MaxVectorSize, max_vector_size);
}
} else {
- FLAG_SET_DEFAULT(MaxVectorSize, 16);
+ FLAG_SET_DEFAULT(MaxVectorSize, FloatRegister::neon_vl);
}
}
- int inline_size = (UseSVE > 0 && MaxVectorSize >= 16) ? MaxVectorSize : 0;
+ int inline_size = (UseSVE > 0 && MaxVectorSize >= FloatRegister::sve_vl_min) ? MaxVectorSize : 0;
if (FLAG_IS_DEFAULT(ArrayOperationPartialInlineSize)) {
FLAG_SET_DEFAULT(ArrayOperationPartialInlineSize, inline_size);
} else if (ArrayOperationPartialInlineSize != 0 && ArrayOperationPartialInlineSize != inline_size) {
@@ -606,12 +615,12 @@ static bool check_info_file(const char* fpath,
return false;
}
while (fgets(line, sizeof(line), fp) != nullptr) {
- if (strcasestr(line, virt1) != 0) {
+ if (strcasestr(line, virt1) != nullptr) {
Abstract_VM_Version::_detected_virtualization = vt1;
fclose(fp);
return true;
}
- if (virt2 != nullptr && strcasestr(line, virt2) != 0) {
+ if (virt2 != nullptr && strcasestr(line, virt2) != nullptr) {
Abstract_VM_Version::_detected_virtualization = vt2;
fclose(fp);
return true;
diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
index f6cac72804f..04cf9c9c2a0 100644
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
@@ -46,6 +46,7 @@ class VM_Version : public Abstract_VM_Version {
static int _dcache_line_size;
static int _icache_line_size;
static int _initial_sve_vector_length;
+ static int _max_supported_sve_vector_length;
static bool _rop_protection;
static uintptr_t _pac_mask;
@@ -164,7 +165,8 @@ enum Ampere_CPU_Model {
static int icache_line_size() { return _icache_line_size; }
static int dcache_line_size() { return _dcache_line_size; }
- static int get_initial_sve_vector_length() { return _initial_sve_vector_length; };
+ static int get_initial_sve_vector_length() { return _initial_sve_vector_length; };
+ static int get_max_supported_sve_vector_length() { return _max_supported_sve_vector_length; };
// Aarch64 supports fast class initialization checks
static bool supports_fast_class_init_checks() { return true; }
diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad
index 638c48ad5aa..bfca986f350 100644
--- a/src/hotspot/cpu/arm/arm.ad
+++ b/src/hotspot/cpu/arm/arm.ad
@@ -1003,10 +1003,6 @@ const RegMask* Matcher::predicate_reg_mask(void) {
return nullptr;
}
-const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) {
- return nullptr;
-}
-
// Vector calling convention not yet implemented.
bool Matcher::supports_vector_calling_convention(void) {
return false;
@@ -3890,6 +3886,7 @@ instruct loadRange(iRegI dst, memoryI mem) %{
instruct loadP(iRegP dst, memoryP mem) %{
+ predicate(!(UseG1GC && n->as_Load()->barrier_data() != 0));
match(Set dst (LoadP mem));
ins_cost(MEMORY_REF_COST);
size(4);
@@ -4225,18 +4222,6 @@ instruct storeB(memoryB mem, store_RegI src) %{
ins_pipe(istore_mem_reg);
%}
-instruct storeCM(memoryB mem, store_RegI src) %{
- match(Set mem (StoreCM mem src));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "STRB $src,$mem\t! CMS card-mark byte" %}
- ins_encode %{
- __ strb($src$$Register, $mem$$Address);
- %}
- ins_pipe(istore_mem_reg);
-%}
-
// Store Char/Short
@@ -4356,6 +4341,7 @@ instruct movSP(store_ptr_RegP dst, SPRegP src) %{
instruct storeP(memoryP mem, store_ptr_RegP src) %{
+ predicate(!(UseG1GC && n->as_Store()->barrier_data() != 0));
match(Set mem (StoreP mem src));
ins_cost(MEMORY_REF_COST);
size(4);
@@ -5390,6 +5376,7 @@ instruct compareAndSwapI_bool(memoryex mem, iRegI oldval, iRegI newval, iRegI re
%}
instruct compareAndSwapP_bool(memoryex mem, iRegP oldval, iRegP newval, iRegI res, iRegI tmp, flagsReg ccr ) %{
+ predicate(!(UseG1GC && n->as_LoadStore()->barrier_data() != 0));
match(Set res (CompareAndSwapP mem (Binary oldval newval)));
effect( KILL ccr, TEMP tmp);
size(28);
@@ -5659,6 +5646,7 @@ instruct xchgL(memoryex mem, iRegLd newval, iRegLd res, iRegI tmp, flagsReg ccr)
%}
instruct xchgP(memoryex mem, iRegP newval, iRegP res, iRegI tmp, flagsReg ccr) %{
+ predicate(!(UseG1GC && n->as_LoadStore()->barrier_data() != 0));
match(Set res (GetAndSetP mem newval));
effect(KILL ccr, TEMP tmp, TEMP res);
size(16);
@@ -8953,6 +8941,20 @@ instruct tailjmpInd(IPRegP jump_target, RExceptionRegP ex_oop) %{
ins_pipe(tail_call);
%}
+// Forward exception.
+instruct ForwardExceptionjmp()
+%{
+ match(ForwardException);
+ ins_cost(CALL_COST);
+
+ format %{ "b forward_exception_stub" %}
+ ins_encode %{
+ // OK to trash Rtemp, because Rtemp is used by stub
+ __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp);
+ %}
+ ins_pipe(tail_call);
+%}
+
// Create exception oop: created by stack-crawling runtime code.
// Created exception is now available to this handler, and is setup
// just prior to jumping to this handler. No code emitted.
diff --git a/src/hotspot/cpu/arm/assembler_arm_32.hpp b/src/hotspot/cpu/arm/assembler_arm_32.hpp
index dd04ad1ab3a..e53eefac097 100644
--- a/src/hotspot/cpu/arm/assembler_arm_32.hpp
+++ b/src/hotspot/cpu/arm/assembler_arm_32.hpp
@@ -119,8 +119,9 @@ class RegisterSet {
}
friend RegisterSet operator | (const RegisterSet set1, const RegisterSet set2) {
- assert((set1._encoding & set2._encoding) == 0,
- "encoding constraint");
+// why so strong constraint?
+// assert((set1._encoding & set2._encoding) == 0,
+// "encoding constraint");
return RegisterSet(set1._encoding | set2._encoding);
}
@@ -142,6 +143,11 @@ class RegisterSet {
}
return count;
}
+
+ static RegisterSet from(RegSet set) {
+ assert(set.size(), "RegSet must not be empty");
+ return RegisterSet(set.bits());
+ }
};
#if R9_IS_SCRATCHED
@@ -157,6 +163,10 @@ class FloatRegisterSet {
public:
+ FloatRegisterSet() {
+ _encoding = 0;
+ }
+
FloatRegisterSet(FloatRegister reg) {
if (reg->hi_bit() == 0) {
_encoding = reg->hi_bits() << 12 | reg->lo_bit() << 22 | 1;
@@ -185,6 +195,15 @@ class FloatRegisterSet {
return (_encoding & 0xFFFFFF00) | ((_encoding & 0xFF) << 1);
}
+ static FloatRegisterSet from(FloatRegSet set) {
+ assert(set.size(), "FloatRegSet must not be empty");
+ // the vector load/store instructions operate on a set of consecutive registers.
+ // for the sake of simplicity, write all registers between the first and last in the set
+ size_t range = (*set.rbegin())->encoding() - (*set.begin())->encoding() + 1;
+ // push_float stores float regisgters by pairs
+ return FloatRegisterSet(*set.begin(), (range+1)/2);
+ }
+
};
diff --git a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp
index 3d8dbc38071..8e85fa88a87 100644
--- a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp
+++ b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,7 +46,7 @@ void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
ce->store_parameter(_bci, 0);
ce->store_parameter(_method->as_constant_ptr()->as_metadata(), 1);
- __ call(Runtime1::entry_for(Runtime1::counter_overflow_id), relocInfo::runtime_call_type);
+ __ call(Runtime1::entry_for(C1StubId::counter_overflow_id), relocInfo::runtime_call_type);
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
@@ -57,7 +57,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
if (_info->deoptimize_on_exception()) {
- __ call(Runtime1::entry_for(Runtime1::predicate_failed_trap_id), relocInfo::runtime_call_type);
+ __ call(Runtime1::entry_for(C1StubId::predicate_failed_trap_id), relocInfo::runtime_call_type);
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
debug_only(__ should_not_reach_here());
@@ -73,10 +73,10 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
}
if (_throw_index_out_of_bounds_exception) {
- __ call(Runtime1::entry_for(Runtime1::throw_index_exception_id), relocInfo::runtime_call_type);
+ __ call(Runtime1::entry_for(C1StubId::throw_index_exception_id), relocInfo::runtime_call_type);
} else {
__ str(_array->as_pointer_register(), Address(SP, BytesPerWord)); // ??? Correct offset? Correct instruction?
- __ call(Runtime1::entry_for(Runtime1::throw_range_check_failed_id), relocInfo::runtime_call_type);
+ __ call(Runtime1::entry_for(C1StubId::throw_range_check_failed_id), relocInfo::runtime_call_type);
}
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
@@ -89,7 +89,7 @@ PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- __ call(Runtime1::entry_for(Runtime1::predicate_failed_trap_id), relocInfo::runtime_call_type);
+ __ call(Runtime1::entry_for(C1StubId::predicate_failed_trap_id), relocInfo::runtime_call_type);
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
debug_only(__ should_not_reach_here());
@@ -100,7 +100,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) {
ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
}
__ bind(_entry);
- __ call(Runtime1::entry_for(Runtime1::throw_div0_exception_id),
+ __ call(Runtime1::entry_for(C1StubId::throw_div0_exception_id),
relocInfo::runtime_call_type);
ce->add_call_info_here(_info);
DEBUG_ONLY(STOP("DivByZero");)
@@ -109,14 +109,14 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) {
// Implementation of NewInstanceStub
-NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) {
+NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, C1StubId stub_id) {
_result = result;
_klass = klass;
_klass_reg = klass_reg;
_info = new CodeEmitInfo(info);
- assert(stub_id == Runtime1::new_instance_id ||
- stub_id == Runtime1::fast_new_instance_id ||
- stub_id == Runtime1::fast_new_instance_init_check_id,
+ assert(stub_id == C1StubId::new_instance_id ||
+ stub_id == C1StubId::fast_new_instance_id ||
+ stub_id == C1StubId::fast_new_instance_init_check_id,
"need new_instance id");
_stub_id = stub_id;
}
@@ -148,7 +148,7 @@ void NewTypeArrayStub::emit_code(LIR_Assembler* ce) {
assert(_klass_reg->as_register() == R1, "runtime call setup");
assert(_length->as_register() == R2, "runtime call setup");
__ bind(_entry);
- __ call(Runtime1::entry_for(Runtime1::new_type_array_id), relocInfo::runtime_call_type);
+ __ call(Runtime1::entry_for(C1StubId::new_type_array_id), relocInfo::runtime_call_type);
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
__ b(_continuation);
@@ -170,7 +170,7 @@ void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
assert(_klass_reg->as_register() == R1, "runtime call setup");
assert(_length->as_register() == R2, "runtime call setup");
__ bind(_entry);
- __ call(Runtime1::entry_for(Runtime1::new_object_array_id), relocInfo::runtime_call_type);
+ __ call(Runtime1::entry_for(C1StubId::new_object_array_id), relocInfo::runtime_call_type);
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
__ b(_continuation);
@@ -189,9 +189,9 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
__ str(lock_reg, Address(SP, BytesPerWord));
}
- Runtime1::StubID enter_id = ce->compilation()->has_fpu_code() ?
- Runtime1::monitorenter_id :
- Runtime1::monitorenter_nofpu_id;
+ C1StubId enter_id = ce->compilation()->has_fpu_code() ?
+ C1StubId::monitorenter_id :
+ C1StubId::monitorenter_nofpu_id;
__ call(Runtime1::entry_for(enter_id), relocInfo::runtime_call_type);
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
@@ -210,9 +210,9 @@ void MonitorExitStub::emit_code(LIR_Assembler* ce) {
__ str(lock_reg, Address(SP));
// Non-blocking leaf routine - no call info needed
- Runtime1::StubID exit_id = ce->compilation()->has_fpu_code() ?
- Runtime1::monitorexit_id :
- Runtime1::monitorexit_nofpu_id;
+ C1StubId exit_id = ce->compilation()->has_fpu_code() ?
+ C1StubId::monitorexit_id :
+ C1StubId::monitorexit_nofpu_id;
__ call(Runtime1::entry_for(exit_id), relocInfo::runtime_call_type);
__ b(_continuation);
}
@@ -322,10 +322,10 @@ void PatchingStub::emit_code(LIR_Assembler* ce) {
address target = nullptr;
relocInfo::relocType reloc_type = relocInfo::none;
switch (_id) {
- case access_field_id: target = Runtime1::entry_for(Runtime1::access_field_patching_id); break;
- case load_klass_id: target = Runtime1::entry_for(Runtime1::load_klass_patching_id); reloc_type = relocInfo::metadata_type; break;
- case load_mirror_id: target = Runtime1::entry_for(Runtime1::load_mirror_patching_id); reloc_type = relocInfo::oop_type; break;
- case load_appendix_id: target = Runtime1::entry_for(Runtime1::load_appendix_patching_id); reloc_type = relocInfo::oop_type; break;
+ case access_field_id: target = Runtime1::entry_for(C1StubId::access_field_patching_id); break;
+ case load_klass_id: target = Runtime1::entry_for(C1StubId::load_klass_patching_id); reloc_type = relocInfo::metadata_type; break;
+ case load_mirror_id: target = Runtime1::entry_for(C1StubId::load_mirror_patching_id); reloc_type = relocInfo::oop_type; break;
+ case load_appendix_id: target = Runtime1::entry_for(C1StubId::load_appendix_patching_id); reloc_type = relocInfo::oop_type; break;
default: ShouldNotReachHere();
}
__ bind(call_patch);
@@ -351,7 +351,7 @@ void DeoptimizeStub::emit_code(LIR_Assembler* ce) {
__ mov_slow(Rtemp, _trap_request);
ce->verify_reserved_argument_area_size(1);
__ str(Rtemp, Address(SP));
- __ call(Runtime1::entry_for(Runtime1::deoptimize_id), relocInfo::runtime_call_type);
+ __ call(Runtime1::entry_for(C1StubId::deoptimize_id), relocInfo::runtime_call_type);
ce->add_call_info_here(_info);
DEBUG_ONLY(__ should_not_reach_here());
}
@@ -362,9 +362,9 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
if (_info->deoptimize_on_exception()) {
// Deoptimize, do not throw the exception, because it is
// probably wrong to do it here.
- a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ a = Runtime1::entry_for(C1StubId::predicate_failed_trap_id);
} else {
- a = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id);
+ a = Runtime1::entry_for(C1StubId::throw_null_pointer_exception_id);
}
ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
__ bind(_entry);
diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
index 999f8fe5904..b14e6f0b4ca 100644
--- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
+++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
@@ -213,7 +213,7 @@ int LIR_Assembler::emit_exception_handler() {
// check that there is really an exception
__ verify_not_null_oop(Rexception_obj);
- __ call(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id), relocInfo::runtime_call_type);
+ __ call(Runtime1::entry_for(C1StubId::handle_exception_from_callee_id), relocInfo::runtime_call_type);
__ should_not_reach_here();
assert(code_offset() - offset <= exception_handler_size(), "overflow");
@@ -253,7 +253,7 @@ int LIR_Assembler::emit_unwind_handler() {
// remove the activation and dispatch to the unwind handler
__ remove_frame(initial_frame_size_in_bytes()); // restores FP and LR
- __ jump(Runtime1::entry_for(Runtime1::unwind_exception_id), relocInfo::runtime_call_type, Rtemp);
+ __ jump(Runtime1::entry_for(C1StubId::unwind_exception_id), relocInfo::runtime_call_type, Rtemp);
// Emit the slow path assembly
if (stub != nullptr) {
@@ -948,6 +948,7 @@ void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) {
if (op->init_check()) {
Register tmp = op->tmp1()->as_register();
__ ldrb(tmp, Address(op->klass()->as_register(), InstanceKlass::init_state_offset()));
+ __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp);
add_debug_info_for_null_check_here(op->stub()->info());
__ cmp(tmp, InstanceKlass::fully_initialized);
__ b(*op->stub()->entry(), ne);
@@ -1136,7 +1137,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
__ b(*failure_target, ne);
// slow case
assert(klass_RInfo == R0 && k_RInfo == R1, "runtime call setup");
- __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
+ __ call(Runtime1::entry_for(C1StubId::slow_subtype_check_id), relocInfo::runtime_call_type);
__ cbz(R0, *failure_target);
if (op->should_profile()) {
Register mdo = klass_RInfo, recv = k_RInfo, tmp1 = Rtemp;
@@ -1210,7 +1211,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
__ cmp(Rtemp, k_RInfo, ne);
__ b(*success_target, eq);
assert(klass_RInfo == R0 && k_RInfo == R1, "runtime call setup");
- __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
+ __ call(Runtime1::entry_for(C1StubId::slow_subtype_check_id), relocInfo::runtime_call_type);
__ cbz(R0, *failure_target);
}
} else {
@@ -1227,7 +1228,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
__ b(*failure_target, ne);
// slow case
assert(klass_RInfo == R0 && k_RInfo == R1, "runtime call setup");
- __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
+ __ call(Runtime1::entry_for(C1StubId::slow_subtype_check_id), relocInfo::runtime_call_type);
__ cbz(R0, *failure_target);
}
@@ -1303,7 +1304,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
}
__ b(*success_target, eq);
assert(klass_RInfo == R0 && k_RInfo == R1, "runtime call setup");
- __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
+ __ call(Runtime1::entry_for(C1StubId::slow_subtype_check_id), relocInfo::runtime_call_type);
if (!op->should_profile()) {
move_regs(R0, res);
} else {
@@ -1334,7 +1335,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
__ b(*failure_target, ne);
// slow case
assert(klass_RInfo == R0 && k_RInfo == R1, "runtime call setup");
- __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
+ __ call(Runtime1::entry_for(C1StubId::slow_subtype_check_id), relocInfo::runtime_call_type);
if (!op->should_profile()) {
move_regs(R0, res);
}
@@ -1981,9 +1982,9 @@ void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmit
assert(exceptionPC->as_register() == Rexception_pc, "must match");
info->add_register_oop(exceptionOop);
- Runtime1::StubID handle_id = compilation()->has_fpu_code() ?
- Runtime1::handle_exception_id :
- Runtime1::handle_exception_nofpu_id;
+ C1StubId handle_id = compilation()->has_fpu_code() ?
+ C1StubId::handle_exception_id :
+ C1StubId::handle_exception_nofpu_id;
Label return_address;
__ adr(Rexception_pc, return_address);
__ call(Runtime1::entry_for(handle_id), relocInfo::runtime_call_type);
@@ -2260,7 +2261,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
__ mov(altFP_7_11, R1);
__ mov(R0, tmp);
__ mov(R1, tmp2);
- __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); // does not blow any registers except R0, LR and Rtemp
+ __ call(Runtime1::entry_for(C1StubId::slow_subtype_check_id), relocInfo::runtime_call_type); // does not blow any registers except R0, LR and Rtemp
__ cmp_32(R0, 0);
__ mov(R0, R6);
__ mov(R1, altFP_7_11);
diff --git a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp
index f4e3812d77c..adda0c1c290 100644
--- a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp
+++ b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1054,7 +1054,7 @@ void LIRGenerator::do_NewMultiArray(NewMultiArray* x) {
args->append(rank);
args->append(varargs);
LIR_Opr reg = result_register_for(x->type());
- __ call_runtime(Runtime1::entry_for(Runtime1::new_multi_array_id),
+ __ call_runtime(Runtime1::entry_for(C1StubId::new_multi_array_id),
LIR_OprFact::illegalOpr, reg, args, info);
LIR_Opr result = rlock_result(x);
@@ -1083,7 +1083,7 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
CodeStub* stub;
if (x->is_incompatible_class_change_check()) {
assert(patching_info == nullptr, "can't patch this");
- stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id,
+ stub = new SimpleExceptionStub(C1StubId::throw_incompatible_class_change_error_id,
LIR_OprFact::illegalOpr, info_for_exception);
} else if (x->is_invokespecial_receiver_check()) {
assert(patching_info == nullptr, "can't patch this");
@@ -1091,7 +1091,7 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
Deoptimization::Reason_class_check,
Deoptimization::Action_none);
} else {
- stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id,
+ stub = new SimpleExceptionStub(C1StubId::throw_class_cast_exception_id,
LIR_OprFact::illegalOpr, info_for_exception);
}
diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
index f1267587ce4..70542d278ac 100644
--- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
+++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
@@ -195,8 +195,8 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp2, obj);
- ldr_u32(tmp2, Address(tmp2, Klass::access_flags_offset()));
- tst(tmp2, JVM_ACC_IS_VALUE_BASED_CLASS);
+ ldrb(tmp2, Address(tmp2, Klass::misc_flags_offset()));
+ tst(tmp2, KlassFlags::_misc_is_value_based_class);
b(slow_case, ne);
}
diff --git a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp
index 9862a074a68..b5117dedc42 100644
--- a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp
+++ b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -65,7 +65,7 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre
reset_last_Java_frame(Rtemp);
assert(frame_size() != no_frame_size, "frame must be fixed");
- if (_stub_id != Runtime1::forward_exception_id) {
+ if (_stub_id != (int)C1StubId::forward_exception_id) {
ldr(R3, Address(Rthread, Thread::pending_exception_offset()));
}
@@ -81,10 +81,10 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre
// Check for pending exception
// unpack_with_exception_in_tls path is taken through
// Runtime1::exception_handler_for_pc
- if (_stub_id != Runtime1::forward_exception_id) {
+ if (_stub_id != (int)C1StubId::forward_exception_id) {
assert(frame_size() != no_frame_size, "cannot directly call forward_exception_id");
cmp(R3, 0);
- jump(Runtime1::entry_for(Runtime1::forward_exception_id), relocInfo::runtime_call_type, Rtemp, ne);
+ jump(Runtime1::entry_for(C1StubId::forward_exception_id), relocInfo::runtime_call_type, Rtemp, ne);
} else {
#ifdef ASSERT
// Should not have pending exception in forward_exception stub
@@ -280,7 +280,7 @@ static void restore_sp_for_method_handle(StubAssembler* sasm) {
}
-OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) {
+OopMapSet* Runtime1::generate_handle_exception(C1StubId id, StubAssembler* sasm) {
__ block_comment("generate_handle_exception");
bool save_fpu_registers = false;
@@ -290,7 +290,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) {
OopMap* oop_map = nullptr;
switch (id) {
- case forward_exception_id: {
+ case C1StubId::forward_exception_id: {
save_fpu_registers = HaveVFP;
oop_map = generate_oop_map(sasm);
__ ldr(Rexception_obj, Address(Rthread, Thread::pending_exception_offset()));
@@ -299,14 +299,14 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) {
__ str(zero, Address(Rthread, Thread::pending_exception_offset()));
break;
}
- case handle_exception_id:
+ case C1StubId::handle_exception_id:
save_fpu_registers = HaveVFP;
// fall-through
- case handle_exception_nofpu_id:
+ case C1StubId::handle_exception_nofpu_id:
// At this point all registers MAY be live.
oop_map = save_live_registers(sasm, save_fpu_registers);
break;
- case handle_exception_from_callee_id:
+ case C1StubId::handle_exception_from_callee_id:
// At this point all registers except exception oop (R4/R19) and
// exception pc (R5/R20) are dead.
oop_map = save_live_registers(sasm); // TODO it's not required to save all registers
@@ -328,13 +328,13 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) {
// Restore the registers that were saved at the beginning, remove
// frame and jump to the exception handler.
switch (id) {
- case forward_exception_id:
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::forward_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
restore_live_registers(sasm, save_fpu_registers);
// Note: the restore live registers includes the jump to LR (patched to R0)
break;
- case handle_exception_from_callee_id:
+ case C1StubId::handle_exception_from_callee_id:
restore_live_registers_without_return(sasm); // must not jump immediately to handler
restore_sp_for_method_handle(sasm);
__ ret();
@@ -403,7 +403,7 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
}
-OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
+OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) {
const bool must_gc_arguments = true;
const bool dont_gc_arguments = false;
@@ -411,16 +411,16 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
bool save_fpu_registers = HaveVFP;
switch (id) {
- case forward_exception_id:
+ case C1StubId::forward_exception_id:
{
oop_maps = generate_handle_exception(id, sasm);
// does not return on ARM
}
break;
- case new_instance_id:
- case fast_new_instance_id:
- case fast_new_instance_init_check_id:
+ case C1StubId::new_instance_id:
+ case C1StubId::fast_new_instance_id:
+ case C1StubId::fast_new_instance_init_check_id:
{
const Register result = R0;
const Register klass = R1;
@@ -436,7 +436,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case counter_overflow_id:
+ case C1StubId::counter_overflow_id:
{
OopMap* oop_map = save_live_registers(sasm);
__ ldr(R1, Address(SP, arg1_offset));
@@ -448,10 +448,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case new_type_array_id:
- case new_object_array_id:
+ case C1StubId::new_type_array_id:
+ case C1StubId::new_object_array_id:
{
- if (id == new_type_array_id) {
+ if (id == C1StubId::new_type_array_id) {
__ set_info("new_type_array", dont_gc_arguments);
} else {
__ set_info("new_object_array", dont_gc_arguments);
@@ -463,7 +463,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
OopMap* map = save_live_registers(sasm);
int call_offset;
- if (id == new_type_array_id) {
+ if (id == C1StubId::new_type_array_id) {
call_offset = __ call_RT(result, noreg, CAST_FROM_FN_PTR(address, new_type_array), klass, length);
} else {
call_offset = __ call_RT(result, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length);
@@ -477,7 +477,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case new_multi_array_id:
+ case C1StubId::new_multi_array_id:
{
__ set_info("new_multi_array", dont_gc_arguments);
@@ -500,15 +500,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case register_finalizer_id:
+ case C1StubId::register_finalizer_id:
{
__ set_info("register_finalizer", dont_gc_arguments);
- // Do not call runtime if JVM_ACC_HAS_FINALIZER flag is not set
+ // Do not call runtime if has_finalizer flag is not set
__ load_klass(Rtemp, R0);
- __ ldr_u32(Rtemp, Address(Rtemp, Klass::access_flags_offset()));
+ __ ldrb(Rtemp, Address(Rtemp, Klass::misc_flags_offset()));
- __ tst(Rtemp, JVM_ACC_HAS_FINALIZER);
+ __ tst(Rtemp, KlassFlags::_misc_has_finalizer);
__ bx(LR, eq);
// Call VM
@@ -521,78 +521,78 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case throw_range_check_failed_id:
+ case C1StubId::throw_range_check_failed_id:
{
__ set_info("range_check_failed", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), true);
}
break;
- case throw_index_exception_id:
+ case C1StubId::throw_index_exception_id:
{
__ set_info("index_range_check_failed", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true);
}
break;
- case throw_div0_exception_id:
+ case C1StubId::throw_div0_exception_id:
{
__ set_info("throw_div0_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false);
}
break;
- case throw_null_pointer_exception_id:
+ case C1StubId::throw_null_pointer_exception_id:
{
__ set_info("throw_null_pointer_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false);
}
break;
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
{
__ set_info("handle_exception", dont_gc_arguments);
oop_maps = generate_handle_exception(id, sasm);
}
break;
- case handle_exception_from_callee_id:
+ case C1StubId::handle_exception_from_callee_id:
{
__ set_info("handle_exception_from_callee", dont_gc_arguments);
oop_maps = generate_handle_exception(id, sasm);
}
break;
- case unwind_exception_id:
+ case C1StubId::unwind_exception_id:
{
__ set_info("unwind_exception", dont_gc_arguments);
generate_unwind_exception(sasm);
}
break;
- case throw_array_store_exception_id:
+ case C1StubId::throw_array_store_exception_id:
{
__ set_info("throw_array_store_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_array_store_exception), true);
}
break;
- case throw_class_cast_exception_id:
+ case C1StubId::throw_class_cast_exception_id:
{
__ set_info("throw_class_cast_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true);
}
break;
- case throw_incompatible_class_change_error_id:
+ case C1StubId::throw_incompatible_class_change_error_id:
{
__ set_info("throw_incompatible_class_cast_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false);
}
break;
- case slow_subtype_check_id:
+ case C1StubId::slow_subtype_check_id:
{
// (in) R0 - sub, destroyed,
// (in) R1 - super, not changed
@@ -625,10 +625,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case monitorenter_nofpu_id:
+ case C1StubId::monitorenter_nofpu_id:
save_fpu_registers = false;
// fall through
- case monitorenter_id:
+ case C1StubId::monitorenter_id:
{
__ set_info("monitorenter", dont_gc_arguments);
const Register obj = R1;
@@ -643,10 +643,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case monitorexit_nofpu_id:
+ case C1StubId::monitorexit_nofpu_id:
save_fpu_registers = false;
// fall through
- case monitorexit_id:
+ case C1StubId::monitorexit_id:
{
__ set_info("monitorexit", dont_gc_arguments);
const Register lock = R1;
@@ -659,7 +659,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case deoptimize_id:
+ case C1StubId::deoptimize_id:
{
__ set_info("deoptimize", dont_gc_arguments);
OopMap* oop_map = save_live_registers(sasm);
@@ -675,35 +675,35 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case access_field_patching_id:
+ case C1StubId::access_field_patching_id:
{
__ set_info("access_field_patching", dont_gc_arguments);
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching));
}
break;
- case load_klass_patching_id:
+ case C1StubId::load_klass_patching_id:
{
__ set_info("load_klass_patching", dont_gc_arguments);
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching));
}
break;
- case load_appendix_patching_id:
+ case C1StubId::load_appendix_patching_id:
{
__ set_info("load_appendix_patching", dont_gc_arguments);
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching));
}
break;
- case load_mirror_patching_id:
+ case C1StubId::load_mirror_patching_id:
{
__ set_info("load_mirror_patching", dont_gc_arguments);
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_mirror_patching));
}
break;
- case predicate_failed_trap_id:
+ case C1StubId::predicate_failed_trap_id:
{
__ set_info("predicate_failed_trap", dont_gc_arguments);
diff --git a/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp
index 1db30ce5c68..900bd33fd9d 100644
--- a/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp
+++ b/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -86,8 +86,8 @@ void C2_MacroAssembler::fast_lock(Register Roop, Register Rbox, Register Rscratc
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(Rscratch, Roop);
- ldr_u32(Rscratch, Address(Rscratch, Klass::access_flags_offset()));
- tst(Rscratch, JVM_ACC_IS_VALUE_BASED_CLASS);
+ ldrb(Rscratch, Address(Rscratch, Klass::misc_flags_offset()));
+ tst(Rscratch, KlassFlags::_misc_is_value_based_class);
b(done, ne);
}
diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp
index 3c5e29aa871..56ae7707fbf 100644
--- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp
+++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp
@@ -39,8 +39,10 @@
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "gc/g1/c1/g1BarrierSetC1.hpp"
-#endif
-
+#endif // COMPILER1
+#ifdef COMPILER2
+#include "gc/g1/c2/g1BarrierSetC2.hpp"
+#endif // COMPILER2
#define __ masm->
#ifdef PRODUCT
@@ -106,70 +108,87 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas
#endif // !R9_IS_SCRATCHED
}
-// G1 pre-barrier.
-// Blows all volatile registers R0-R3, Rtemp, LR).
-// If store_addr != noreg, then previous value is loaded from [store_addr];
-// in such case store_addr and new_val registers are preserved;
-// otherwise pre_val register is preserved.
-void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
- Register store_addr,
- Register new_val,
- Register pre_val,
- Register tmp1,
- Register tmp2) {
- Label done;
- Label runtime;
-
- if (store_addr != noreg) {
- assert_different_registers(store_addr, new_val, pre_val, tmp1, tmp2, noreg);
- } else {
- assert (new_val == noreg, "should be");
- assert_different_registers(pre_val, tmp1, tmp2, noreg);
- }
-
- Address in_progress(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
- Address index(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
- Address buffer(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
+static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime,
+ const Register thread, const Register value, const Register temp1, const Register temp2) {
+ assert_different_registers(value, temp1, temp2);
+ // Can we store original value in the thread's buffer?
+ // (The index field is typed as size_t.)
+ __ ldr(temp1, Address(thread, in_bytes(index_offset))); // temp1 := *(index address)
+ __ cbz(temp1, runtime); // jump to runtime if index == 0 (full buffer)
+ // The buffer is not full, store value into it.
+ __ sub(temp1, temp1, wordSize); // temp1 := next index
+ __ str(temp1, Address(thread, in_bytes(index_offset))); // *(index address) := next index
+ __ ldr(temp2, Address(thread, in_bytes(buffer_offset))); // temp2 := buffer address
+ // Record the previous value
+ __ str(value, Address(temp2, temp1)); // *(buffer address + next index) := value
+ }
+static void generate_pre_barrier_fast_path(MacroAssembler* masm,
+ const Register thread,
+ const Register tmp1) {
+ Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
// Is marking active?
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "adjust this code");
__ ldrb(tmp1, in_progress);
- __ cbz(tmp1, done);
+}
+static void generate_pre_barrier_slow_path(MacroAssembler* masm,
+ const Register obj,
+ const Register pre_val,
+ const Register thread,
+ const Register tmp1,
+ const Register tmp2,
+ Label& done,
+ Label& runtime) {
// Do we need to load the previous value?
- if (store_addr != noreg) {
- __ load_heap_oop(pre_val, Address(store_addr, 0));
+ if (obj != noreg) {
+ __ load_heap_oop(pre_val, Address(obj, 0));
}
// Is the previous value null?
__ cbz(pre_val, done);
- // Can we store original value in the thread's buffer?
- // Is index == 0?
- // (The index field is typed as size_t.)
+ generate_queue_test_and_insertion(masm,
+ G1ThreadLocalData::satb_mark_queue_index_offset(),
+ G1ThreadLocalData::satb_mark_queue_buffer_offset(),
+ runtime,
+ thread, pre_val, tmp1, tmp2);
+ __ b(done);
+}
- __ ldr(tmp1, index); // tmp1 := *index_adr
- __ ldr(tmp2, buffer);
+// G1 pre-barrier.
+// Blows all volatile registers R0-R3, LR).
+// If obj != noreg, then previous value is loaded from [obj];
+// in such case obj and pre_val registers is preserved;
+// otherwise pre_val register is preserved.
+void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register tmp1,
+ Register tmp2) {
+ Label done;
+ Label runtime;
- __ subs(tmp1, tmp1, wordSize); // tmp1 := tmp1 - wordSize
- __ b(runtime, lt); // If negative, goto runtime
+ assert_different_registers(obj, pre_val, tmp1, tmp2, noreg);
- __ str(tmp1, index); // *index_adr := tmp1
+ generate_pre_barrier_fast_path(masm, Rthread, tmp1);
+ // If marking is not active (*(mark queue active address) == 0), jump to done
+ __ cbz(tmp1, done);
- // Record the previous value
- __ str(pre_val, Address(tmp2, tmp1));
- __ b(done);
+ generate_pre_barrier_slow_path(masm, obj, pre_val, Rthread, tmp1, tmp2, done, runtime);
__ bind(runtime);
// save the live input values
- if (store_addr != noreg) {
- // avoid raw_push to support any ordering of store_addr and new_val
- __ push(RegisterSet(store_addr) | RegisterSet(new_val));
- } else {
- __ push(pre_val);
+ RegisterSet set = RegisterSet(pre_val) | RegisterSet(R0, R3) | RegisterSet(R12);
+ // save the live input values
+ if (obj != noreg) {
+ // avoid raw_push to support any ordering of store_addr and pre_val
+ set = set | RegisterSet(obj);
}
+ __ push(set);
+
if (pre_val != R0) {
__ mov(R0, pre_val);
}
@@ -177,33 +196,17 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), R0, R1);
- if (store_addr != noreg) {
- __ pop(RegisterSet(store_addr) | RegisterSet(new_val));
- } else {
- __ pop(pre_val);
- }
-
+ __ pop(set);
__ bind(done);
}
-// G1 post-barrier.
-// Blows all volatile registers R0-R3, Rtemp, LR).
-void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
- Register store_addr,
- Register new_val,
- Register tmp1,
- Register tmp2,
- Register tmp3) {
-
- Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
- Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
-
- BarrierSet* bs = BarrierSet::barrier_set();
- CardTableBarrierSet* ctbs = barrier_set_cast(bs);
- CardTable* ct = ctbs->card_table();
- Label done;
- Label runtime;
-
+static void generate_post_barrier_fast_path(MacroAssembler* masm,
+ const Register store_addr,
+ const Register new_val,
+ const Register tmp1,
+ const Register tmp2,
+ Label& done,
+ bool new_val_may_be_null) {
// Does store cross heap regions?
__ eor(tmp1, store_addr, new_val);
@@ -211,22 +214,31 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
__ b(done, eq);
// crosses regions, storing null?
-
- __ cbz(new_val, done);
-
+ if (new_val_may_be_null) {
+ __ cbz(new_val, done);
+ }
// storing region crossing non-null, is card already dirty?
const Register card_addr = tmp1;
- __ mov_address(tmp2, (address)ct->byte_map_base());
+ CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set());
+ __ mov_address(tmp2, (address)ct->card_table()->byte_map_base());
__ add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTable::card_shift()));
__ ldrb(tmp2, Address(card_addr));
__ cmp(tmp2, (int)G1CardTable::g1_young_card_val());
- __ b(done, eq);
+}
+static void generate_post_barrier_slow_path(MacroAssembler* masm,
+ const Register thread,
+ const Register tmp1,
+ const Register tmp2,
+ const Register tmp3,
+ Label& done,
+ Label& runtime) {
__ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2);
-
assert(CardTable::dirty_card_val() == 0, "adjust this code");
+ // card_addr is loaded by generate_post_barrier_fast_path
+ const Register card_addr = tmp1;
__ ldrb(tmp2, Address(card_addr));
__ cbz(tmp2, done);
@@ -234,29 +246,139 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
// dirty card and log.
__ strb(__ zero_register(tmp2), Address(card_addr));
+ generate_queue_test_and_insertion(masm,
+ G1ThreadLocalData::dirty_card_queue_index_offset(),
+ G1ThreadLocalData::dirty_card_queue_buffer_offset(),
+ runtime,
+ thread, card_addr, tmp2, tmp3);
+ __ b(done);
+}
- __ ldr(tmp2, queue_index);
- __ ldr(tmp3, buffer);
- __ subs(tmp2, tmp2, wordSize);
- __ b(runtime, lt); // go to runtime if now negative
-
- __ str(tmp2, queue_index);
+// G1 post-barrier.
+// Blows all volatile registers R0-R3, LR).
+void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register tmp1,
+ Register tmp2,
+ Register tmp3) {
+ Label done;
+ Label runtime;
- __ str(card_addr, Address(tmp3, tmp2));
- __ b(done);
+ generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */);
+ // If card is young, jump to done
+ // card_addr and card are loaded by generate_post_barrier_fast_path
+ const Register card = tmp2;
+ const Register card_addr = tmp1;
+ __ b(done, eq);
+ generate_post_barrier_slow_path(masm, Rthread, card_addr, tmp2, tmp3, done, runtime);
__ bind(runtime);
+ RegisterSet set = RegisterSet(store_addr) | RegisterSet(R0, R3) | RegisterSet(R12);
+ __ push(set);
+
if (card_addr != R0) {
__ mov(R0, card_addr);
}
__ mov(R1, Rthread);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), R0, R1);
+ __ pop(set);
+
__ bind(done);
}
+#if defined(COMPILER2)
+
+static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path, Register tmp1) {
+ SaveLiveRegisters save_registers(masm, stub);
+ if (c_rarg0 != arg) {
+ __ mov(c_rarg0, arg);
+ }
+ __ mov(c_rarg1, Rthread);
+ __ call_VM_leaf(runtime_path, R0, R1);
+}
+
+void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2,
+ G1PreBarrierStubC2* stub) {
+ assert(thread == Rthread, "must be");
+ assert_different_registers(obj, pre_val, tmp1, tmp2);
+ assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register");
+
+ stub->initialize_registers(obj, pre_val, thread, tmp1, tmp2);
+
+ generate_pre_barrier_fast_path(masm, thread, tmp1);
+ // If marking is active (*(mark queue active address) != 0), jump to stub (slow path)
+ __ cbnz(tmp1, *stub->entry());
+
+ __ bind(*stub->continuation());
+}
+
+void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
+ G1PreBarrierStubC2* stub) const {
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ Label runtime;
+ Register obj = stub->obj();
+ Register pre_val = stub->pre_val();
+ Register thread = stub->thread();
+ Register tmp1 = stub->tmp1();
+ Register tmp2 = stub->tmp2();
+
+ __ bind(*stub->entry());
+ generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, *stub->continuation(), runtime);
+
+ __ bind(runtime);
+ generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), tmp1);
+ __ b(*stub->continuation());
+}
+
+void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2,
+ Register tmp3,
+ G1PostBarrierStubC2* stub) {
+ assert(thread == Rthread, "must be");
+ assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg);
+
+ stub->initialize_registers(thread, tmp1, tmp2, tmp3);
+
+ bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0;
+ generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null);
+ // If card is not young, jump to stub (slow path)
+ __ b(*stub->entry(), ne);
+
+ __ bind(*stub->continuation());
+}
+
+void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
+ G1PostBarrierStubC2* stub) const {
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ Label runtime;
+ Register thread = stub->thread();
+ Register tmp1 = stub->tmp1(); // tmp1 holds the card address.
+ Register tmp2 = stub->tmp2();
+ Register tmp3 = stub->tmp3();
+
+ __ bind(*stub->entry());
+ generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, tmp3, *stub->continuation(), runtime);
+
+ __ bind(runtime);
+ generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp2);
+ __ b(*stub->continuation());
+}
+
+#endif // COMPILER2
+
void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Address src, Register tmp1, Register tmp2, Register tmp3) {
bool on_oop = type == T_OBJECT || type == T_ARRAY;
@@ -268,7 +390,7 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator
if (on_oop && on_reference) {
// Generate the G1 pre-barrier code to log the value of
// the referent field in an SATB buffer.
- g1_write_barrier_pre(masm, noreg, noreg, dst, tmp1, tmp2);
+ g1_write_barrier_pre(masm, noreg, dst, tmp1, tmp2);
}
}
@@ -295,7 +417,7 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco
}
if (needs_pre_barrier) {
- g1_write_barrier_pre(masm, store_addr, new_val, tmp1, tmp2, tmp3);
+ g1_write_barrier_pre(masm, store_addr, tmp3 /*pre_val*/, tmp1, tmp2);
}
if (is_null) {
diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp
index 52932faa3e4..aefde19142e 100644
--- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp
+++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp
@@ -33,6 +33,8 @@ class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
class G1PostBarrierStub;
+class G1PreBarrierStubC2;
+class G1PostBarrierStubC2;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@@ -43,7 +45,6 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
void g1_write_barrier_pre(MacroAssembler* masm,
Register store_addr,
- Register new_val,
Register pre_val,
Register tmp1,
Register tmp2);
@@ -70,6 +71,29 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
#endif
+
+#ifdef COMPILER2
+ void g1_write_barrier_pre_c2(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2,
+ G1PreBarrierStubC2* c2_stub);
+ void generate_c2_pre_barrier_stub(MacroAssembler* masm,
+ G1PreBarrierStubC2* stub) const;
+ void g1_write_barrier_post_c2(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2,
+ Register tmp3,
+ G1PostBarrierStubC2* c2_stub);
+ void generate_c2_post_barrier_stub(MacroAssembler* masm,
+ G1PostBarrierStubC2* stub) const;
+#endif
+
};
#endif // CPU_ARM_GC_G1_G1BARRIERSETASSEMBLER_ARM_HPP
diff --git a/src/hotspot/cpu/arm/gc/g1/g1_arm.ad b/src/hotspot/cpu/arm/gc/g1/g1_arm.ad
new file mode 100644
index 00000000000..8a0a9e1aa53
--- /dev/null
+++ b/src/hotspot/cpu/arm/gc/g1/g1_arm.ad
@@ -0,0 +1,201 @@
+//
+// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+//
+// This code is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 2 only, as
+// published by the Free Software Foundation.
+//
+// This code is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// version 2 for more details (a copy is included in the LICENSE file that
+// accompanied this code).
+//
+// You should have received a copy of the GNU General Public License version
+// 2 along with this work; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+// or visit www.oracle.com if you need additional information or have any
+// questions.
+//
+
+source_hpp %{
+
+#include "gc/g1/c2/g1BarrierSetC2.hpp"
+#include "gc/shared/gc_globals.hpp"
+
+%}
+
+source %{
+
+#include "gc/g1/g1BarrierSetAssembler_arm.hpp"
+#include "gc/g1/g1BarrierSetRuntime.hpp"
+
+static void write_barrier_pre(MacroAssembler* masm,
+ const MachNode* node,
+ Register obj,
+ Register pre_val,
+ Register tmp1,
+ Register tmp2,
+ RegSet preserve = RegSet(),
+ RegSet no_preserve = RegSet()) {
+ if (!G1PreBarrierStubC2::needs_barrier(node)) {
+ return;
+ }
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
+ G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node);
+ for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) {
+ stub->preserve(*reg);
+ }
+ for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) {
+ stub->dont_preserve(*reg);
+ }
+ g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, Rthread, tmp1, tmp2, stub);
+}
+
+static void write_barrier_post(MacroAssembler* masm,
+ const MachNode* node,
+ Register store_addr,
+ Register new_val,
+ Register tmp1,
+ Register tmp2,
+ Register tmp3) {
+ if (!G1PostBarrierStubC2::needs_barrier(node)) {
+ return;
+ }
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
+ G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
+ g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, Rthread, tmp1, tmp2, tmp3, stub);
+}
+
+%}
+
+instruct g1StoreP(indirect mem, iRegP src, iRegP tmp1, iRegP tmp2, iRegP tmp3, flagsReg icc)
+%{
+ predicate(UseG1GC && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreP mem src));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL icc);
+ ins_cost(2 * (MEMORY_REF_COST + BRANCH_COST));
+ format %{ "sd $src, $mem\t# ptr" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ __ str($src$$Register, Address($mem$$Register));
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $src$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ $tmp3$$Register /* tmp3 */);
+ %}
+ ins_pipe(istore_mem_reg);
+%}
+
+instruct g1CompareAndSwapP(iRegI res, indirect mem, iRegP newval, iRegP tmp1, iRegP tmp2, iRegP tmp3, iRegP oldval, flagsReg ccr )
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapP mem (Binary oldval newval)));
+ effect(KILL ccr, TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3);
+ ins_cost(4 * (MEMORY_REF_COST + BRANCH_COST));
+ format %{ "loop: \n\t"
+ "LDREX $tmp1, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t"
+ "CMP $tmp1, $oldval\n\t"
+ "STREX.eq $tmp1, $newval, $mem\n\t"
+ "MOV.ne $tmp1, 0 \n\t"
+ "EORS.eq $tmp1,$tmp1, 1 \n\t"
+ "B.eq loop \n\t"
+ "MOV $res, $tmp1" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $oldval$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ Label loop;
+ __ bind(loop);
+ __ ldrex($tmp1$$Register,$mem$$Address);
+ __ cmp($tmp1$$Register, $oldval$$Register);
+ __ strex($tmp1$$Register, $newval$$Register, $mem$$Address, eq);
+ __ mov($tmp1$$Register, 0, ne);
+ __ eors($tmp1$$Register, $tmp1$$Register, 1, eq);
+ __ b(loop, eq);
+ __ mov($res$$Register, $tmp1$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ $tmp3$$Register /* tmp3 */);
+ %}
+ ins_pipe(long_memory_op);
+%}
+
+
+instruct g1GetAndSetP(indirect mem, iRegP newval, iRegP tmp1, iRegP tmp2, iRegP tmp3, iRegP preval, flagsReg ccr)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set preval (GetAndSetP mem newval));
+ effect(KILL ccr, TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3);
+ ins_cost(4 * (MEMORY_REF_COST + BRANCH_COST));
+ format %{ "loop: \n\t"
+ "LDREX $preval, $mem\n\t"
+ "STREX $tmp1, $newval, $mem\n\t"
+ "CMP $tmp1, 0 \n\t"
+ "B.ne loop \n\t" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ assert_different_registers($mem$$Register, $newval$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $preval$$Register /* pre_val (as a temporary register) */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */);
+ Label loop;
+ __ bind(loop);
+ __ ldrex($preval$$Register,$mem$$Address);
+ __ strex($tmp1$$Register, $newval$$Register, $mem$$Address);
+ __ cmp($tmp1$$Register, 0);
+ __ b(loop, ne);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ $tmp3$$Register /* tmp3 */);
+ %}
+ ins_pipe(long_memory_op);
+%}
+
+instruct g1LoadP(iRegP dst, indirect mem, iRegP tmp1, iRegP tmp2, flagsReg icc)
+%{
+ predicate(UseG1GC && n->as_Load()->barrier_data() != 0);
+ match(Set dst (LoadP mem));
+ effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL icc);
+ ins_cost(MEMORY_REF_COST + BRANCH_COST);
+ format %{ "ld $dst, $mem\t# ptr" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ __ ldr($dst$$Register, Address($mem$$Register));
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $dst$$Register /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(iload_mem);
+%}
diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp
index ea19730673c..c13a259a1b9 100644
--- a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp
+++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp
@@ -31,6 +31,10 @@
#include "runtime/javaThread.hpp"
#include "runtime/stubRoutines.hpp"
+#ifdef COMPILER2
+#include "gc/shared/c2/barrierSetC2.hpp"
+#endif // COMPILER2
+
#define __ masm->
void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
@@ -206,7 +210,57 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) {
#ifdef COMPILER2
OptoReg::Name BarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) {
- Unimplemented(); // This must be implemented to support late barrier expansion.
+ if (!OptoReg::is_reg(opto_reg)) {
+ return OptoReg::Bad;
+ }
+
+ const VMReg vm_reg = OptoReg::as_VMReg(opto_reg);
+ if (!vm_reg->is_valid()){
+ // skip APSR and FPSCR
+ return OptoReg::Bad;
+ }
+
+ return opto_reg;
}
+void SaveLiveRegisters::initialize(BarrierStubC2* stub) {
+ // Record registers that needs to be saved/restored
+ RegMaskIterator rmi(stub->preserve_set());
+ while (rmi.has_next()) {
+ const OptoReg::Name opto_reg = rmi.next();
+ if (OptoReg::is_reg(opto_reg)) {
+ const VMReg vm_reg = OptoReg::as_VMReg(opto_reg);
+ if (vm_reg->is_Register()) {
+ gp_regs += RegSet::of(vm_reg->as_Register());
+ } else if (vm_reg->is_FloatRegister()) {
+ fp_regs += FloatRegSet::of(vm_reg->as_FloatRegister());
+ } else {
+ fatal("Unknown register type");
+ }
+ }
+ }
+ // Remove C-ABI SOE registers that will be updated
+ gp_regs -= RegSet::range(R4, R11) + RegSet::of(R13, R15);
+
+ // Remove C-ABI SOE fp registers
+ fp_regs -= FloatRegSet::range(S16, S31);
+}
+
+SaveLiveRegisters::SaveLiveRegisters(MacroAssembler* masm, BarrierStubC2* stub)
+ : masm(masm),
+ gp_regs(),
+ fp_regs() {
+ // Figure out what registers to save/restore
+ initialize(stub);
+
+ // Save registers
+ if (gp_regs.size() > 0) __ push(RegisterSet::from(gp_regs));
+ if (fp_regs.size() > 0) __ fpush(FloatRegisterSet::from(fp_regs));
+}
+
+SaveLiveRegisters::~SaveLiveRegisters() {
+ // Restore registers
+ if (fp_regs.size() > 0) __ fpop(FloatRegisterSet::from(fp_regs));
+ if (gp_regs.size() > 0) __ pop(RegisterSet::from(gp_regs));
+}
#endif // COMPILER2
diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp
index 60021390ea2..054d172f463 100644
--- a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp
+++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp
@@ -31,7 +31,9 @@
#ifdef COMPILER2
#include "code/vmreg.hpp"
#include "opto/optoreg.hpp"
+#include "opto/regmask.hpp"
+class BarrierStubC2;
class Node;
#endif // COMPILER2
@@ -69,4 +71,26 @@ class BarrierSetAssembler: public CHeapObj {
#endif // COMPILER2
};
+#ifdef COMPILER2
+// This class saves and restores the registers that need to be preserved across
+// the runtime call represented by a given C2 barrier stub. Use as follows:
+// {
+// SaveLiveRegisters save(masm, stub);
+// ..
+// __ bl(...);
+// ..
+// }
+class SaveLiveRegisters {
+private:
+ MacroAssembler* const masm;
+ RegSet gp_regs;
+ FloatRegSet fp_regs;
+
+public:
+ void initialize(BarrierStubC2* stub);
+ SaveLiveRegisters(MacroAssembler* masm, BarrierStubC2* stub);
+ ~SaveLiveRegisters();
+};
+
+#endif // COMPILER2
#endif // CPU_ARM_GC_SHARED_BARRIERSETASSEMBLER_ARM_HPP
diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp
index ba161e360be..3a81fdddb3c 100644
--- a/src/hotspot/cpu/arm/interp_masm_arm.cpp
+++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -909,8 +909,8 @@ void InterpreterMacroAssembler::lock_object(Register Rlock) {
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(R0, Robj);
- ldr_u32(R0, Address(R0, Klass::access_flags_offset()));
- tst(R0, JVM_ACC_IS_VALUE_BASED_CLASS);
+ ldrb(R0, Address(R0, Klass::misc_flags_offset()));
+ tst(R0, KlassFlags::_misc_is_value_based_class);
b(slow_case, ne);
}
@@ -985,15 +985,7 @@ void InterpreterMacroAssembler::lock_object(Register Rlock) {
bind(slow_case);
// Call the runtime routine for slow case
- if (LockingMode == LM_LIGHTWEIGHT) {
- // Pass oop, not lock, in fast lock case. call_VM wants R1 though.
- push(R1);
- mov(R1, Robj);
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), R1);
- pop(R1);
- } else {
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), Rlock);
- }
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), Rlock);
bind(done);
}
}
diff --git a/src/hotspot/cpu/arm/methodHandles_arm.cpp b/src/hotspot/cpu/arm/methodHandles_arm.cpp
index 83939292055..7fc984afa99 100644
--- a/src/hotspot/cpu/arm/methodHandles_arm.cpp
+++ b/src/hotspot/cpu/arm/methodHandles_arm.cpp
@@ -39,6 +39,7 @@
#include "prims/jvmtiExport.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/frame.inline.hpp"
+#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "utilities/preserveException.hpp"
@@ -140,7 +141,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, bool for_comp
__ bind(L_no_such_method);
// throw exception
- __ jump(StubRoutines::throw_AbstractMethodError_entry(), relocInfo::runtime_call_type, Rtemp);
+ __ jump(SharedRuntime::throw_AbstractMethodError_entry(), relocInfo::runtime_call_type, Rtemp);
}
void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm,
@@ -461,7 +462,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
if (iid == vmIntrinsics::_linkToInterface) {
__ bind(L_incompatible_class_change_error);
- __ jump(StubRoutines::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, Rtemp);
+ __ jump(SharedRuntime::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, Rtemp);
}
}
}
diff --git a/src/hotspot/cpu/arm/register_arm.hpp b/src/hotspot/cpu/arm/register_arm.hpp
index 9f486d2a625..d8961fd2935 100644
--- a/src/hotspot/cpu/arm/register_arm.hpp
+++ b/src/hotspot/cpu/arm/register_arm.hpp
@@ -303,6 +303,31 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl {
static const int max_fpr;
};
+typedef AbstractRegSet RegSet;
+typedef AbstractRegSet FloatRegSet;
+
+template <>
+inline Register AbstractRegSet::first() {
+ if (_bitset == 0) { return noreg; }
+ return as_Register(count_trailing_zeros(_bitset));
+}
+
+
+template <>
+inline FloatRegister AbstractRegSet::first() {
+ uint32_t first = _bitset & -_bitset;
+ return first ? as_FloatRegister(exact_log2(first)) : fnoreg;
+}
+
+template <>
+inline FloatRegister AbstractRegSet::last() {
+ if (_bitset == 0) { return fnoreg; }
+ int last = max_size() - 1 - count_leading_zeros(_bitset);
+ return as_FloatRegister(last);
+}
+
+
+
class VFPSystemRegisterImpl;
typedef VFPSystemRegisterImpl* VFPSystemRegister;
class VFPSystemRegisterImpl : public AbstractRegisterImpl {
diff --git a/src/hotspot/cpu/arm/runtime_arm.cpp b/src/hotspot/cpu/arm/runtime_arm.cpp
index 94a9ef553c7..6f6c0c17e00 100644
--- a/src/hotspot/cpu/arm/runtime_arm.cpp
+++ b/src/hotspot/cpu/arm/runtime_arm.cpp
@@ -37,10 +37,146 @@
#include "runtime/vframeArray.hpp"
#include "utilities/globalDefinitions.hpp"
#include "vmreg_arm.inline.hpp"
-#endif
#define __ masm->
+//------------------------------generate_uncommon_trap_blob--------------------
+// Ought to generate an ideal graph & compile, but here's some ASM
+// instead.
+void OptoRuntime::generate_uncommon_trap_blob() {
+ // allocate space for the code
+ ResourceMark rm;
+
+ // setup code generation tools
+#ifdef _LP64
+ CodeBuffer buffer("uncommon_trap_blob", 2700, 512);
+#else
+ // Measured 8/7/03 at 660 in 32bit debug build
+ CodeBuffer buffer("uncommon_trap_blob", 2000, 512);
+#endif
+ // bypassed when code generation useless
+ MacroAssembler* masm = new MacroAssembler(&buffer);
+ const Register Rublock = R6;
+ const Register Rsender = altFP_7_11;
+ assert_different_registers(Rublock, Rsender, Rexception_obj, R0, R1, R2, R3, R8, Rtemp);
+
+ //
+ // This is the entry point for all traps the compiler takes when it thinks
+ // it cannot handle further execution of compilation code. The frame is
+ // deoptimized in these cases and converted into interpreter frames for
+ // execution
+ // The steps taken by this frame are as follows:
+ // - push a fake "unpack_frame"
+ // - call the C routine Deoptimization::uncommon_trap (this function
+ // packs the current compiled frame into vframe arrays and returns
+ // information about the number and size of interpreter frames which
+ // are equivalent to the frame which is being deoptimized)
+ // - deallocate the "unpack_frame"
+ // - deallocate the deoptimization frame
+ // - in a loop using the information returned in the previous step
+ // push interpreter frames;
+ // - create a dummy "unpack_frame"
+ // - call the C routine: Deoptimization::unpack_frames (this function
+ // lays out values on the interpreter frame which was just created)
+ // - deallocate the dummy unpack_frame
+ // - return to the interpreter entry point
+ //
+ // Refer to the following methods for more information:
+ // - Deoptimization::uncommon_trap
+ // - Deoptimization::unpack_frame
+
+ // the unloaded class index is in R0 (first parameter to this blob)
+
+ __ raw_push(FP, LR);
+ __ set_last_Java_frame(SP, FP, false, Rtemp);
+ __ mov(R2, Deoptimization::Unpack_uncommon_trap);
+ __ mov(R1, R0);
+ __ mov(R0, Rthread);
+ __ call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap));
+ __ mov(Rublock, R0);
+ __ reset_last_Java_frame(Rtemp);
+ __ raw_pop(FP, LR);
+
+#ifdef ASSERT
+ { Label L;
+ __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::unpack_kind_offset()));
+ __ cmp_32(Rtemp, Deoptimization::Unpack_uncommon_trap);
+ __ b(L, eq);
+ __ stop("OptoRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap");
+ __ bind(L);
+ }
+#endif
+
+
+ // Set initial stack state before pushing interpreter frames
+ __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset()));
+ __ ldr(R2, Address(Rublock, Deoptimization::UnrollBlock::frame_pcs_offset()));
+ __ ldr(R3, Address(Rublock, Deoptimization::UnrollBlock::frame_sizes_offset()));
+
+ __ add(SP, SP, Rtemp);
+
+ // See if it is enough stack to push deoptimized frames.
+#ifdef ASSERT
+ // Compilers generate code that bang the stack by as much as the
+ // interpreter would need. So this stack banging should never
+ // trigger a fault. Verify that it does not on non product builds.
+ //
+ // The compiled method that we are deoptimizing was popped from the stack.
+ // If the stack bang results in a stack overflow, we don't return to the
+ // method that is being deoptimized. The stack overflow exception is
+ // propagated to the caller of the deoptimized method. Need to get the pc
+ // from the caller in LR and restore FP.
+ __ ldr(LR, Address(R2, 0));
+ __ ldr(FP, Address(Rublock, Deoptimization::UnrollBlock::initial_info_offset()));
+ __ ldr_s32(R8, Address(Rublock, Deoptimization::UnrollBlock::total_frame_sizes_offset()));
+ __ arm_stack_overflow_check(R8, Rtemp);
+#endif
+ __ ldr_s32(R8, Address(Rublock, Deoptimization::UnrollBlock::number_of_frames_offset()));
+ __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::caller_adjustment_offset()));
+ __ mov(Rsender, SP);
+ __ sub(SP, SP, Rtemp);
+ // __ ldr(FP, Address(FP));
+ __ ldr(FP, Address(Rublock, Deoptimization::UnrollBlock::initial_info_offset()));
+
+ // Push interpreter frames in a loop
+ Label loop;
+ __ bind(loop);
+ __ ldr(LR, Address(R2, wordSize, post_indexed)); // load frame pc
+ __ ldr(Rtemp, Address(R3, wordSize, post_indexed)); // load frame size
+
+ __ raw_push(FP, LR); // create new frame
+ __ mov(FP, SP);
+ __ sub(Rtemp, Rtemp, 2*wordSize);
+
+ __ sub(SP, SP, Rtemp);
+
+ __ str(Rsender, Address(FP, frame::interpreter_frame_sender_sp_offset * wordSize));
+ __ mov(LR, 0);
+ __ str(LR, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize));
+ __ subs(R8, R8, 1); // decrement counter
+ __ mov(Rsender, SP);
+ __ b(loop, ne);
+
+ // Re-push self-frame
+ __ ldr(LR, Address(R2));
+ __ raw_push(FP, LR);
+ __ mov(FP, SP);
+
+ // Call unpack_frames with proper arguments
+ __ mov(R0, Rthread);
+ __ mov(R1, Deoptimization::Unpack_uncommon_trap);
+ __ set_last_Java_frame(SP, FP, true, Rtemp);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames));
+ // oop_maps->add_gc_map(__ pc() - start, new OopMap(frame_size_in_words, 0));
+ __ reset_last_Java_frame(Rtemp);
+
+ __ mov(SP, FP);
+ __ pop(RegisterSet(FP) | RegisterSet(PC));
+
+ masm->flush();
+ _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, nullptr, 2 /* LR+FP */);
+}
+
//------------------------------ generate_exception_blob ---------------------------
// creates exception blob at the end
// Using exception blob, this code is jumped from a compiled method.
@@ -148,3 +284,6 @@ void OptoRuntime::generate_exception_blob() {
_exception_blob = ExceptionBlob::create(&buffer, oop_maps, framesize_in_words);
}
+
+#endif // COMPILER2
+
diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
index 3792fab082b..7c1f3aafe7d 100644
--- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
+++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
@@ -38,6 +38,7 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/safepointMechanism.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/timerTrace.hpp"
#include "runtime/vframeArray.hpp"
#include "utilities/align.hpp"
#include "utilities/powerOfTwo.hpp"
@@ -1360,7 +1361,8 @@ uint SharedRuntime::out_preserve_stack_slots() {
//------------------------------generate_deopt_blob----------------------------
void SharedRuntime::generate_deopt_blob() {
ResourceMark rm;
- CodeBuffer buffer("deopt_blob", 1024, 1024);
+ const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id);
+ CodeBuffer buffer(name, 1024, 1024);
int frame_size_in_words;
OopMapSet* oop_maps;
int reexecute_offset;
@@ -1595,162 +1597,23 @@ void SharedRuntime::generate_deopt_blob() {
_deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
}
-#ifdef COMPILER2
-
-//------------------------------generate_uncommon_trap_blob--------------------
-// Ought to generate an ideal graph & compile, but here's some ASM
-// instead.
-void SharedRuntime::generate_uncommon_trap_blob() {
- // allocate space for the code
- ResourceMark rm;
-
- // setup code generation tools
-#ifdef _LP64
- CodeBuffer buffer("uncommon_trap_blob", 2700, 512);
-#else
- // Measured 8/7/03 at 660 in 32bit debug build
- CodeBuffer buffer("uncommon_trap_blob", 2000, 512);
-#endif
- // bypassed when code generation useless
- MacroAssembler* masm = new MacroAssembler(&buffer);
- const Register Rublock = R6;
- const Register Rsender = altFP_7_11;
- assert_different_registers(Rublock, Rsender, Rexception_obj, R0, R1, R2, R3, R8, Rtemp);
-
- //
- // This is the entry point for all traps the compiler takes when it thinks
- // it cannot handle further execution of compilation code. The frame is
- // deoptimized in these cases and converted into interpreter frames for
- // execution
- // The steps taken by this frame are as follows:
- // - push a fake "unpack_frame"
- // - call the C routine Deoptimization::uncommon_trap (this function
- // packs the current compiled frame into vframe arrays and returns
- // information about the number and size of interpreter frames which
- // are equivalent to the frame which is being deoptimized)
- // - deallocate the "unpack_frame"
- // - deallocate the deoptimization frame
- // - in a loop using the information returned in the previous step
- // push interpreter frames;
- // - create a dummy "unpack_frame"
- // - call the C routine: Deoptimization::unpack_frames (this function
- // lays out values on the interpreter frame which was just created)
- // - deallocate the dummy unpack_frame
- // - return to the interpreter entry point
- //
- // Refer to the following methods for more information:
- // - Deoptimization::uncommon_trap
- // - Deoptimization::unpack_frame
-
- // the unloaded class index is in R0 (first parameter to this blob)
-
- __ raw_push(FP, LR);
- __ set_last_Java_frame(SP, FP, false, Rtemp);
- __ mov(R2, Deoptimization::Unpack_uncommon_trap);
- __ mov(R1, R0);
- __ mov(R0, Rthread);
- __ call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap));
- __ mov(Rublock, R0);
- __ reset_last_Java_frame(Rtemp);
- __ raw_pop(FP, LR);
-
-#ifdef ASSERT
- { Label L;
- __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::unpack_kind_offset()));
- __ cmp_32(Rtemp, Deoptimization::Unpack_uncommon_trap);
- __ b(L, eq);
- __ stop("SharedRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap");
- __ bind(L);
- }
-#endif
-
-
- // Set initial stack state before pushing interpreter frames
- __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset()));
- __ ldr(R2, Address(Rublock, Deoptimization::UnrollBlock::frame_pcs_offset()));
- __ ldr(R3, Address(Rublock, Deoptimization::UnrollBlock::frame_sizes_offset()));
-
- __ add(SP, SP, Rtemp);
-
- // See if it is enough stack to push deoptimized frames.
-#ifdef ASSERT
- // Compilers generate code that bang the stack by as much as the
- // interpreter would need. So this stack banging should never
- // trigger a fault. Verify that it does not on non product builds.
- //
- // The compiled method that we are deoptimizing was popped from the stack.
- // If the stack bang results in a stack overflow, we don't return to the
- // method that is being deoptimized. The stack overflow exception is
- // propagated to the caller of the deoptimized method. Need to get the pc
- // from the caller in LR and restore FP.
- __ ldr(LR, Address(R2, 0));
- __ ldr(FP, Address(Rublock, Deoptimization::UnrollBlock::initial_info_offset()));
- __ ldr_s32(R8, Address(Rublock, Deoptimization::UnrollBlock::total_frame_sizes_offset()));
- __ arm_stack_overflow_check(R8, Rtemp);
-#endif
- __ ldr_s32(R8, Address(Rublock, Deoptimization::UnrollBlock::number_of_frames_offset()));
- __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::caller_adjustment_offset()));
- __ mov(Rsender, SP);
- __ sub(SP, SP, Rtemp);
- // __ ldr(FP, Address(FP));
- __ ldr(FP, Address(Rublock, Deoptimization::UnrollBlock::initial_info_offset()));
-
- // Push interpreter frames in a loop
- Label loop;
- __ bind(loop);
- __ ldr(LR, Address(R2, wordSize, post_indexed)); // load frame pc
- __ ldr(Rtemp, Address(R3, wordSize, post_indexed)); // load frame size
-
- __ raw_push(FP, LR); // create new frame
- __ mov(FP, SP);
- __ sub(Rtemp, Rtemp, 2*wordSize);
-
- __ sub(SP, SP, Rtemp);
-
- __ str(Rsender, Address(FP, frame::interpreter_frame_sender_sp_offset * wordSize));
- __ mov(LR, 0);
- __ str(LR, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize));
- __ subs(R8, R8, 1); // decrement counter
- __ mov(Rsender, SP);
- __ b(loop, ne);
-
- // Re-push self-frame
- __ ldr(LR, Address(R2));
- __ raw_push(FP, LR);
- __ mov(FP, SP);
-
- // Call unpack_frames with proper arguments
- __ mov(R0, Rthread);
- __ mov(R1, Deoptimization::Unpack_uncommon_trap);
- __ set_last_Java_frame(SP, FP, true, Rtemp);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames));
- // oop_maps->add_gc_map(__ pc() - start, new OopMap(frame_size_in_words, 0));
- __ reset_last_Java_frame(Rtemp);
-
- __ mov(SP, FP);
- __ pop(RegisterSet(FP) | RegisterSet(PC));
-
- masm->flush();
- _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, nullptr, 2 /* LR+FP */);
-}
-
-#endif // COMPILER2
-
//------------------------------generate_handler_blob------
//
// Generate a special Compile2Runtime blob that saves all registers,
// setup oopmap, and calls safepoint code to stop the compiled code for
// a safepoint.
//
-SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) {
+SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) {
assert(StubRoutines::forward_exception_entry() != nullptr, "must be generated before");
+ assert(is_polling_page_id(id), "expected a polling page stub id");
ResourceMark rm;
- CodeBuffer buffer("handler_blob", 256, 256);
+ const char* name = SharedRuntime::stub_name(id);
+ CodeBuffer buffer(name, 256, 256);
int frame_size_words;
OopMapSet* oop_maps;
- bool cause_return = (poll_type == POLL_AT_RETURN);
+ bool cause_return = (id == SharedStubId::polling_page_return_handler_id);
MacroAssembler* masm = new MacroAssembler(&buffer);
address start = __ pc();
@@ -1812,10 +1675,12 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
return SafepointBlob::create(&buffer, oop_maps, frame_size_words);
}
-RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) {
+RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) {
assert(StubRoutines::forward_exception_entry() != nullptr, "must be generated before");
+ assert(is_resolve_id(id), "expected a resolve stub id");
ResourceMark rm;
+ const char* name = SharedRuntime::stub_name(id);
CodeBuffer buffer(name, 1000, 512);
int frame_size_words;
OopMapSet *oop_maps;
@@ -1869,3 +1734,149 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha
return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true);
}
+
+//------------------------------------------------------------------------------------------------------------------------
+// Continuation point for throwing of implicit exceptions that are not handled in
+// the current activation. Fabricates an exception oop and initiates normal
+// exception dispatching in this frame.
+RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) {
+ assert(is_throw_id(id), "expected a throw stub id");
+
+ const char* name = SharedRuntime::stub_name(id);
+
+ int insts_size = 128;
+ int locs_size = 32;
+
+ ResourceMark rm;
+ const char* timer_msg = "SharedRuntime generate_throw_exception";
+ TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime));
+
+ CodeBuffer code(name, insts_size, locs_size);
+ OopMapSet* oop_maps;
+ int frame_size;
+ int frame_complete;
+
+ oop_maps = new OopMapSet();
+ MacroAssembler* masm = new MacroAssembler(&code);
+
+ address start = __ pc();
+
+ frame_size = 2;
+ __ mov(Rexception_pc, LR);
+ __ raw_push(FP, LR);
+
+ frame_complete = __ pc() - start;
+
+ // Any extra arguments are already supposed to be R1 and R2
+ __ mov(R0, Rthread);
+
+ int pc_offset = __ set_last_Java_frame(SP, FP, false, Rtemp);
+ assert(((__ pc()) - start) == __ offset(), "warning: start differs from code_begin");
+ __ call(runtime_entry);
+ if (pc_offset == -1) {
+ pc_offset = __ offset();
+ }
+
+ // Generate oop map
+ OopMap* map = new OopMap(frame_size*VMRegImpl::slots_per_word, 0);
+ oop_maps->add_gc_map(pc_offset, map);
+ __ reset_last_Java_frame(Rtemp); // Rtemp free since scratched by far call
+
+ __ raw_pop(FP, LR);
+ __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp);
+
+ RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete,
+ frame_size, oop_maps, false);
+ return stub;
+}
+
+#if INCLUDE_JFR
+
+// For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
+// It returns a jobject handle to the event writer.
+// The handle is dereferenced and the return value is the event writer oop.
+RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() {
+ enum layout {
+ r1_off,
+ r2_off,
+ return_off,
+ framesize // inclusive of return address
+ };
+
+ const char* name = SharedRuntime::stub_name(SharedStubId::jfr_write_checkpoint_id);
+ CodeBuffer code(name, 512, 64);
+ MacroAssembler* masm = new MacroAssembler(&code);
+
+ address start = __ pc();
+ __ raw_push(R1, R2, LR);
+ address the_pc = __ pc();
+
+ int frame_complete = the_pc - start;
+
+ __ set_last_Java_frame(SP, FP, true, Rtemp);
+ __ mov(c_rarg0, Rthread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), c_rarg0);
+ __ reset_last_Java_frame(Rtemp);
+
+ // R0 is jobject handle result, unpack and process it through a barrier.
+ __ resolve_global_jobject(R0, Rtemp, R1);
+
+ __ raw_pop(R1, R2, LR);
+ __ ret();
+
+ OopMapSet* oop_maps = new OopMapSet();
+ OopMap* map = new OopMap(framesize, 1);
+ oop_maps->add_gc_map(frame_complete, map);
+
+ RuntimeStub* stub =
+ RuntimeStub::new_runtime_stub(name,
+ &code,
+ frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps,
+ false);
+ return stub;
+}
+
+// For c2: call to return a leased buffer.
+RuntimeStub* SharedRuntime::generate_jfr_return_lease() {
+ enum layout {
+ r1_off,
+ r2_off,
+ return_off,
+ framesize // inclusive of return address
+ };
+
+ const char* name = SharedRuntime::stub_name(SharedStubId::jfr_return_lease_id);
+ CodeBuffer code(name, 512, 64);
+ MacroAssembler* masm = new MacroAssembler(&code);
+
+ address start = __ pc();
+ __ raw_push(R1, R2, LR);
+ address the_pc = __ pc();
+
+ int frame_complete = the_pc - start;
+
+ __ set_last_Java_frame(SP, FP, true, Rtemp);
+ __ mov(c_rarg0, Rthread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), c_rarg0);
+ __ reset_last_Java_frame(Rtemp);
+
+ __ raw_pop(R1, R2, LR);
+ __ ret();
+
+ OopMapSet* oop_maps = new OopMapSet();
+ OopMap* map = new OopMap(framesize, 1);
+ oop_maps->add_gc_map(frame_complete, map);
+
+ RuntimeStub* stub =
+ RuntimeStub::new_runtime_stub(name,
+ &code,
+ frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps,
+ false);
+ return stub;
+}
+
+#endif // INCLUDE_JFR
diff --git a/src/hotspot/cpu/arm/smallRegisterMap_arm.inline.hpp b/src/hotspot/cpu/arm/smallRegisterMap_arm.inline.hpp
index 4186eafd35f..08adbbd89d8 100644
--- a/src/hotspot/cpu/arm/smallRegisterMap_arm.inline.hpp
+++ b/src/hotspot/cpu/arm/smallRegisterMap_arm.inline.hpp
@@ -30,8 +30,15 @@
// Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap
class SmallRegisterMap {
+ constexpr SmallRegisterMap() = default;
+ ~SmallRegisterMap() = default;
+ NONCOPYABLE(SmallRegisterMap);
+
public:
- static constexpr SmallRegisterMap* instance = nullptr;
+ static const SmallRegisterMap* instance() {
+ static constexpr SmallRegisterMap the_instance{};
+ return &the_instance;
+ }
private:
static void assert_is_rfp(VMReg r) NOT_DEBUG_RETURN
DEBUG_ONLY({ Unimplemented(); })
@@ -46,12 +53,6 @@ class SmallRegisterMap {
return map;
}
- SmallRegisterMap() {}
-
- SmallRegisterMap(const RegisterMap* map) {
- Unimplemented();
- }
-
inline address location(VMReg reg, intptr_t* sp) const {
Unimplemented();
return nullptr;
diff --git a/src/hotspot/cpu/arm/stubGenerator_arm.cpp b/src/hotspot/cpu/arm/stubGenerator_arm.cpp
index 0d66a2fbb0a..9b91e02cf07 100644
--- a/src/hotspot/cpu/arm/stubGenerator_arm.cpp
+++ b/src/hotspot/cpu/arm/stubGenerator_arm.cpp
@@ -2961,52 +2961,6 @@ class StubGenerator: public StubCodeGenerator {
#undef __
#define __ masm->
- //------------------------------------------------------------------------------------------------------------------------
- // Continuation point for throwing of implicit exceptions that are not handled in
- // the current activation. Fabricates an exception oop and initiates normal
- // exception dispatching in this frame.
- address generate_throw_exception(const char* name, address runtime_entry) {
- int insts_size = 128;
- int locs_size = 32;
- CodeBuffer code(name, insts_size, locs_size);
- OopMapSet* oop_maps;
- int frame_size;
- int frame_complete;
-
- oop_maps = new OopMapSet();
- MacroAssembler* masm = new MacroAssembler(&code);
-
- address start = __ pc();
-
- frame_size = 2;
- __ mov(Rexception_pc, LR);
- __ raw_push(FP, LR);
-
- frame_complete = __ pc() - start;
-
- // Any extra arguments are already supposed to be R1 and R2
- __ mov(R0, Rthread);
-
- int pc_offset = __ set_last_Java_frame(SP, FP, false, Rtemp);
- assert(((__ pc()) - start) == __ offset(), "warning: start differs from code_begin");
- __ call(runtime_entry);
- if (pc_offset == -1) {
- pc_offset = __ offset();
- }
-
- // Generate oop map
- OopMap* map = new OopMap(frame_size*VMRegImpl::slots_per_word, 0);
- oop_maps->add_gc_map(pc_offset, map);
- __ reset_last_Java_frame(Rtemp); // Rtemp free since scratched by far call
-
- __ raw_pop(FP, LR);
- __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp);
-
- RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete,
- frame_size, oop_maps, false);
- return stub->entry_point();
- }
-
address generate_cont_thaw(const char* label, Continuation::thaw_kind kind) {
if (!Continuations::enabled()) return nullptr;
Unimplemented();
@@ -3025,95 +2979,6 @@ class StubGenerator: public StubCodeGenerator {
return generate_cont_thaw("Cont thaw return barrier exception", Continuation::thaw_return_barrier_exception);
}
-#if INCLUDE_JFR
-
- // For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
- // It returns a jobject handle to the event writer.
- // The handle is dereferenced and the return value is the event writer oop.
- static RuntimeStub* generate_jfr_write_checkpoint() {
- enum layout {
- r1_off,
- r2_off,
- return_off,
- framesize // inclusive of return address
- };
-
- CodeBuffer code("jfr_write_checkpoint", 512, 64);
- MacroAssembler* masm = new MacroAssembler(&code);
-
- address start = __ pc();
- __ raw_push(R1, R2, LR);
- address the_pc = __ pc();
-
- int frame_complete = the_pc - start;
-
- __ set_last_Java_frame(SP, FP, true, Rtemp);
- __ mov(c_rarg0, Rthread);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), c_rarg0);
- __ reset_last_Java_frame(Rtemp);
-
- // R0 is jobject handle result, unpack and process it through a barrier.
- __ resolve_global_jobject(R0, Rtemp, R1);
-
- __ raw_pop(R1, R2, LR);
- __ ret();
-
- OopMapSet* oop_maps = new OopMapSet();
- OopMap* map = new OopMap(framesize, 1);
- oop_maps->add_gc_map(frame_complete, map);
-
- RuntimeStub* stub =
- RuntimeStub::new_runtime_stub(code.name(),
- &code,
- frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps,
- false);
- return stub;
- }
-
- // For c2: call to return a leased buffer.
- static RuntimeStub* generate_jfr_return_lease() {
- enum layout {
- r1_off,
- r2_off,
- return_off,
- framesize // inclusive of return address
- };
-
- CodeBuffer code("jfr_return_lease", 512, 64);
- MacroAssembler* masm = new MacroAssembler(&code);
-
- address start = __ pc();
- __ raw_push(R1, R2, LR);
- address the_pc = __ pc();
-
- int frame_complete = the_pc - start;
-
- __ set_last_Java_frame(SP, FP, true, Rtemp);
- __ mov(c_rarg0, Rthread);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), c_rarg0);
- __ reset_last_Java_frame(Rtemp);
-
- __ raw_pop(R1, R2, LR);
- __ ret();
-
- OopMapSet* oop_maps = new OopMapSet();
- OopMap* map = new OopMap(framesize, 1);
- oop_maps->add_gc_map(frame_complete, map);
-
- RuntimeStub* stub =
- RuntimeStub::new_runtime_stub(code.name(),
- &code,
- frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps,
- false);
- return stub;
- }
-
-#endif // INCLUDE_JFR
-
//---------------------------------------------------------------------------
// Initialization
@@ -3132,8 +2997,6 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_catch_exception_entry = generate_catch_exception();
// stub for throwing stack overflow error used both by interpreter and compiler
- StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError));
-
if (UnsafeMemoryAccess::_table == nullptr) {
UnsafeMemoryAccess::create_table(32 + 4); // 32 for copyMemory; 4 for setMemory
}
@@ -3155,28 +3018,11 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_cont_thaw = generate_cont_thaw();
StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier();
StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception();
-
- JFR_ONLY(generate_jfr_stubs();)
}
-#if INCLUDE_JFR
- void generate_jfr_stubs() {
- StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint();
- StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point();
- StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease();
- StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point();
- }
-#endif // INCLUDE_JFR
-
void generate_final_stubs() {
// Generates all stubs and initializes the entry points
- // These entry points require SharedInfo::stack0 to be set up in non-core builds
- // and need to be relocatable, so they each fabricate a RuntimeStub internally.
- StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError));
- StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError));
- StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call));
-
//------------------------------------------------------------------------------------------------------------------------
// entry points that are platform specific
diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp
index efaf78ee568..ec9d237e50d 100644
--- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp
+++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp
@@ -175,6 +175,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
break;
case Interpreter::java_lang_math_fmaD:
case Interpreter::java_lang_math_fmaF:
+ case Interpreter::java_lang_math_tanh:
// TODO: Implement intrinsic
break;
default:
@@ -560,7 +561,7 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) {
__ cmp(Rtemp, R0);
__ mov(SP, Rsender_sp, ls); // restore SP
- __ b(StubRoutines::throw_StackOverflowError_entry(), ls);
+ __ b(SharedRuntime::throw_StackOverflowError_entry(), ls);
}
diff --git a/src/hotspot/cpu/arm/templateTable_arm.cpp b/src/hotspot/cpu/arm/templateTable_arm.cpp
index e657c659588..0974ff1f9a9 100644
--- a/src/hotspot/cpu/arm/templateTable_arm.cpp
+++ b/src/hotspot/cpu/arm/templateTable_arm.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -2494,8 +2494,8 @@ void TemplateTable::_return(TosState state) {
assert(state == vtos, "only valid state");
__ ldr(R1, aaddress(0));
__ load_klass(Rtemp, R1);
- __ ldr_u32(Rtemp, Address(Rtemp, Klass::access_flags_offset()));
- __ tbz(Rtemp, exact_log2(JVM_ACC_HAS_FINALIZER), skip_register_finalizer);
+ __ ldrb(Rtemp, Address(Rtemp, Klass::misc_flags_offset()));
+ __ tbz(Rtemp, exact_log2(KlassFlags::_misc_has_finalizer), skip_register_finalizer);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), R1);
@@ -3974,6 +3974,7 @@ void TemplateTable::_new() {
// make sure klass is initialized
// make sure klass is fully initialized
__ ldrb(Rtemp, Address(Rklass, InstanceKlass::init_state_offset()));
+ __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp);
__ cmp(Rtemp, InstanceKlass::fully_initialized);
__ b(slow_case, ne);
diff --git a/src/hotspot/cpu/arm/upcallLinker_arm.cpp b/src/hotspot/cpu/arm/upcallLinker_arm.cpp
index c7645f4a033..696b2001e6b 100644
--- a/src/hotspot/cpu/arm/upcallLinker_arm.cpp
+++ b/src/hotspot/cpu/arm/upcallLinker_arm.cpp
@@ -25,7 +25,7 @@
#include "prims/upcallLinker.hpp"
#include "utilities/debug.hpp"
-address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
+address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
diff --git a/src/hotspot/cpu/ppc/assembler_ppc.cpp b/src/hotspot/cpu/ppc/assembler_ppc.cpp
index 26fc1aacad3..dc8180bfedf 100644
--- a/src/hotspot/cpu/ppc/assembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/assembler_ppc.cpp
@@ -292,31 +292,54 @@ void Assembler::stb(Register d, RegisterOrConstant roc, Register s1, Register tm
}
}
-void Assembler::add(Register d, RegisterOrConstant roc, Register s1) {
+void Assembler::add(Register d, Register s, RegisterOrConstant roc) {
if (roc.is_constant()) {
intptr_t c = roc.as_constant();
assert(is_simm(c, 16), "too big");
- addi(d, s1, (int)c);
+ addi(d, s, (int)c);
+ } else {
+ add(d, s, roc.as_register());
}
- else add(d, roc.as_register(), s1);
}
-void Assembler::subf(Register d, RegisterOrConstant roc, Register s1) {
+void Assembler::sub(Register d, Register s, RegisterOrConstant roc) {
if (roc.is_constant()) {
intptr_t c = roc.as_constant();
assert(is_simm(-c, 16), "too big");
- addi(d, s1, (int)-c);
+ addi(d, s, (int)-c);
+ } else {
+ sub(d, s, roc.as_register());
+ }
+}
+
+void Assembler::xorr(Register d, Register s, RegisterOrConstant roc) {
+ if (roc.is_constant()) {
+ intptr_t c = roc.as_constant();
+ assert(is_uimm(c, 16), "too big");
+ xori(d, s, (int)c);
+ } else {
+ xorr(d, s, roc.as_register());
}
- else subf(d, roc.as_register(), s1);
}
-void Assembler::cmpd(ConditionRegister d, RegisterOrConstant roc, Register s1) {
+void Assembler::cmpw(ConditionRegister d, Register s, RegisterOrConstant roc) {
if (roc.is_constant()) {
intptr_t c = roc.as_constant();
assert(is_simm(c, 16), "too big");
- cmpdi(d, s1, (int)c);
+ cmpwi(d, s, (int)c);
+ } else {
+ cmpw(d, s, roc.as_register());
+ }
+}
+
+void Assembler::cmpd(ConditionRegister d, Register s, RegisterOrConstant roc) {
+ if (roc.is_constant()) {
+ intptr_t c = roc.as_constant();
+ assert(is_simm(c, 16), "too big");
+ cmpdi(d, s, (int)c);
+ } else {
+ cmpd(d, s, roc.as_register());
}
- else cmpd(d, roc.as_register(), s1);
}
// Load a 64 bit constant. Patchable.
diff --git a/src/hotspot/cpu/ppc/assembler_ppc.hpp b/src/hotspot/cpu/ppc/assembler_ppc.hpp
index d18574f50a9..d445108098b 100644
--- a/src/hotspot/cpu/ppc/assembler_ppc.hpp
+++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp
@@ -2512,9 +2512,13 @@ class Assembler : public AbstractAssembler {
void stw( Register d, RegisterOrConstant roc, Register s1 = noreg, Register tmp = noreg);
void sth( Register d, RegisterOrConstant roc, Register s1 = noreg, Register tmp = noreg);
void stb( Register d, RegisterOrConstant roc, Register s1 = noreg, Register tmp = noreg);
- void add( Register d, RegisterOrConstant roc, Register s1);
- void subf(Register d, RegisterOrConstant roc, Register s1);
- void cmpd(ConditionRegister d, RegisterOrConstant roc, Register s1);
+ void add( Register d, Register s, RegisterOrConstant roc);
+ void add( Register d, RegisterOrConstant roc, Register s) { add(d, s, roc); }
+ void sub( Register d, Register s, RegisterOrConstant roc);
+ void xorr(Register d, Register s, RegisterOrConstant roc);
+ void xorr(Register d, RegisterOrConstant roc, Register s) { xorr(d, s, roc); }
+ void cmpw(ConditionRegister d, Register s, RegisterOrConstant roc);
+ void cmpd(ConditionRegister d, Register s, RegisterOrConstant roc);
// Load pointer d from s1+roc.
void ld_ptr(Register d, RegisterOrConstant roc, Register s1 = noreg) { ld(d, roc, s1); }
diff --git a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp
index dc70c73d4b3..451f3b7e9cd 100644
--- a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2021 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -68,7 +68,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
if (_info->deoptimize_on_exception()) {
- address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ address a = Runtime1::entry_for(C1StubId::predicate_failed_trap_id);
//__ load_const_optimized(R0, a);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a));
__ mtctr(R0);
@@ -79,8 +79,8 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
return;
}
- address stub = _throw_index_out_of_bounds_exception ? Runtime1::entry_for(Runtime1::throw_index_exception_id)
- : Runtime1::entry_for(Runtime1::throw_range_check_failed_id);
+ address stub = _throw_index_out_of_bounds_exception ? Runtime1::entry_for(C1StubId::throw_index_exception_id)
+ : Runtime1::entry_for(C1StubId::throw_range_check_failed_id);
//__ load_const_optimized(R0, stub);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
__ mtctr(R0);
@@ -109,7 +109,7 @@ PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ address a = Runtime1::entry_for(C1StubId::predicate_failed_trap_id);
//__ load_const_optimized(R0, a);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a));
__ mtctr(R0);
@@ -133,7 +133,7 @@ void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
__ load_const_optimized(R0, md.value());
__ std(R0, -8, R1_SP);
- address a = Runtime1::entry_for(Runtime1::counter_overflow_id);
+ address a = Runtime1::entry_for(C1StubId::counter_overflow_id);
//__ load_const_optimized(R0, a);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a));
__ mtctr(R0);
@@ -150,7 +150,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) {
ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
}
__ bind(_entry);
- address stub = Runtime1::entry_for(Runtime1::throw_div0_exception_id);
+ address stub = Runtime1::entry_for(C1StubId::throw_div0_exception_id);
//__ load_const_optimized(R0, stub);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
__ mtctr(R0);
@@ -165,9 +165,9 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
address a;
if (_info->deoptimize_on_exception()) {
// Deoptimize, do not throw the exception, because it is probably wrong to do it here.
- a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ a = Runtime1::entry_for(C1StubId::predicate_failed_trap_id);
} else {
- a = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id);
+ a = Runtime1::entry_for(C1StubId::throw_null_pointer_exception_id);
}
if (ImplicitNullChecks || TrapBasedNullChecks) {
@@ -199,14 +199,14 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) {
// Implementation of NewInstanceStub
-NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) {
+NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, C1StubId stub_id) {
_result = result;
_klass = klass;
_klass_reg = klass_reg;
_info = new CodeEmitInfo(info);
- assert(stub_id == Runtime1::new_instance_id ||
- stub_id == Runtime1::fast_new_instance_id ||
- stub_id == Runtime1::fast_new_instance_init_check_id,
+ assert(stub_id == C1StubId::new_instance_id ||
+ stub_id == C1StubId::fast_new_instance_id ||
+ stub_id == C1StubId::fast_new_instance_init_check_id,
"need new_instance id");
_stub_id = stub_id;
}
@@ -236,7 +236,7 @@ NewTypeArrayStub::NewTypeArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr re
void NewTypeArrayStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- address entry = Runtime1::entry_for(Runtime1::new_type_array_id);
+ address entry = Runtime1::entry_for(C1StubId::new_type_array_id);
//__ load_const_optimized(R0, entry);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry));
__ mr_if_needed(/*op->tmp1()->as_register()*/ R5_ARG3, _length->as_register()); // already sign-extended
@@ -259,7 +259,7 @@ NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Op
void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- address entry = Runtime1::entry_for(Runtime1::new_object_array_id);
+ address entry = Runtime1::entry_for(C1StubId::new_object_array_id);
//__ load_const_optimized(R0, entry);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry));
__ mr_if_needed(/*op->tmp1()->as_register()*/ R5_ARG3, _length->as_register()); // already sign-extended
@@ -272,7 +272,7 @@ void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? Runtime1::monitorenter_id : Runtime1::monitorenter_nofpu_id);
+ address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? C1StubId::monitorenter_id : C1StubId::monitorenter_nofpu_id);
//__ load_const_optimized(R0, stub);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
__ mr_if_needed(/*scratch_opr()->as_register()*/ R4_ARG2, _obj_reg->as_register());
@@ -289,7 +289,7 @@ void MonitorExitStub::emit_code(LIR_Assembler* ce) {
if (_compute_lock) {
ce->monitor_address(_monitor_ix, _lock_reg);
}
- address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? Runtime1::monitorexit_id : Runtime1::monitorexit_nofpu_id);
+ address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? C1StubId::monitorexit_id : C1StubId::monitorexit_nofpu_id);
//__ load_const_optimized(R0, stub);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
assert(_lock_reg->as_register() == R4_ARG2, "");
@@ -403,12 +403,12 @@ void PatchingStub::emit_code(LIR_Assembler* ce) {
address target = nullptr;
relocInfo::relocType reloc_type = relocInfo::none;
switch (_id) {
- case access_field_id: target = Runtime1::entry_for(Runtime1::access_field_patching_id); break;
- case load_klass_id: target = Runtime1::entry_for(Runtime1::load_klass_patching_id);
+ case access_field_id: target = Runtime1::entry_for(C1StubId::access_field_patching_id); break;
+ case load_klass_id: target = Runtime1::entry_for(C1StubId::load_klass_patching_id);
reloc_type = relocInfo::metadata_type; break;
- case load_mirror_id: target = Runtime1::entry_for(Runtime1::load_mirror_patching_id);
+ case load_mirror_id: target = Runtime1::entry_for(C1StubId::load_mirror_patching_id);
reloc_type = relocInfo::oop_type; break;
- case load_appendix_id: target = Runtime1::entry_for(Runtime1::load_appendix_patching_id);
+ case load_appendix_id: target = Runtime1::entry_for(C1StubId::load_appendix_patching_id);
reloc_type = relocInfo::oop_type; break;
default: ShouldNotReachHere();
}
@@ -434,7 +434,7 @@ void PatchingStub::emit_code(LIR_Assembler* ce) {
void DeoptimizeStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- address stub = Runtime1::entry_for(Runtime1::deoptimize_id);
+ address stub = Runtime1::entry_for(C1StubId::deoptimize_id);
//__ load_const_optimized(R0, stub);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
__ mtctr(R0);
diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp
index 0c1e23c6353..57e5f65d2f9 100644
--- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp
@@ -133,9 +133,20 @@ void LIR_Assembler::osr_entry() {
// copied into place by code emitted in the IR.
Register OSR_buf = osrBufferPointer()->as_register();
- { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below");
- int monitor_offset = BytesPerWord * method()->max_locals() +
- (2 * BytesPerWord) * (number_of_locks - 1);
+ {
+ assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below");
+
+ const int locals_space = BytesPerWord * method()->max_locals();
+ int monitor_offset = locals_space + (2 * BytesPerWord) * (number_of_locks - 1);
+ bool use_OSR_bias = false;
+
+ if (!Assembler::is_simm16(monitor_offset + BytesPerWord) && number_of_locks > 0) {
+ // Offsets too large for ld instructions. Use bias.
+ __ add_const_optimized(OSR_buf, OSR_buf, locals_space);
+ monitor_offset -= locals_space;
+ use_OSR_bias = true;
+ }
+
// SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in
// the OSR buffer using 2 word entries: first the lock and then
// the oop.
@@ -161,6 +172,11 @@ void LIR_Assembler::osr_entry() {
__ ld(R0, slot_offset + 1*BytesPerWord, OSR_buf);
__ std(R0, mo.disp(), mo.base());
}
+
+ if (use_OSR_bias) {
+ // Restore.
+ __ sub_const_optimized(OSR_buf, OSR_buf, locals_space);
+ }
}
}
@@ -176,7 +192,7 @@ int LIR_Assembler::emit_exception_handler() {
}
int offset = code_offset();
- address entry_point = CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::handle_exception_from_callee_id));
+ address entry_point = CAST_FROM_FN_PTR(address, Runtime1::entry_for(C1StubId::handle_exception_from_callee_id));
//__ load_const_optimized(R0, entry_point);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry_point));
__ mtctr(R0);
@@ -213,7 +229,11 @@ int LIR_Assembler::emit_unwind_handler() {
if (method()->is_synchronized()) {
monitor_address(0, FrameMap::R4_opr);
stub = new MonitorExitStub(FrameMap::R4_opr, true, 0);
- __ unlock_object(R5, R6, R4, *stub->entry());
+ if (LockingMode == LM_MONITOR) {
+ __ b(*stub->entry());
+ } else {
+ __ unlock_object(R5, R6, R4, *stub->entry());
+ }
__ bind(*stub->continuation());
}
@@ -222,7 +242,7 @@ int LIR_Assembler::emit_unwind_handler() {
}
// Dispatch to the unwind logic.
- address unwind_stub = Runtime1::entry_for(Runtime1::unwind_exception_id);
+ address unwind_stub = Runtime1::entry_for(C1StubId::unwind_exception_id);
//__ load_const_optimized(R0, unwind_stub);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(unwind_stub));
if (preserve_exception) { __ mr(Rexception, Rexception_save); }
@@ -1800,8 +1820,8 @@ void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmit
__ calculate_address_from_global_toc(exceptionPC->as_register(), pc_for_athrow, true, true, /*add_relocation*/ true);
add_call_info(pc_for_athrow_offset, info); // for exception handler
- address stub = Runtime1::entry_for(compilation()->has_fpu_code() ? Runtime1::handle_exception_id
- : Runtime1::handle_exception_nofpu_id);
+ address stub = Runtime1::entry_for(compilation()->has_fpu_code() ? C1StubId::handle_exception_id
+ : C1StubId::handle_exception_nofpu_id);
//__ load_const_optimized(R0, stub);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
__ mtctr(R0);
@@ -1859,7 +1879,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
__ stw(R11_scratch1, simm16_offs, tmp);
}
#endif
- __ call_c_with_frame_resize(copyfunc_addr, /*stub does not need resized frame*/ 0);
+ __ call_c(copyfunc_addr, relocInfo::runtime_call_type);
__ nand(tmp, R3_RET, R3_RET);
__ subf(length, tmp, length);
@@ -2001,7 +2021,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
__ check_klass_subtype_fast_path(sub_klass, super_klass, tmp, tmp2,
&cont, copyfunc_addr != nullptr ? ©func : &slow, nullptr);
- address slow_stc = Runtime1::entry_for(Runtime1::slow_subtype_check_id);
+ address slow_stc = Runtime1::entry_for(C1StubId::slow_subtype_check_id);
//__ load_const_optimized(tmp, slow_stc, tmp2);
__ calculate_address_from_global_toc(tmp, slow_stc, true, true, false);
__ mtctr(tmp);
@@ -2057,7 +2077,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
int sco_offset = in_bytes(Klass::super_check_offset_offset());
__ lwz(chk_off, sco_offset, super_k);
- __ call_c_with_frame_resize(copyfunc_addr, /*stub does not need resized frame*/ 0);
+ __ call_c(copyfunc_addr, relocInfo::runtime_call_type);
#ifndef PRODUCT
if (PrintC1Statistics) {
@@ -2181,7 +2201,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
// Arraycopy stubs takes a length in number of elements, so don't scale it.
__ mr(len, length);
- __ call_c_with_frame_resize(entry, /*stub does not need resized frame*/ 0);
+ __ call_c(entry, relocInfo::runtime_call_type);
if (stub != nullptr) {
__ bind(*stub->continuation());
@@ -2274,6 +2294,7 @@ void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) {
}
__ lbz(op->tmp1()->as_register(),
in_bytes(InstanceKlass::init_state_offset()), op->klass()->as_register());
+ // acquire barrier included in membar_storestore() which follows the allocation immediately.
__ cmpwi(CCR0, op->tmp1()->as_register(), InstanceKlass::fully_initialized);
__ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CCR0, Assembler::equal), *op->stub()->entry());
}
@@ -2452,7 +2473,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L
__ b(*success);
} else {
// Call out-of-line instance of __ check_klass_subtype_slow_path(...):
- address entry = Runtime1::entry_for(Runtime1::slow_subtype_check_id);
+ address entry = Runtime1::entry_for(C1StubId::slow_subtype_check_id);
// Stub needs fixed registers (tmp1-3).
Register original_k_RInfo = op->tmp1()->as_register();
Register original_klass_RInfo = op->tmp2()->as_register();
@@ -2543,7 +2564,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
__ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, R0, &done, &failure, nullptr);
// Call out-of-line instance of __ check_klass_subtype_slow_path(...):
- const address slow_path = Runtime1::entry_for(Runtime1::slow_subtype_check_id);
+ const address slow_path = Runtime1::entry_for(C1StubId::slow_subtype_check_id);
//__ load_const_optimized(R0, slow_path);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(slow_path));
__ mtctr(R0);
@@ -2620,7 +2641,7 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) {
__ cmpxchgw(BOOL_RESULT, /*current_value=*/R0, cmp_value, new_value, addr,
MacroAssembler::MemBarNone,
MacroAssembler::cmpxchgx_hint_atomic_update(),
- noreg, /*check without ldarx first*/true);
+ noreg, nullptr, /*check without ldarx first*/true);
}
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
@@ -2850,8 +2871,8 @@ void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) {
void LIR_Assembler::rt_call(LIR_Opr result, address dest,
const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) {
// Stubs: Called via rt_call, but dest is a stub address (no function descriptor).
- if (dest == Runtime1::entry_for(Runtime1::register_finalizer_id) ||
- dest == Runtime1::entry_for(Runtime1::new_multi_array_id )) {
+ if (dest == Runtime1::entry_for(C1StubId::register_finalizer_id) ||
+ dest == Runtime1::entry_for(C1StubId::new_multi_array_id )) {
//__ load_const_optimized(R0, dest);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(dest));
__ mtctr(R0);
@@ -2862,7 +2883,7 @@ void LIR_Assembler::rt_call(LIR_Opr result, address dest,
return;
}
- __ call_c_with_frame_resize(dest, /*no resizing*/ 0);
+ __ call_c(dest, relocInfo::runtime_call_type);
if (info != nullptr) {
add_call_info_here(info);
}
diff --git a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp
index 04762a22c61..7973e9d0545 100644
--- a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp
@@ -1032,7 +1032,7 @@ void LIRGenerator::do_NewMultiArray(NewMultiArray* x) {
args->append(rank);
args->append(varargs);
const LIR_Opr reg = result_register_for(x->type());
- __ call_runtime(Runtime1::entry_for(Runtime1::new_multi_array_id),
+ __ call_runtime(Runtime1::entry_for(C1StubId::new_multi_array_id),
LIR_OprFact::illegalOpr,
reg, args, info);
@@ -1067,7 +1067,7 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
if (x->is_incompatible_class_change_check()) {
assert(patching_info == nullptr, "can't patch this");
- stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id,
+ stub = new SimpleExceptionStub(C1StubId::throw_incompatible_class_change_error_id,
LIR_OprFact::illegalOpr, info_for_exception);
} else if (x->is_invokespecial_receiver_check()) {
assert(patching_info == nullptr, "can't patch this");
@@ -1075,7 +1075,7 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
Deoptimization::Reason_class_check,
Deoptimization::Action_none);
} else {
- stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception);
+ stub = new SimpleExceptionStub(C1StubId::throw_class_cast_exception_id, obj.result(), info_for_exception);
}
// Following registers are used by slow_subtype_check:
LIR_Opr tmp1 = FrameMap::R4_oop_opr; // super_klass
diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp
index abc439df827..ea4d76e200f 100644
--- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp
@@ -86,13 +86,13 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(Rscratch, Roop);
- lwz(Rscratch, in_bytes(Klass::access_flags_offset()), Rscratch);
- testbitdi(CCR0, R0, Rscratch, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
+ lbz(Rscratch, in_bytes(Klass::misc_flags_offset()), Rscratch);
+ testbitdi(CCR0, R0, Rscratch, exact_log2(KlassFlags::_misc_is_value_based_class));
bne(CCR0, slow_int);
}
if (LockingMode == LM_LIGHTWEIGHT) {
- lightweight_lock(Roop, Rmark, Rscratch, slow_int);
+ lightweight_lock(Rbox, Roop, Rmark, Rscratch, slow_int);
} else if (LockingMode == LM_LEGACY) {
// ... and mark it unlocked.
ori(Rmark, Rmark, markWord::unlocked_value);
@@ -114,6 +114,8 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox
/*check without membar and ldarx first*/true);
// If compare/exchange succeeded we found an unlocked object and we now have locked it
// hence we are done.
+ } else {
+ assert(false, "Unhandled LockingMode:%d", LockingMode);
}
b(done);
@@ -168,6 +170,8 @@ void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rb
MacroAssembler::cmpxchgx_hint_release_lock(),
noreg,
&slow_int);
+ } else {
+ assert(false, "Unhandled LockingMode:%d", LockingMode);
}
b(done);
bind(slow_int);
@@ -293,7 +297,7 @@ void C1_MacroAssembler::initialize_object(
if (CURRENT_ENV->dtrace_alloc_probes()) {
Unimplemented();
// assert(obj == O0, "must be");
-// call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)),
+// call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(C1StubId::dtrace_object_alloc_id)),
// relocInfo::runtime_call_type);
}
@@ -369,7 +373,7 @@ void C1_MacroAssembler::allocate_array(
if (CURRENT_ENV->dtrace_alloc_probes()) {
Unimplemented();
//assert(obj == O0, "must be");
- //call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)),
+ //call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(C1StubId::dtrace_object_alloc_id)),
// relocInfo::runtime_call_type);
}
@@ -398,20 +402,9 @@ void C1_MacroAssembler::null_check(Register r, Label* Lnull) {
if (TrapBasedNullChecks) { // SIGTRAP based
trap_null_check(r);
} else { // explicit
- //const address exception_entry = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id);
+ //const address exception_entry = Runtime1::entry_for(C1StubId::throw_null_pointer_exception_id);
assert(Lnull != nullptr, "must have Label for explicit check");
cmpdi(CCR0, r, 0);
bc_far_optimized(Assembler::bcondCRbiIs1, bi0(CCR0, Assembler::equal), *Lnull);
}
}
-
-address C1_MacroAssembler::call_c_with_frame_resize(address dest, int frame_resize) {
- if (frame_resize) { resize_frame(-frame_resize, R0); }
-#if defined(ABI_ELFv2)
- address return_pc = call_c(dest, relocInfo::runtime_call_type);
-#else
- address return_pc = call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, dest), relocInfo::runtime_call_type);
-#endif
- if (frame_resize) { resize_frame(frame_resize, R0); }
- return return_pc;
-}
diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.hpp
index c0a3dd3b83c..381cb63f832 100644
--- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.hpp
+++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.hpp
@@ -89,6 +89,5 @@
void null_check(Register r, Label *Lnull = nullptr);
- address call_c_with_frame_resize(address dest, int frame_resize);
#endif // CPU_PPC_C1_MACROASSEMBLER_PPC_HPP
diff --git a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp
index 63914c5d1cb..654626d66d8 100644
--- a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2023 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -62,7 +62,7 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result,
// ARG1 must hold thread address.
mr(R3_ARG1, R16_thread);
- address return_pc = call_c_with_frame_resize(entry_point, /*No resize, we have a C compatible frame.*/0);
+ address return_pc = call_c(entry_point);
reset_last_Java_frame();
@@ -97,12 +97,12 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result,
//load_const_optimized(R0, StubRoutines::forward_exception_entry());
//mtctr(R0);
//bctr();
- } else if (_stub_id == Runtime1::forward_exception_id) {
+ } else if (_stub_id == (int)C1StubId::forward_exception_id) {
should_not_reach_here();
} else {
// keep stub frame for next call_RT
- //load_const_optimized(R0, Runtime1::entry_for(Runtime1::forward_exception_id));
- add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(Runtime1::entry_for(Runtime1::forward_exception_id)));
+ //load_const_optimized(R0, Runtime1::entry_for(C1StubId::forward_exception_id));
+ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(Runtime1::entry_for(C1StubId::forward_exception_id)));
mtctr(R0);
bctr();
}
@@ -388,7 +388,7 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
return oop_maps;
}
-OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
+OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) {
OopMapSet* oop_maps = nullptr;
// For better readability.
@@ -397,22 +397,22 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
// Stub code & info for the different stubs.
switch (id) {
- case forward_exception_id:
+ case C1StubId::forward_exception_id:
{
oop_maps = generate_handle_exception(id, sasm);
}
break;
- case new_instance_id:
- case fast_new_instance_id:
- case fast_new_instance_init_check_id:
+ case C1StubId::new_instance_id:
+ case C1StubId::fast_new_instance_id:
+ case C1StubId::fast_new_instance_init_check_id:
{
- if (id == new_instance_id) {
+ if (id == C1StubId::new_instance_id) {
__ set_info("new_instance", dont_gc_arguments);
- } else if (id == fast_new_instance_id) {
+ } else if (id == C1StubId::fast_new_instance_id) {
__ set_info("fast new_instance", dont_gc_arguments);
} else {
- assert(id == fast_new_instance_init_check_id, "bad StubID");
+ assert(id == C1StubId::fast_new_instance_init_check_id, "bad C1StubId");
__ set_info("fast new_instance init check", dont_gc_arguments);
}
@@ -422,15 +422,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case counter_overflow_id:
+ case C1StubId::counter_overflow_id:
// Bci and method are on stack.
oop_maps = stub_call_with_stack_parms(sasm, noreg, CAST_FROM_FN_PTR(address, counter_overflow), 2);
break;
- case new_type_array_id:
- case new_object_array_id:
+ case C1StubId::new_type_array_id:
+ case C1StubId::new_object_array_id:
{
- if (id == new_type_array_id) {
+ if (id == C1StubId::new_type_array_id) {
__ set_info("new_type_array", dont_gc_arguments);
} else {
__ set_info("new_object_array", dont_gc_arguments);
@@ -439,7 +439,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
#ifdef ASSERT
// Assert object type is really an array of the proper kind.
{
- int tag = (id == new_type_array_id) ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_obj_value;
+ int tag = (id == C1StubId::new_type_array_id) ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_obj_value;
Label ok;
__ lwz(R0, in_bytes(Klass::layout_helper_offset()), R4_ARG2);
__ srawi(R0, R0, Klass::_lh_array_tag_shift);
@@ -453,7 +453,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
// We don't support eden allocation.
- if (id == new_type_array_id) {
+ if (id == C1StubId::new_type_array_id) {
oop_maps = generate_stub_call(sasm, R3_RET, CAST_FROM_FN_PTR(address, new_type_array), R4_ARG2, R5_ARG3);
} else {
oop_maps = generate_stub_call(sasm, R3_RET, CAST_FROM_FN_PTR(address, new_object_array), R4_ARG2, R5_ARG3);
@@ -461,7 +461,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case new_multi_array_id:
+ case C1StubId::new_multi_array_id:
{
// R4: klass
// R5: rank
@@ -471,7 +471,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case register_finalizer_id:
+ case C1StubId::register_finalizer_id:
{
__ set_info("register_finalizer", dont_gc_arguments);
// This code is called via rt_call. Hence, caller-save registers have been saved.
@@ -479,8 +479,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
// Load the klass and check the has finalizer flag.
__ load_klass(t, R3_ARG1);
- __ lwz(t, in_bytes(Klass::access_flags_offset()), t);
- __ testbitdi(CCR0, R0, t, exact_log2(JVM_ACC_HAS_FINALIZER));
+ __ lbz(t, in_bytes(Klass::misc_flags_offset()), t);
+ __ testbitdi(CCR0, R0, t, exact_log2(KlassFlags::_misc_has_finalizer));
// Return if has_finalizer bit == 0 (CR0.eq).
__ bclr(Assembler::bcondCRbiIs1, Assembler::bi0(CCR0, Assembler::equal), Assembler::bhintbhBCLRisReturn);
@@ -501,50 +501,50 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case throw_range_check_failed_id:
+ case C1StubId::throw_range_check_failed_id:
{
__ set_info("range_check_failed", dont_gc_arguments); // Arguments will be discarded.
oop_maps = generate_exception_throw_with_stack_parms(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), 2);
}
break;
- case throw_index_exception_id:
+ case C1StubId::throw_index_exception_id:
{
__ set_info("index_range_check_failed", dont_gc_arguments); // Arguments will be discarded.
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true);
}
break;
- case throw_div0_exception_id:
+ case C1StubId::throw_div0_exception_id:
{
__ set_info("throw_div0_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false);
}
break;
- case throw_null_pointer_exception_id:
+ case C1StubId::throw_null_pointer_exception_id:
{
__ set_info("throw_null_pointer_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false);
}
break;
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
{
__ set_info("handle_exception", dont_gc_arguments);
oop_maps = generate_handle_exception(id, sasm);
}
break;
- case handle_exception_from_callee_id:
+ case C1StubId::handle_exception_from_callee_id:
{
__ set_info("handle_exception_from_callee", dont_gc_arguments);
oop_maps = generate_handle_exception(id, sasm);
}
break;
- case unwind_exception_id:
+ case C1StubId::unwind_exception_id:
{
const Register Rexception = R3 /*LIRGenerator::exceptionOopOpr()*/,
Rexception_pc = R4 /*LIRGenerator::exceptionPcOpr()*/,
@@ -572,28 +572,28 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case throw_array_store_exception_id:
+ case C1StubId::throw_array_store_exception_id:
{
__ set_info("throw_array_store_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_array_store_exception), true);
}
break;
- case throw_class_cast_exception_id:
+ case C1StubId::throw_class_cast_exception_id:
{
__ set_info("throw_class_cast_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true);
}
break;
- case throw_incompatible_class_change_error_id:
+ case C1StubId::throw_incompatible_class_change_error_id:
{
__ set_info("throw_incompatible_class_cast_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false);
}
break;
- case slow_subtype_check_id:
+ case C1StubId::slow_subtype_check_id:
{ // Support for uint StubRoutine::partial_subtype_check( Klass sub, Klass super );
const Register sub_klass = R5,
super_klass = R4,
@@ -605,12 +605,12 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case monitorenter_nofpu_id:
- case monitorenter_id:
+ case C1StubId::monitorenter_nofpu_id:
+ case C1StubId::monitorenter_id:
{
__ set_info("monitorenter", dont_gc_arguments);
- int save_fpu_registers = (id == monitorenter_id);
+ int save_fpu_registers = (id == C1StubId::monitorenter_id);
// Make a frame and preserve the caller's caller-save registers.
OopMap* oop_map = save_live_registers(sasm, save_fpu_registers);
@@ -624,15 +624,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case monitorexit_nofpu_id:
- case monitorexit_id:
+ case C1StubId::monitorexit_nofpu_id:
+ case C1StubId::monitorexit_id:
{
// note: Really a leaf routine but must setup last java sp
// => use call_RT for now (speed can be improved by
// doing last java sp setup manually).
__ set_info("monitorexit", dont_gc_arguments);
- int save_fpu_registers = (id == monitorexit_id);
+ int save_fpu_registers = (id == C1StubId::monitorexit_id);
// Make a frame and preserve the caller's caller-save registers.
OopMap* oop_map = save_live_registers(sasm, save_fpu_registers);
@@ -646,7 +646,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case deoptimize_id:
+ case C1StubId::deoptimize_id:
{
__ set_info("deoptimize", dont_gc_arguments);
__ std(R0, -8, R1_SP); // Pass trap_request on stack.
@@ -662,35 +662,35 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case access_field_patching_id:
+ case C1StubId::access_field_patching_id:
{
__ set_info("access_field_patching", dont_gc_arguments);
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching));
}
break;
- case load_klass_patching_id:
+ case C1StubId::load_klass_patching_id:
{
__ set_info("load_klass_patching", dont_gc_arguments);
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching));
}
break;
- case load_mirror_patching_id:
+ case C1StubId::load_mirror_patching_id:
{
__ set_info("load_mirror_patching", dont_gc_arguments);
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_mirror_patching));
}
break;
- case load_appendix_patching_id:
+ case C1StubId::load_appendix_patching_id:
{
__ set_info("load_appendix_patching", dont_gc_arguments);
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching));
}
break;
- case dtrace_object_alloc_id:
+ case C1StubId::dtrace_object_alloc_id:
{ // O0: object
__ unimplemented("stub dtrace_object_alloc_id");
__ set_info("dtrace_object_alloc", dont_gc_arguments);
@@ -710,7 +710,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case predicate_failed_trap_id:
+ case C1StubId::predicate_failed_trap_id:
{
__ set_info("predicate_failed_trap", dont_gc_arguments);
OopMap* oop_map = save_live_registers(sasm);
@@ -754,7 +754,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
-OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) {
+OopMapSet* Runtime1::generate_handle_exception(C1StubId id, StubAssembler* sasm) {
__ block_comment("generate_handle_exception");
// Save registers, if required.
@@ -764,7 +764,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) {
Rexception_pc = R4 /*LIRGenerator::exceptionPcOpr()*/;
switch (id) {
- case forward_exception_id:
+ case C1StubId::forward_exception_id:
// We're handling an exception in the context of a compiled frame.
// The registers have been saved in the standard places. Perform
// an exception lookup in the caller and dispatch to the handler
@@ -780,12 +780,12 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) {
__ ld(Rexception_pc, _abi0(lr), Rexception_pc);
__ std(R0, in_bytes(JavaThread::pending_exception_offset()), R16_thread);
break;
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
// At this point all registers MAY be live.
- oop_map = save_live_registers(sasm, id != handle_exception_nofpu_id, Rexception_pc);
+ oop_map = save_live_registers(sasm, id != C1StubId::handle_exception_nofpu_id, Rexception_pc);
break;
- case handle_exception_from_callee_id:
+ case C1StubId::handle_exception_from_callee_id:
// At this point all registers except exception oop and exception pc are dead.
oop_map = new OopMap(frame_size_in_bytes / sizeof(jint), 0);
sasm->set_frame_size(frame_size_in_bytes / BytesPerWord);
@@ -824,13 +824,13 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) {
// Restore the registers that were saved at the beginning, remove
// the frame and jump to the exception handler.
switch (id) {
- case forward_exception_id:
- case handle_exception_nofpu_id:
- case handle_exception_id:
- restore_live_registers(sasm, noreg, noreg, id != handle_exception_nofpu_id);
+ case C1StubId::forward_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
+ restore_live_registers(sasm, noreg, noreg, id != C1StubId::handle_exception_nofpu_id);
__ bctr();
break;
- case handle_exception_from_callee_id: {
+ case C1StubId::handle_exception_from_callee_id: {
__ pop_frame();
__ ld(Rexception_pc, _abi0(lr), R1_SP);
__ mtlr(Rexception_pc);
diff --git a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp
index cc69c0abe36..1147c3b42b2 100644
--- a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp
@@ -39,12 +39,12 @@
void C2_MacroAssembler::fast_lock_lightweight(ConditionRegister flag, Register obj, Register box,
Register tmp1, Register tmp2, Register tmp3) {
- compiler_fast_lock_lightweight_object(flag, obj, tmp1, tmp2, tmp3);
+ compiler_fast_lock_lightweight_object(flag, obj, box, tmp1, tmp2, tmp3);
}
void C2_MacroAssembler::fast_unlock_lightweight(ConditionRegister flag, Register obj, Register box,
Register tmp1, Register tmp2, Register tmp3) {
- compiler_fast_unlock_lightweight_object(flag, obj, tmp1, tmp2, tmp3);
+ compiler_fast_unlock_lightweight_object(flag, obj, box, tmp1, tmp2, tmp3);
}
// Intrinsics for CompactStrings
diff --git a/src/hotspot/cpu/ppc/frame_ppc.cpp b/src/hotspot/cpu/ppc/frame_ppc.cpp
index 4c1ffeb0d76..eb16af5e9db 100644
--- a/src/hotspot/cpu/ppc/frame_ppc.cpp
+++ b/src/hotspot/cpu/ppc/frame_ppc.cpp
@@ -117,9 +117,9 @@ bool frame::safe_for_sender(JavaThread *thread) {
return false;
}
- common_abi* sender_abi = (common_abi*) fp;
+ volatile common_abi* sender_abi = (common_abi*) fp; // May get updated concurrently by deoptimization!
intptr_t* sender_sp = (intptr_t*) fp;
- address sender_pc = (address) sender_abi->lr;;
+ address sender_pc = (address) sender_abi->lr;
if (Continuation::is_return_barrier_entry(sender_pc)) {
// If our sender_pc is the return barrier, then our "real" sender is the continuation entry
@@ -134,9 +134,18 @@ bool frame::safe_for_sender(JavaThread *thread) {
return false;
}
+ intptr_t* unextended_sender_sp = is_interpreted_frame() ? interpreter_frame_sender_sp() : sender_sp;
+
+ // If the sender is a deoptimized nmethod we need to check if the original pc is valid.
+ nmethod* sender_nm = sender_blob->as_nmethod_or_null();
+ if (sender_nm != nullptr && sender_nm->is_deopt_pc(sender_pc)) {
+ address orig_pc = *(address*)((address)unextended_sender_sp + sender_nm->orig_pc_offset());
+ if (!sender_nm->insts_contains_inclusive(orig_pc)) return false;
+ }
+
// It should be safe to construct the sender though it might not be valid.
- frame sender(sender_sp, sender_pc, nullptr /* unextended_sp */, nullptr /* fp */, sender_blob);
+ frame sender(sender_sp, sender_pc, unextended_sender_sp, nullptr /* fp */, sender_blob);
// Do we have a valid fp?
address sender_fp = (address) sender.fp();
diff --git a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp
index 7d230d301c2..39693bdf925 100644
--- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp
@@ -41,10 +41,20 @@
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "gc/g1/c1/g1BarrierSetC1.hpp"
-#endif
+#endif // COMPILER1
+#ifdef COMPILER2
+#include "gc/g1/c2/g1BarrierSetC2.hpp"
+#endif // COMPILER2
#define __ masm->
+static void generate_marking_inactive_test(MacroAssembler* masm) {
+ int active_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
+ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ lbz(R0, active_offset, R16_thread); // tmp1 := *(mark queue active address)
+ __ cmpwi(CCR0, R0, 0);
+}
+
void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register from, Register to, Register count,
Register preserve1, Register preserve2) {
@@ -58,13 +68,7 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm
Label filtered;
// Is marking active?
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- __ lwz(R0, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread);
- } else {
- guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- __ lbz(R0, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread);
- }
- __ cmpdi(CCR0, R0, 0);
+ generate_marking_inactive_test(masm);
__ beq(CCR0, filtered);
__ save_LR(R0);
@@ -109,35 +113,48 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas
__ restore_LR(R0);
}
+static void generate_queue_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime,
+ const Register value, const Register temp) {
+ assert_different_registers(value, temp);
+ // Can we store a value in the given thread's buffer?
+ // (The index field is typed as size_t.)
+ __ ld(temp, in_bytes(index_offset), R16_thread); // temp := *(index address)
+ __ cmpdi(CCR0, temp, 0); // jump to runtime if index == 0 (full buffer)
+ __ beq(CCR0, runtime);
+ // The buffer is not full, store value into it.
+ __ ld(R0, in_bytes(buffer_offset), R16_thread); // R0 := buffer address
+ __ addi(temp, temp, -wordSize); // temp := next index
+ __ std(temp, in_bytes(index_offset), R16_thread); // *(index address) := next index
+ __ stdx(value, temp, R0); // *(buffer address + next index) := value
+}
+
void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, DecoratorSet decorators,
Register obj, RegisterOrConstant ind_or_offs, Register pre_val,
Register tmp1, Register tmp2,
MacroAssembler::PreservationLevel preservation_level) {
+ assert_different_registers(pre_val, tmp1, tmp2);
+
bool not_null = (decorators & IS_NOT_NULL) != 0,
preloaded = obj == noreg;
Register nv_save = noreg;
- if (preloaded) {
+ // Determine necessary runtime invocation preservation measures
+ const bool needs_frame = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR;
+ const bool preserve_gp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_REGS;
+ const bool preserve_fp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS;
+ int nbytes_save = 0;
+
+ if (pre_val->is_volatile() && preloaded && !preserve_gp_registers) {
// We are not loading the previous value so make
// sure that we don't trash the value in pre_val
// with the code below.
- assert_different_registers(pre_val, tmp1, tmp2);
- if (pre_val->is_volatile()) {
- nv_save = !tmp1->is_volatile() ? tmp1 : tmp2;
- assert(!nv_save->is_volatile(), "need one nv temp register if pre_val lives in volatile register");
- }
+ nv_save = !tmp1->is_volatile() ? tmp1 : tmp2;
+ assert(!nv_save->is_volatile(), "need one nv temp register if pre_val lives in volatile register");
}
Label runtime, filtered;
- // Is marking active?
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- __ lwz(tmp1, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread);
- } else {
- guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- __ lbz(tmp1, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread);
- }
- __ cmpdi(CCR0, tmp1, 0);
+ generate_marking_inactive_test(masm);
__ beq(CCR0, filtered);
// Do we need to load the previous value?
@@ -175,28 +192,12 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator
// Can we store original value in the thread's buffer?
// Is index == 0?
// (The index field is typed as size_t.)
- const Register Rbuffer = tmp1, Rindex = tmp2;
-
- __ ld(Rindex, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()), R16_thread);
- __ cmpdi(CCR0, Rindex, 0);
- __ beq(CCR0, runtime); // If index == 0, goto runtime.
- __ ld(Rbuffer, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()), R16_thread);
-
- __ addi(Rindex, Rindex, -wordSize); // Decrement index.
- __ std(Rindex, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()), R16_thread);
-
- // Record the previous value.
- __ stdx(pre_val, Rbuffer, Rindex);
+ generate_queue_insertion(masm, G1ThreadLocalData::satb_mark_queue_index_offset(), G1ThreadLocalData::satb_mark_queue_buffer_offset(),
+ runtime, pre_val, tmp1);
__ b(filtered);
__ bind(runtime);
- // Determine necessary runtime invocation preservation measures
- const bool needs_frame = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR;
- const bool preserve_gp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_REGS;
- const bool preserve_fp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS;
- int nbytes_save = 0;
-
// May need to preserve LR. Also needed if current frame is not compatible with C calling convention.
if (needs_frame) {
if (preserve_gp_registers) {
@@ -210,11 +211,11 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator
__ push_frame_reg_args(nbytes_save, tmp2);
}
- if (pre_val->is_volatile() && preloaded && !preserve_gp_registers) {
+ if (nv_save != noreg) {
__ mr(nv_save, pre_val); // Save pre_val across C call if it was preloaded.
}
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, R16_thread);
- if (pre_val->is_volatile() && preloaded && !preserve_gp_registers) {
+ if (nv_save != noreg) {
__ mr(pre_val, nv_save); // restore
}
@@ -230,6 +231,26 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator
__ bind(filtered);
}
+static void generate_region_crossing_test(MacroAssembler* masm, const Register store_addr, const Register new_val) {
+ __ xorr(R0, store_addr, new_val); // tmp1 := store address ^ new value
+ __ srdi_(R0, R0, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
+}
+
+static Address generate_card_young_test(MacroAssembler* masm, const Register store_addr, const Register tmp1, const Register tmp2) {
+ CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set());
+ __ load_const_optimized(tmp1, (address)(ct->card_table()->byte_map_base()), tmp2);
+ __ srdi(tmp2, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base
+ __ lbzx(R0, tmp1, tmp2); // tmp1 := card address
+ __ cmpwi(CCR0, R0, (int)G1CardTable::g1_young_card_val());
+ return Address(tmp1, tmp2); // return card address
+}
+
+static void generate_card_dirty_test(MacroAssembler* masm, Address card_addr) {
+ __ membar(Assembler::StoreLoad); // Must reload after StoreLoad membar due to concurrent refinement
+ __ lbzx(R0, card_addr.base(), card_addr.index()); // tmp2 := card
+ __ cmpwi(CCR0, R0, (int)G1CardTable::dirty_card_val()); // tmp2 := card == dirty_card_val?
+}
+
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, DecoratorSet decorators,
Register store_addr, Register new_val,
Register tmp1, Register tmp2, Register tmp3,
@@ -241,9 +262,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato
CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set());
- // Does store cross heap regions?
- __ xorr(tmp1, store_addr, new_val);
- __ srdi_(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes);
+ generate_region_crossing_test(masm, store_addr, new_val);
__ beq(CCR0, filtered);
// Crosses regions, storing null?
@@ -257,43 +276,22 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato
__ beq(CCR0, filtered);
}
- // Storing region crossing non-null, is card already dirty?
- const Register Rcard_addr = tmp1;
- Register Rbase = tmp2;
- __ load_const_optimized(Rbase, (address)(ct->card_table()->byte_map_base()), /*temp*/ tmp3);
-
- __ srdi(Rcard_addr, store_addr, CardTable::card_shift());
-
- // Get the address of the card.
- __ lbzx(/*card value*/ tmp3, Rbase, Rcard_addr);
- __ cmpwi(CCR0, tmp3, (int)G1CardTable::g1_young_card_val());
+ Address card_addr = generate_card_young_test(masm, store_addr, tmp1, tmp2);
__ beq(CCR0, filtered);
- __ membar(Assembler::StoreLoad);
- __ lbzx(/*card value*/ tmp3, Rbase, Rcard_addr); // Reload after membar.
- __ cmpwi(CCR0, tmp3 /* card value */, (int)G1CardTable::dirty_card_val());
+ generate_card_dirty_test(masm, card_addr);
__ beq(CCR0, filtered);
- // Storing a region crossing, non-null oop, card is clean.
- // Dirty card and log.
- __ li(tmp3, (int)G1CardTable::dirty_card_val());
- //release(); // G1: oops are allowed to get visible after dirty marking.
- __ stbx(tmp3, Rbase, Rcard_addr);
-
- __ add(Rcard_addr, Rbase, Rcard_addr); // This is the address which needs to get enqueued.
- Rbase = noreg; // end of lifetime
+ __ li(R0, (int)G1CardTable::dirty_card_val());
+ __ stbx(R0, card_addr.base(), card_addr.index()); // *(card address) := dirty_card_val
- const Register Rqueue_index = tmp2,
- Rqueue_buf = tmp3;
- __ ld(Rqueue_index, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()), R16_thread);
- __ cmpdi(CCR0, Rqueue_index, 0);
- __ beq(CCR0, runtime); // index == 0 then jump to runtime
- __ ld(Rqueue_buf, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()), R16_thread);
+ Register Rcard_addr = tmp3;
+ __ add(Rcard_addr, card_addr.base(), card_addr.index()); // This is the address which needs to get enqueued.
- __ addi(Rqueue_index, Rqueue_index, -wordSize); // decrement index
- __ std(Rqueue_index, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()), R16_thread);
-
- __ stdx(Rcard_addr, Rqueue_buf, Rqueue_index); // store card
+ generate_queue_insertion(masm,
+ G1ThreadLocalData::dirty_card_queue_index_offset(),
+ G1ThreadLocalData::dirty_card_queue_buffer_offset(),
+ runtime, Rcard_addr, tmp1);
__ b(filtered);
__ bind(runtime);
@@ -392,6 +390,142 @@ void G1BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value
__ bind(done);
}
+#ifdef COMPILER2
+
+static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) {
+ SaveLiveRegisters save_registers(masm, stub);
+ __ call_VM_leaf(runtime_path, arg, R16_thread);
+}
+
+void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register tmp1,
+ Register tmp2,
+ G1PreBarrierStubC2* stub) {
+ assert_different_registers(obj, tmp1, tmp2, R0);
+ assert_different_registers(pre_val, tmp1, R0);
+ assert(!UseCompressedOops || tmp2 != noreg, "tmp2 needed with CompressedOops");
+
+ stub->initialize_registers(obj, pre_val, R16_thread, tmp1, tmp2);
+
+ generate_marking_inactive_test(masm);
+ __ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CCR0, Assembler::equal), *stub->entry());
+
+ __ bind(*stub->continuation());
+}
+
+void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
+ G1PreBarrierStubC2* stub) const {
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ Label runtime;
+ Register obj = stub->obj();
+ Register pre_val = stub->pre_val();
+ Register tmp1 = stub->tmp1();
+
+ __ bind(*stub->entry());
+
+ if (obj != noreg) {
+ // Note: C2 currently doesn't use implicit null checks with barriers.
+ // Otherwise, obj could be null and the following instruction would raise a SIGSEGV.
+ if (UseCompressedOops) {
+ __ lwz(pre_val, 0, obj);
+ } else {
+ __ ld(pre_val, 0, obj);
+ }
+ }
+ __ cmpdi(CCR0, pre_val, 0);
+ __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), *stub->continuation());
+
+ Register pre_val_decoded = pre_val;
+ if (UseCompressedOops) {
+ pre_val_decoded = __ decode_heap_oop_not_null(stub->tmp2(), pre_val);
+ }
+
+ generate_queue_insertion(masm,
+ G1ThreadLocalData::satb_mark_queue_index_offset(),
+ G1ThreadLocalData::satb_mark_queue_buffer_offset(),
+ runtime, pre_val_decoded, tmp1);
+ __ b(*stub->continuation());
+
+ __ bind(runtime);
+ generate_c2_barrier_runtime_call(masm, stub, pre_val_decoded, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry));
+ __ b(*stub->continuation());
+}
+
+void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register tmp1,
+ Register tmp2,
+ G1PostBarrierStubC2* stub,
+ bool decode_new_val) {
+ assert_different_registers(store_addr, new_val, tmp1, R0);
+ assert_different_registers(store_addr, tmp1, tmp2, R0);
+
+ stub->initialize_registers(R16_thread, tmp1, tmp2);
+
+ bool null_check_required = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0;
+ Register new_val_decoded = new_val;
+
+ if (decode_new_val) {
+ assert(UseCompressedOops, "or should not be here");
+ if (null_check_required && CompressedOops::base() != nullptr) {
+ // We prefer doing the null check after the region crossing check.
+ // Only compressed oop modes with base != null require a null check here.
+ __ cmpwi(CCR0, new_val, 0);
+ __ beq(CCR0, *stub->continuation());
+ null_check_required = false;
+ }
+ new_val_decoded = __ decode_heap_oop_not_null(tmp2, new_val);
+ }
+
+ generate_region_crossing_test(masm, store_addr, new_val_decoded);
+ __ beq(CCR0, *stub->continuation());
+
+ // crosses regions, storing null?
+ if (null_check_required) {
+ __ cmpdi(CCR0, new_val_decoded, 0);
+ __ beq(CCR0, *stub->continuation());
+ }
+
+ Address card_addr = generate_card_young_test(masm, store_addr, tmp1, tmp2);
+ assert(card_addr.base() == tmp1 && card_addr.index() == tmp2, "needed by post barrier stub");
+ __ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CCR0, Assembler::equal), *stub->entry());
+
+ __ bind(*stub->continuation());
+}
+
+void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
+ G1PostBarrierStubC2* stub) const {
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ Label runtime;
+ Address card_addr(stub->tmp1(), stub->tmp2()); // See above.
+
+ __ bind(*stub->entry());
+
+ generate_card_dirty_test(masm, card_addr);
+ __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), *stub->continuation());
+
+ __ li(R0, (int)G1CardTable::dirty_card_val());
+ __ stbx(R0, card_addr.base(), card_addr.index()); // *(card address) := dirty_card_val
+
+ Register Rcard_addr = stub->tmp1();
+ __ add(Rcard_addr, card_addr.base(), card_addr.index()); // This is the address which needs to get enqueued.
+
+ generate_queue_insertion(masm,
+ G1ThreadLocalData::dirty_card_queue_index_offset(),
+ G1ThreadLocalData::dirty_card_queue_buffer_offset(),
+ runtime, Rcard_addr, stub->tmp2());
+ __ b(*stub->continuation());
+
+ __ bind(runtime);
+ generate_c2_barrier_runtime_call(masm, stub, Rcard_addr, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry));
+ __ b(*stub->continuation());
+}
+
+#endif // COMPILER2
+
#ifdef COMPILER1
#undef __
@@ -470,13 +604,7 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
__ std(tmp2, -24, R1_SP);
// Is marking still active?
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- __ lwz(tmp, satb_q_active_byte_offset, R16_thread);
- } else {
- assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- __ lbz(tmp, satb_q_active_byte_offset, R16_thread);
- }
- __ cmpdi(CCR0, tmp, 0);
+ generate_marking_inactive_test(sasm);
__ beq(CCR0, marking_not_active);
__ bind(restart);
diff --git a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp
index d9a252ff6ea..1c9fe8a5d10 100644
--- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp
+++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp
@@ -30,10 +30,16 @@
#include "gc/shared/modRefBarrierSetAssembler.hpp"
#include "utilities/macros.hpp"
+#ifdef COMPILER2
+#include "gc/g1/c2/g1BarrierSetC2.hpp"
+#endif
+
class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
class G1PostBarrierStub;
+class G1PreBarrierStubC2;
+class G1PostBarrierStubC2;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@@ -59,6 +65,25 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
MacroAssembler::PreservationLevel preservation_level);
public:
+#ifdef COMPILER2
+ void g1_write_barrier_pre_c2(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register tmp1,
+ Register tmp2,
+ G1PreBarrierStubC2* c2_stub);
+ void generate_c2_pre_barrier_stub(MacroAssembler* masm,
+ G1PreBarrierStubC2* stub) const;
+ void g1_write_barrier_post_c2(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register tmp1,
+ Register tmp2,
+ G1PostBarrierStubC2* c2_stub,
+ bool decode_new_val);
+ void generate_c2_post_barrier_stub(MacroAssembler* masm,
+ G1PostBarrierStubC2* stub) const;
+#endif
#ifdef COMPILER1
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
diff --git a/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad b/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad
new file mode 100644
index 00000000000..f4163242cad
--- /dev/null
+++ b/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad
@@ -0,0 +1,684 @@
+//
+// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2024 SAP SE. All rights reserved.
+// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+//
+// This code is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 2 only, as
+// published by the Free Software Foundation.
+//
+// This code is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// version 2 for more details (a copy is included in the LICENSE file that
+// accompanied this code).
+//
+// You should have received a copy of the GNU General Public License version
+// 2 along with this work; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+// or visit www.oracle.com if you need additional information or have any
+// questions.
+//
+
+source_hpp %{
+
+#include "gc/g1/c2/g1BarrierSetC2.hpp"
+#include "gc/shared/gc_globals.hpp"
+
+%}
+
+source %{
+
+#include "gc/g1/g1BarrierSetAssembler_ppc.hpp"
+#include "gc/g1/g1BarrierSetRuntime.hpp"
+
+static void pre_write_barrier(MacroAssembler* masm,
+ const MachNode* node,
+ Register obj,
+ Register pre_val,
+ Register tmp1,
+ Register tmp2 = noreg, // only needed with CompressedOops when pre_val needs to be preserved
+ RegSet preserve = RegSet(),
+ RegSet no_preserve = RegSet()) {
+ if (!G1PreBarrierStubC2::needs_barrier(node)) {
+ return;
+ }
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
+ G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node);
+ for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) {
+ stub->preserve(*reg);
+ }
+ for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) {
+ stub->dont_preserve(*reg);
+ }
+ g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, tmp1, (tmp2 != noreg) ? tmp2 : pre_val, stub);
+}
+
+static void post_write_barrier(MacroAssembler* masm,
+ const MachNode* node,
+ Register store_addr,
+ Register new_val,
+ Register tmp1,
+ Register tmp2,
+ bool decode_new_val = false) {
+ if (!G1PostBarrierStubC2::needs_barrier(node)) {
+ return;
+ }
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
+ G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
+ g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, tmp1, tmp2, stub, decode_new_val);
+}
+
+%}
+
+instruct g1StoreP(indirect mem, iRegPsrc src, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreP mem src));
+ effect(TEMP tmp1, TEMP tmp2, KILL cr0);
+ ins_cost(2 * MEMORY_REF_COST);
+ format %{ "std $mem, $src\t# ptr" %}
+ ins_encode %{
+ pre_write_barrier(masm, this,
+ $mem$$Register,
+ $tmp1$$Register,
+ $tmp2$$Register,
+ noreg,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ __ std($src$$Register, 0, $mem$$Register);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $src$$Register /* new_val */,
+ $tmp1$$Register,
+ $tmp2$$Register);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct g1StoreN(indirect mem, iRegNsrc src, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreN mem src));
+ effect(TEMP tmp1, TEMP tmp2, KILL cr0);
+ ins_cost(2 * MEMORY_REF_COST);
+ format %{ "stw $mem, $src\t# ptr" %}
+ ins_encode %{
+ pre_write_barrier(masm, this,
+ $mem$$Register,
+ $tmp1$$Register,
+ $tmp2$$Register,
+ noreg,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ __ stw($src$$Register, 0, $mem$$Register);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $src$$Register /* new_val */,
+ $tmp1$$Register,
+ $tmp2$$Register,
+ true /* decode_new_val */);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct g1EncodePAndStoreN(indirect mem, iRegPsrc src, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreN mem (EncodeP src)));
+ effect(TEMP tmp1, TEMP tmp2, KILL cr0);
+ ins_cost(2 * MEMORY_REF_COST);
+ format %{ "encode_heap_oop $src\n\t"
+ "stw $mem, $src\t# ptr" %}
+ ins_encode %{
+ pre_write_barrier(masm, this,
+ $mem$$Register,
+ $tmp1$$Register,
+ $tmp2$$Register,
+ noreg,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ Register encoded_oop = noreg;
+ if ((barrier_data() & G1C2BarrierPostNotNull) == 0) {
+ encoded_oop = __ encode_heap_oop($tmp2$$Register, $src$$Register);
+ } else {
+ encoded_oop = __ encode_heap_oop_not_null($tmp2$$Register, $src$$Register);
+ }
+ __ stw(encoded_oop, 0, $mem$$Register);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $src$$Register /* new_val */,
+ $tmp1$$Register,
+ $tmp2$$Register);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct g1CompareAndExchangeP(iRegPdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 &&
+ (((CompareAndExchangeNode*)n)->order() != MemNode::acquire && ((CompareAndExchangeNode*)n)->order() != MemNode::seqcst));
+ match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
+ effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0);
+ format %{ "cmpxchgd $newval, $mem" %}
+ ins_encode %{
+ Label no_update;
+ __ cmpxchgd(CCR0, $res$$Register, $oldval$$Register, $newval$$Register, $mem$$Register,
+ MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
+ noreg, &no_update, true);
+ // Pass oldval to SATB which is the only value which can get overwritten.
+ // Can be done after cmpxchg because there's no safepoint here.
+ pre_write_barrier(masm, this,
+ noreg,
+ $oldval$$Register,
+ $tmp1$$Register,
+ $tmp2$$Register,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $newval$$Register,
+ $tmp1$$Register,
+ $tmp2$$Register);
+ __ bind(no_update);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct g1CompareAndExchangeP_acq(iRegPdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 &&
+ (((CompareAndExchangeNode*)n)->order() == MemNode::acquire || ((CompareAndExchangeNode*)n)->order() == MemNode::seqcst));
+ match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
+ effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0);
+ format %{ "cmpxchgd acq $newval, $mem" %}
+ ins_encode %{
+ Label no_update;
+ __ cmpxchgd(CCR0, $res$$Register, $oldval$$Register, $newval$$Register, $mem$$Register,
+ MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
+ noreg, &no_update, true);
+ // Pass oldval to SATB which is the only value which can get overwritten.
+ // Can be done after cmpxchg because there's no safepoint here.
+ pre_write_barrier(masm, this,
+ noreg,
+ $oldval$$Register,
+ $tmp1$$Register,
+ $tmp2$$Register,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $newval$$Register,
+ $tmp1$$Register,
+ $tmp2$$Register);
+ __ bind(no_update);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ isync();
+ } else {
+ // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that.
+ __ sync();
+ }
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct g1CompareAndExchangeN(iRegNdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 &&
+ (((CompareAndExchangeNode*)n)->order() != MemNode::acquire && ((CompareAndExchangeNode*)n)->order() != MemNode::seqcst));
+ match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
+ effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0);
+ format %{ "cmpxchgw $newval, $mem" %}
+ ins_encode %{
+ Label no_update;
+ __ cmpxchgw(CCR0, $res$$Register, $oldval$$Register, $newval$$Register, $mem$$Register,
+ MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
+ noreg, &no_update, true);
+ // Pass oldval to SATB which is the only value which can get overwritten.
+ // Can be done after cmpxchg because there's no safepoint here.
+ pre_write_barrier(masm, this,
+ noreg,
+ $oldval$$Register,
+ $tmp1$$Register,
+ $tmp2$$Register,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $newval$$Register,
+ $tmp1$$Register,
+ $tmp2$$Register,
+ true /* decode_new_val */);
+ __ bind(no_update);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct g1CompareAndExchangeN_acq(iRegNdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 &&
+ (((CompareAndExchangeNode*)n)->order() == MemNode::acquire || ((CompareAndExchangeNode*)n)->order() == MemNode::seqcst));
+ match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
+ effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0);
+ format %{ "cmpxchgw acq $newval, $mem" %}
+ ins_encode %{
+ Label no_update;
+ __ cmpxchgw(CCR0, $res$$Register, $oldval$$Register, $newval$$Register, $mem$$Register,
+ MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
+ noreg, &no_update, true);
+ // Pass oldval to SATB which is the only value which can get overwritten.
+ // Can be done after cmpxchg because there's no safepoint here.
+ pre_write_barrier(masm, this,
+ noreg,
+ $oldval$$Register,
+ $tmp1$$Register,
+ $tmp2$$Register,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $newval$$Register,
+ $tmp1$$Register,
+ $tmp2$$Register,
+ true /* decode_new_val */);
+ __ bind(no_update);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ isync();
+ } else {
+ // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that.
+ __ sync();
+ }
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct g1CompareAndSwapP(iRegIdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 &&
+ (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst));
+ match(Set res (CompareAndSwapP mem (Binary oldval newval)));
+ effect(TEMP_DEF res, TEMP tmp, KILL cr0);
+ format %{ "CMPXCHGD $res, $mem, $oldval, $newval; as bool; ptr" %}
+ ins_encode %{
+ Label no_update;
+ __ li($res$$Register, 0);
+ __ cmpxchgd(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register,
+ MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
+ noreg, &no_update, true);
+ // Pass oldval to SATB which is the only value which can get overwritten.
+ // Can be done after cmpxchg because there's no safepoint here.
+ pre_write_barrier(masm, this,
+ noreg,
+ $oldval$$Register /* pre_val */,
+ $tmp$$Register,
+ $res$$Register /* temp */,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $newval$$Register,
+ $tmp$$Register,
+ $res$$Register /* temp */);
+ __ li($res$$Register, 1);
+ __ bind(no_update);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct g1CompareAndSwapP_acq(iRegIdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 &&
+ (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst));
+ match(Set res (CompareAndSwapP mem (Binary oldval newval)));
+ effect(TEMP_DEF res, TEMP tmp, KILL cr0);
+ format %{ "CMPXCHGD acq $res, $mem, $oldval, $newval; as bool; ptr" %}
+ ins_encode %{
+ Label no_update;
+ __ li($res$$Register, 0);
+ __ cmpxchgd(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register,
+ MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
+ noreg, &no_update, true);
+ // Pass oldval to SATB which is the only value which can get overwritten.
+ // Can be done after cmpxchg because there's no safepoint here.
+ pre_write_barrier(masm, this,
+ noreg,
+ $oldval$$Register /* pre_val */,
+ $tmp$$Register,
+ $res$$Register /* temp */,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $newval$$Register,
+ $tmp$$Register,
+ $res$$Register /* temp */);
+ __ li($res$$Register, 1);
+ __ bind(no_update);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ isync();
+ } else {
+ // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that.
+ __ sync();
+ }
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct g1CompareAndSwapN(iRegIdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 &&
+ (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst));
+ match(Set res (CompareAndSwapN mem (Binary oldval newval)));
+ effect(TEMP_DEF res, TEMP tmp, KILL cr0);
+ format %{ "CMPXCHGW $res, $mem, $oldval, $newval; as bool; ptr" %}
+ ins_encode %{
+ Label no_update;
+ __ li($res$$Register, 0);
+ __ cmpxchgw(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register,
+ MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
+ noreg, &no_update, true);
+ // Pass oldval to SATB which is the only value which can get overwritten.
+ // Can be done after cmpxchg because there's no safepoint here.
+ pre_write_barrier(masm, this,
+ noreg,
+ $oldval$$Register /* pre_val */,
+ $tmp$$Register,
+ $res$$Register /* temp */,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $newval$$Register,
+ $tmp$$Register,
+ $res$$Register /* temp */,
+ true /* decode_new_val */);
+ __ li($res$$Register, 1);
+ __ bind(no_update);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct g1CompareAndSwapN_acq(iRegIdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 &&
+ (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst));
+ match(Set res (CompareAndSwapN mem (Binary oldval newval)));
+ effect(TEMP_DEF res, TEMP tmp, KILL cr0);
+ format %{ "CMPXCHGW acq $res, $mem, $oldval, $newval; as bool; ptr" %}
+ ins_encode %{
+ Label no_update;
+ __ li($res$$Register, 0);
+ __ cmpxchgw(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register,
+ MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
+ noreg, &no_update, true);
+ // Pass oldval to SATB which is the only value which can get overwritten.
+ // Can be done after cmpxchg because there's no safepoint here.
+ pre_write_barrier(masm, this,
+ noreg,
+ $oldval$$Register /* pre_val */,
+ $tmp$$Register,
+ $res$$Register /* temp */,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $newval$$Register,
+ $tmp$$Register,
+ $res$$Register /* temp */,
+ true /* decode_new_val */);
+ __ li($res$$Register, 1);
+ __ bind(no_update);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ isync();
+ } else {
+ // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that.
+ __ sync();
+ }
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct weakG1CompareAndSwapP(iRegIdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 &&
+ (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst));
+ match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
+ effect(TEMP_DEF res, TEMP tmp, KILL cr0);
+ format %{ "weak CMPXCHGD $res, $mem, $oldval, $newval; as bool; ptr" %}
+ ins_encode %{
+ Label no_update;
+ __ li($res$$Register, 0);
+ __ cmpxchgd(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register,
+ MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
+ noreg, &no_update, true, true);
+ // Pass oldval to SATB which is the only value which can get overwritten.
+ // Can be done after cmpxchg because there's no safepoint here.
+ pre_write_barrier(masm, this,
+ noreg,
+ $oldval$$Register /* pre_val */,
+ $tmp$$Register,
+ $res$$Register /* temp */,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $newval$$Register,
+ $tmp$$Register,
+ $res$$Register /* temp */);
+ __ li($res$$Register, 1);
+ __ bind(no_update);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct weakG1CompareAndSwapP_acq(iRegIdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 &&
+ (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst));
+ match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
+ effect(TEMP_DEF res, TEMP tmp, KILL cr0);
+ format %{ "weak CMPXCHGD acq $res, $mem, $oldval, $newval; as bool; ptr" %}
+ ins_encode %{
+ Label no_update;
+ __ li($res$$Register, 0);
+ __ cmpxchgd(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register,
+ MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
+ noreg, &no_update, true, true);
+ // Pass oldval to SATB which is the only value which can get overwritten.
+ // Can be done after cmpxchg because there's no safepoint here.
+ pre_write_barrier(masm, this,
+ noreg,
+ $oldval$$Register /* pre_val */,
+ $tmp$$Register,
+ $res$$Register /* temp */,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $newval$$Register,
+ $tmp$$Register,
+ $res$$Register /* temp */);
+ __ li($res$$Register, 1);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ isync();
+ } else {
+ // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that.
+ __ sync();
+ }
+ __ bind(no_update); // weak version requires no memory barrier on failure
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct weakG1CompareAndSwapN(iRegIdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 &&
+ (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst));
+ match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
+ effect(TEMP_DEF res, TEMP tmp, KILL cr0);
+ format %{ "weak CMPXCHGW $res, $mem, $oldval, $newval; as bool; ptr" %}
+ ins_encode %{
+ Label no_update;
+ __ li($res$$Register, 0);
+ __ cmpxchgw(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register,
+ MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
+ noreg, &no_update, true, true);
+ // Pass oldval to SATB which is the only value which can get overwritten.
+ // Can be done after cmpxchg because there's no safepoint here.
+ pre_write_barrier(masm, this,
+ noreg,
+ $oldval$$Register /* pre_val */,
+ $tmp$$Register,
+ $res$$Register /* temp */,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $newval$$Register,
+ $tmp$$Register,
+ $res$$Register /* temp */,
+ true /* decode_new_val */);
+ __ li($res$$Register, 1);
+ __ bind(no_update);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct weakG1CompareAndSwapN_acq(iRegIdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 &&
+ (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst));
+ match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
+ effect(TEMP_DEF res, TEMP tmp, KILL cr0);
+ format %{ "weak CMPXCHGW acq $res, $mem, $oldval, $newval; as bool; ptr" %}
+ ins_encode %{
+ Label no_update;
+ __ li($res$$Register, 0);
+ __ cmpxchgw(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register,
+ MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
+ noreg, &no_update, true, true);
+ // Pass oldval to SATB which is the only value which can get overwritten.
+ // Can be done after cmpxchg because there's no safepoint here.
+ pre_write_barrier(masm, this,
+ noreg,
+ $oldval$$Register /* pre_val */,
+ $tmp$$Register,
+ $res$$Register /* temp */,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $newval$$Register,
+ $tmp$$Register,
+ $res$$Register /* temp */,
+ true /* decode_new_val */);
+ __ li($res$$Register, 1);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ isync();
+ } else {
+ // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that.
+ __ sync();
+ }
+ __ bind(no_update); // weak version requires no memory barrier on failure
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct g1GetAndSetP(iRegPdst res, indirect mem, iRegPsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (GetAndSetP mem newval));
+ effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0);
+ format %{ "GetAndSetP $newval, $mem" %}
+ ins_encode %{
+ assert_different_registers($mem$$Register, $newval$$Register);
+ __ getandsetd($res$$Register, $newval$$Register, $mem$$Register,
+ MacroAssembler::cmpxchgx_hint_atomic_update());
+ // Can be done after cmpxchg because there's no safepoint here.
+ pre_write_barrier(masm, this,
+ noreg /* obj */,
+ $res$$Register /* res */,
+ $tmp1$$Register,
+ $tmp2$$Register,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $newval$$Register,
+ $tmp1$$Register,
+ $tmp2$$Register);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ isync();
+ } else {
+ __ sync();
+ }
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct g1GetAndSetN(iRegNdst res, indirect mem, iRegNsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (GetAndSetN mem newval));
+ effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0);
+ format %{ "GetAndSetN $newval, $mem" %}
+ ins_encode %{
+ assert_different_registers($mem$$Register, $newval$$Register);
+ __ getandsetw($res$$Register, $newval$$Register, $mem$$Register,
+ MacroAssembler::cmpxchgx_hint_atomic_update());
+ // Can be done after cmpxchg because there's no safepoint here.
+ pre_write_barrier(masm, this,
+ noreg /* obj */,
+ $res$$Register /* res */,
+ $tmp1$$Register,
+ $tmp2$$Register,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */);
+ post_write_barrier(masm, this,
+ $mem$$Register,
+ $newval$$Register,
+ $tmp1$$Register,
+ $tmp2$$Register,
+ true /* decode_new_val */);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ isync();
+ } else {
+ __ sync();
+ }
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct g1LoadP(iRegPdst dst, memoryAlg4 mem, iRegPdst tmp, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_Load()->is_unordered() && n->as_Load()->barrier_data() != 0);
+ // This instruction does not need an acquiring counterpart because it is only
+ // used for reference loading (Reference::get()).
+ match(Set dst (LoadP mem));
+ effect(TEMP_DEF dst, TEMP tmp, KILL cr0);
+ ins_cost(2 * MEMORY_REF_COST);
+ format %{ "ld $dst, $mem\t# ptr" %}
+ ins_encode %{
+ __ ld($dst$$Register, $mem$$disp, $mem$$base$$Register);
+ pre_write_barrier(masm, this,
+ noreg /* obj */,
+ $dst$$Register /* pre_val */,
+ $tmp$$Register);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct g1LoadN(iRegNdst dst, memoryAlg4 mem, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0)
+%{
+ predicate(UseG1GC && n->as_Load()->is_unordered() && n->as_Load()->barrier_data() != 0);
+ // This instruction does not need an acquiring counterpart because it is only
+ // used for reference loading (Reference::get()).
+ match(Set dst (LoadN mem));
+ effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2, KILL cr0);
+ ins_cost(2 * MEMORY_REF_COST);
+ format %{ "lwz $dst, $mem\t# ptr" %}
+ ins_encode %{
+ __ lwz($dst$$Register, $mem$$disp, $mem$$base$$Register);
+ pre_write_barrier(masm, this,
+ noreg /* obj */,
+ $dst$$Register,
+ $tmp1$$Register,
+ $tmp2$$Register);
+ %}
+ ins_pipe(pipe_class_default);
+%}
diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp
index 16de0b6a7dd..956b082d194 100644
--- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -238,7 +238,7 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler *masm, Register tmp1,
__ ld(tmp1_class_loader_data, in_bytes(InstanceKlass::class_loader_data_offset()), tmp1);
// Fast path: If class loader is strong, the holder cannot be unloaded.
- __ lwz(tmp2, in_bytes(ClassLoaderData::keep_alive_offset()), tmp1_class_loader_data);
+ __ lwz(tmp2, in_bytes(ClassLoaderData::keep_alive_ref_count_offset()), tmp1_class_loader_data);
__ cmpdi(CCR0, tmp2, 0);
__ bne(CCR0, skip_barrier);
diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp
index 6d9a1db1ed4..5f87281bdf9 100644
--- a/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp
+++ b/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp
@@ -43,11 +43,6 @@ void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler *masm) {
Register tmp2 = _tmp2->as_register();
Register result = result_opr()->as_register();
- if (ShenandoahIUBarrier) {
- ShenandoahBarrierSet::assembler()->iu_barrier(masm->masm(), new_val, tmp1, tmp2,
- MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS);
- }
-
if (UseCompressedOops) {
__ encode_heap_oop(cmp_val, cmp_val);
__ encode_heap_oop(new_val, new_val);
@@ -122,10 +117,6 @@ LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess &access, LIRIt
value.load_item();
LIR_Opr value_opr = value.result();
- if (access.is_oop()) {
- value_opr = iu_barrier(access.gen(), value_opr, access.access_emit_info(), access.decorators());
- }
-
assert(type == T_INT || is_reference_type(type) LP64_ONLY( || type == T_LONG ), "unexpected type");
LIR_Opr tmp_xchg = gen->new_register(T_INT);
__ xchg(access.resolved_addr(), value_opr, result, tmp_xchg);
diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp
index 535fe88a680..53150807212 100644
--- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp
@@ -61,20 +61,6 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier(MacroAssembler *masm,
}
}
-void ShenandoahBarrierSetAssembler::iu_barrier(MacroAssembler *masm,
- Register val,
- Register tmp1, Register tmp2,
- MacroAssembler::PreservationLevel preservation_level,
- DecoratorSet decorators) {
- // IU barriers are also employed to avoid resurrection of weak references,
- // even if Shenandoah does not operate in incremental update mode.
- if (ShenandoahIUBarrier || ShenandoahSATBBarrier) {
- __ block_comment("iu_barrier (shenandoahgc) {");
- satb_write_barrier_impl(masm, decorators, noreg, noreg, val, tmp1, tmp2, preservation_level);
- __ block_comment("} iu_barrier (shenandoahgc)");
- }
-}
-
void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler *masm, DecoratorSet decorators,
Register base, RegisterOrConstant ind_or_offs,
Register dst,
@@ -110,7 +96,7 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler *masm, Dec
// Fast path: No barrier required if for every barrier type, it is either disabled or would not store
// any useful information.
- if ((!ShenandoahSATBBarrier || dest_uninitialized) && !ShenandoahIUBarrier && !ShenandoahLoadRefBarrier) {
+ if ((!ShenandoahSATBBarrier || dest_uninitialized) && !ShenandoahLoadRefBarrier) {
return;
}
@@ -158,9 +144,9 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler *masm, Dec
// Invoke runtime.
address jrt_address = nullptr;
if (UseCompressedOops) {
- jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry);
+ jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop);
} else {
- jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry);
+ jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop);
}
assert(jrt_address != nullptr, "jrt routine cannot be found");
@@ -316,7 +302,7 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_impl(MacroAssembler *masm
}
// Invoke runtime.
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, R16_thread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, R16_thread);
// Restore to-be-preserved registers.
if (!preserve_gp_registers && preloaded_mode && pre_val->is_volatile()) {
@@ -582,7 +568,11 @@ void ShenandoahBarrierSetAssembler::load_at(
/* ==== Apply keep-alive barrier, if required (e.g., to inhibit weak reference resurrection) ==== */
if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) {
- iu_barrier(masm, dst, tmp1, tmp2, preservation_level);
+ if (ShenandoahSATBBarrier) {
+ __ block_comment("keep_alive_barrier (shenandoahgc) {");
+ satb_write_barrier_impl(masm, 0, noreg, noreg, dst, tmp1, tmp2, preservation_level);
+ __ block_comment("} keep_alive_barrier (shenandoahgc)");
+ }
}
}
@@ -597,10 +587,6 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler *masm, DecoratorSet
if (ShenandoahSATBBarrier) {
satb_write_barrier(masm, base, ind_or_offs, tmp1, tmp2, tmp3, preservation_level);
}
-
- if (ShenandoahIUBarrier && val != noreg) {
- iu_barrier(masm, val, tmp1, tmp2, preservation_level, decorators);
- }
}
BarrierSetAssembler::store_at(masm, decorators, type,
@@ -683,7 +669,7 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler *masm, Register b
// no special processing is required.
if (UseCompressedOops) {
__ cmpxchgw(CCR0, current_value, expected, new_val, base_addr, MacroAssembler::MemBarNone,
- false, success_flag, true);
+ false, success_flag, nullptr, true);
} else {
__ cmpxchgd(CCR0, current_value, expected, new_val, base_addr, MacroAssembler::MemBarNone,
false, success_flag, nullptr, true);
@@ -920,7 +906,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss
__ push_frame_reg_args(nbytes_save, R11_tmp1);
// Invoke runtime.
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), R0_pre_val, R16_thread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), R0_pre_val, R16_thread);
// Restore to-be-preserved registers.
__ pop_frame();
diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp
index 4514f2540ac..2e56187c169 100644
--- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp
+++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp
@@ -82,11 +82,6 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler {
Register tmp1, Register tmp2, Register tmp3,
MacroAssembler::PreservationLevel preservation_level);
- void iu_barrier(MacroAssembler* masm,
- Register val,
- Register tmp1, Register tmp2,
- MacroAssembler::PreservationLevel preservation_level, DecoratorSet decorators = 0);
-
void load_reference_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register base, RegisterOrConstant ind_or_offs,
Register dst,
diff --git a/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp b/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp
index 136fd7a8ad1..ddeb9adf0a9 100644
--- a/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp
+++ b/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp
@@ -90,7 +90,7 @@ static size_t probe_valid_max_address_bit() {
}
size_t ZPlatformAddressOffsetBits() {
- const static size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1;
+ static const size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1;
const size_t max_address_offset_bits = valid_max_address_offset_bits - 3;
const size_t min_address_offset_bits = max_address_offset_bits - 2;
const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio);
diff --git a/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp
index 9e606054fe9..8a65022126e 100644
--- a/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp
@@ -335,7 +335,7 @@ void ZBarrierSetAssembler::store_barrier_medium(MacroAssembler* masm,
// Try to self-heal null values for atomic accesses
bool need_restore = false;
if (!ind_or_offs.is_constant() || ind_or_offs.as_constant() != 0) {
- __ add(ref_base, ind_or_offs, ref_base);
+ __ add(ref_base, ref_base, ind_or_offs);
need_restore = true;
}
__ ld(R0, in_bytes(ZThreadLocalData::store_good_mask_offset()), R16_thread);
@@ -343,7 +343,7 @@ void ZBarrierSetAssembler::store_barrier_medium(MacroAssembler* masm,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
noreg, need_restore ? nullptr : &slow_path);
if (need_restore) {
- __ subf(ref_base, ind_or_offs, ref_base);
+ __ sub(ref_base, ref_base, ind_or_offs);
__ bne(CCR0, slow_path);
}
} else {
@@ -943,6 +943,8 @@ void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm,
__ call_VM_leaf(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr(), R3_ARG1);
} else if (stub->is_atomic()) {
__ call_VM_leaf(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr(), R3_ARG1);
+ } else if (stub->is_nokeepalive()) {
+ __ call_VM_leaf(ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr(), R3_ARG1);
} else {
__ call_VM_leaf(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr(), R3_ARG1);
}
diff --git a/src/hotspot/cpu/ppc/gc/z/z_ppc.ad b/src/hotspot/cpu/ppc/gc/z/z_ppc.ad
index 017574d40ff..bb696a4738f 100644
--- a/src/hotspot/cpu/ppc/gc/z/z_ppc.ad
+++ b/src/hotspot/cpu/ppc/gc/z/z_ppc.ad
@@ -83,7 +83,8 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Register
z_color(masm, rnew_zpointer, rnew_zaddress);
} else {
bool is_native = (node->barrier_data() & ZBarrierNative) != 0;
- ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, Address(ref_base, disp), rnew_zaddress, rnew_zpointer, is_native, is_atomic);
+ bool is_nokeepalive = (node->barrier_data() & ZBarrierNoKeepalive) != 0;
+ ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, Address(ref_base, disp), rnew_zaddress, rnew_zpointer, is_native, is_atomic, is_nokeepalive);
ZBarrierSetAssembler* bs_asm = ZBarrierSet::assembler();
bs_asm->store_barrier_fast(masm, ref_base, disp, rnew_zaddress, rnew_zpointer, true /* in_nmethod */, is_atomic, *stub->entry(), *stub->continuation());
}
diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
index cdb8a742dcd..aa77f0169ea 100644
--- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp
+++ b/src/hotspot/cpu/ppc/interp_masm_ppc_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.
* Copyright (c) 2012, 2023 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -135,15 +135,7 @@ void InterpreterMacroAssembler::check_and_handle_popframe(Register scratch_reg)
// Call the Interpreter::remove_activation_preserving_args_entry()
// func to get the address of the same-named entrypoint in the
// generated interpreter code.
-#if defined(ABI_ELFv2)
- call_c(CAST_FROM_FN_PTR(address,
- Interpreter::remove_activation_preserving_args_entry),
- relocInfo::none);
-#else
- call_c(CAST_FROM_FN_PTR(FunctionDescriptor*,
- Interpreter::remove_activation_preserving_args_entry),
- relocInfo::none);
-#endif
+ call_c(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_preserving_args_entry));
// Jump to Interpreter::_remove_activation_preserving_args_entry.
mtctr(R3_RET);
@@ -970,13 +962,13 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp, object);
- lwz(tmp, in_bytes(Klass::access_flags_offset()), tmp);
- testbitdi(CCR0, R0, tmp, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
+ lbz(tmp, in_bytes(Klass::misc_flags_offset()), tmp);
+ testbitdi(CCR0, R0, tmp, exact_log2(KlassFlags::_misc_is_value_based_class));
bne(CCR0, slow_case);
}
if (LockingMode == LM_LIGHTWEIGHT) {
- lightweight_lock(object, header, tmp, slow_case);
+ lightweight_lock(monitor, object, header, tmp, slow_case);
b(count_locking);
} else if (LockingMode == LM_LEGACY) {
// Load markWord from object into header.
@@ -1043,11 +1035,7 @@ 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);
- if (LockingMode == LM_LIGHTWEIGHT) {
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), object);
- } else {
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor);
- }
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor);
b(done);
// }
align(32, 12);
diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
index f9e584a1e6b..f036caa0675 100644
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
@@ -1293,11 +1293,7 @@ void MacroAssembler::call_VM_base(Register oop_result,
// ARG1 must hold thread address.
mr(R3_ARG1, R16_thread);
-#if defined(ABI_ELFv2)
address return_pc = call_c(entry_point, relocInfo::none);
-#else
- address return_pc = call_c((FunctionDescriptor*)entry_point, relocInfo::none);
-#endif
reset_last_Java_frame();
@@ -1318,11 +1314,7 @@ void MacroAssembler::call_VM_base(Register oop_result,
void MacroAssembler::call_VM_leaf_base(address entry_point) {
BLOCK_COMMENT("call_VM_leaf {");
-#if defined(ABI_ELFv2)
- call_c(entry_point, relocInfo::none);
-#else
- call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, entry_point), relocInfo::none);
-#endif
+ call_c(entry_point);
BLOCK_COMMENT("} call_VM_leaf");
}
@@ -1501,7 +1493,7 @@ void MacroAssembler::reserved_stack_check(Register return_pc) {
call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), R16_thread);
pop_frame();
mtlr(return_pc);
- load_const_optimized(R0, StubRoutines::throw_delayed_StackOverflowError_entry());
+ load_const_optimized(R0, SharedRuntime::throw_delayed_StackOverflowError_entry());
mtctr(R0);
bctr();
@@ -1620,7 +1612,7 @@ void MacroAssembler::atomic_get_and_modify_generic(Register dest_current_value,
// Temps, addr_base and exchange_value are killed if size < 4 and processor does not support respective instructions.
// Only signed types are supported with size < 4.
void MacroAssembler::cmpxchg_loop_body(ConditionRegister flag, Register dest_current_value,
- Register compare_value, Register exchange_value,
+ RegisterOrConstant compare_value, Register exchange_value,
Register addr_base, Register tmp1, Register tmp2,
Label &retry, Label &failed, bool cmpxchgx_hint, int size) {
// Sub-word instructions are available since Power 8.
@@ -1634,7 +1626,7 @@ void MacroAssembler::cmpxchg_loop_body(ConditionRegister flag, Register dest_cur
modval = exchange_value;
if (instruction_type != size) {
- assert_different_registers(tmp1, tmp2, dest_current_value, compare_value, exchange_value, addr_base);
+ assert_different_registers(tmp1, tmp2, dest_current_value, compare_value.register_or_noreg(), exchange_value, addr_base);
shift_amount = tmp1;
val32 = tmp2;
modval = tmp2;
@@ -1695,21 +1687,23 @@ void MacroAssembler::cmpxchg_loop_body(ConditionRegister flag, Register dest_cur
// CmpxchgX sets condition register to cmpX(current, compare).
void MacroAssembler::cmpxchg_generic(ConditionRegister flag, Register dest_current_value,
- Register compare_value, Register exchange_value,
+ RegisterOrConstant compare_value, Register exchange_value,
Register addr_base, Register tmp1, Register tmp2,
- int semantics, bool cmpxchgx_hint,
- Register int_flag_success, bool contention_hint, bool weak, int size) {
+ int semantics, bool cmpxchgx_hint, Register int_flag_success,
+ Label* failed_ext, bool contention_hint, bool weak, int size) {
Label retry;
- Label failed;
+ Label failed_int;
+ Label& failed = (failed_ext != nullptr) ? *failed_ext : failed_int;
Label done;
// Save one branch if result is returned via register and
// result register is different from the other ones.
bool use_result_reg = (int_flag_success != noreg);
- bool preset_result_reg = (int_flag_success != dest_current_value && int_flag_success != compare_value &&
+ bool preset_result_reg = (int_flag_success != dest_current_value && int_flag_success != compare_value.register_or_noreg() &&
int_flag_success != exchange_value && int_flag_success != addr_base &&
int_flag_success != tmp1 && int_flag_success != tmp2);
assert(!weak || flag == CCR0, "weak only supported with CCR0");
+ assert(int_flag_success == noreg || failed_ext == nullptr, "cannot have both");
assert(size == 1 || size == 2 || size == 4, "unsupported");
if (use_result_reg && preset_result_reg) {
@@ -1735,7 +1729,7 @@ void MacroAssembler::cmpxchg_generic(ConditionRegister flag, Register dest_curre
cmpxchg_loop_body(flag, dest_current_value, compare_value, exchange_value, addr_base, tmp1, tmp2,
retry, failed, cmpxchgx_hint, size);
- if (!weak || use_result_reg) {
+ if (!weak || use_result_reg || failed_ext) {
if (UseStaticBranchPredictionInCompareAndSwapPPC64) {
bne_predict_not_taken(CCR0, weak ? failed : retry); // StXcx_ sets CCR0.
} else {
@@ -1760,7 +1754,7 @@ void MacroAssembler::cmpxchg_generic(ConditionRegister flag, Register dest_curre
b(done);
}
- bind(failed);
+ bind(failed_int);
if (use_result_reg && !preset_result_reg) {
li(int_flag_success, 0);
}
@@ -1787,10 +1781,11 @@ void MacroAssembler::cmpxchg_generic(ConditionRegister flag, Register dest_curre
// To avoid the costly compare exchange the value is tested beforehand.
// Several special cases exist to avoid that unnecessary information is generated.
//
-void MacroAssembler::cmpxchgd(ConditionRegister flag,
- Register dest_current_value, RegisterOrConstant compare_value, Register exchange_value,
- Register addr_base, int semantics, bool cmpxchgx_hint,
- Register int_flag_success, Label* failed_ext, bool contention_hint, bool weak) {
+void MacroAssembler::cmpxchgd(ConditionRegister flag, Register dest_current_value,
+ RegisterOrConstant compare_value, Register exchange_value,
+ Register addr_base,
+ int semantics, bool cmpxchgx_hint, Register int_flag_success,
+ Label* failed_ext, bool contention_hint, bool weak) {
Label retry;
Label failed_int;
Label& failed = (failed_ext != nullptr) ? *failed_ext : failed_int;
@@ -1810,7 +1805,7 @@ void MacroAssembler::cmpxchgd(ConditionRegister flag,
// Add simple guard in order to reduce risk of starving under high contention (recommended by IBM).
if (contention_hint) { // Don't try to reserve if cmp fails.
ld(dest_current_value, 0, addr_base);
- cmpd(flag, compare_value, dest_current_value);
+ cmpd(flag, dest_current_value, compare_value);
bne(flag, failed);
}
@@ -1823,7 +1818,7 @@ void MacroAssembler::cmpxchgd(ConditionRegister flag,
bind(retry);
ldarx(dest_current_value, addr_base, cmpxchgx_hint);
- cmpd(flag, compare_value, dest_current_value);
+ cmpd(flag, dest_current_value, compare_value);
if (UseStaticBranchPredictionInCompareAndSwapPPC64) {
bne_predict_not_taken(flag, failed);
} else {
@@ -2170,7 +2165,6 @@ do { \
(result == R8_ARG6 || result == noreg), "registers must match ppc64.ad"); \
} while(0)
-// Return true: we succeeded in generating this code
void MacroAssembler::lookup_secondary_supers_table(Register r_sub_klass,
Register r_super_klass,
Register temp1,
@@ -2292,9 +2286,8 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl
// The bitmap is full to bursting.
// Implicit invariant: BITMAP_FULL implies (length > 0)
- assert(Klass::SECONDARY_SUPERS_BITMAP_FULL == ~uintx(0), "");
- cmpdi(CCR0, r_bitmap, -1);
- beq(CCR0, L_huge);
+ cmpwi(CCR0, r_array_length, (int32_t)Klass::SECONDARY_SUPERS_TABLE_SIZE - 2);
+ bgt(CCR0, L_huge);
// NB! Our caller has checked bits 0 and 1 in the bitmap. The
// current slot (at secondary_supers[r_array_index]) has not yet
@@ -2417,7 +2410,7 @@ void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass,
void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fast_path, Label* L_slow_path) {
assert(L_fast_path != nullptr || L_slow_path != nullptr, "at least one is required");
- Label L_fallthrough;
+ Label L_check_thread, L_fallthrough;
if (L_fast_path == nullptr) {
L_fast_path = &L_fallthrough;
} else if (L_slow_path == nullptr) {
@@ -2426,10 +2419,14 @@ void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fa
// Fast path check: class is fully initialized
lbz(R0, in_bytes(InstanceKlass::init_state_offset()), klass);
+ // acquire by cmp-branch-isync if fully_initialized
cmpwi(CCR0, R0, InstanceKlass::fully_initialized);
- beq(CCR0, *L_fast_path);
+ bne(CCR0, L_check_thread);
+ isync();
+ b(*L_fast_path);
// Fast path check: current thread is initializer thread
+ bind(L_check_thread);
ld(R0, in_bytes(InstanceKlass::init_thread_offset()), klass);
cmpd(CCR0, thread, R0);
if (L_slow_path == &L_fallthrough) {
@@ -2560,8 +2557,8 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(temp, oop);
- lwz(temp, in_bytes(Klass::access_flags_offset()), temp);
- testbitdi(flag, R0, temp, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
+ lbz(temp, in_bytes(Klass::misc_flags_offset()), temp);
+ testbitdi(flag, R0, temp, exact_log2(KlassFlags::_misc_is_value_based_class));
bne(flag, failure);
}
@@ -2654,7 +2651,19 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register
// flag == NE indicates failure
bind(success);
inc_held_monitor_count(temp);
+#ifdef ASSERT
+ // Check that unlocked label is reached with flag == EQ.
+ Label flag_correct;
+ beq(flag, flag_correct);
+ stop("compiler_fast_lock_object: Flag != EQ");
+#endif
bind(failure);
+#ifdef ASSERT
+ // Check that slow_path label is reached with flag == NE.
+ bne(flag, flag_correct);
+ stop("compiler_fast_lock_object: Flag != NE");
+ bind(flag_correct);
+#endif
}
void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Register oop, Register box,
@@ -2704,17 +2713,12 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe
bind(object_has_monitor);
STATIC_ASSERT(markWord::monitor_value <= INT_MAX);
addi(current_header, current_header, -(int)markWord::monitor_value); // monitor
- ld(temp, in_bytes(ObjectMonitor::owner_offset()), current_header);
-
- // In case of LM_LIGHTWEIGHT, we may reach here with (temp & ObjectMonitor::ANONYMOUS_OWNER) != 0.
- // This is handled like owner thread mismatches: We take the slow path.
- cmpd(flag, temp, R16_thread);
- bne(flag, failure);
ld(displaced_header, in_bytes(ObjectMonitor::recursions_offset()), current_header);
-
addic_(displaced_header, displaced_header, -1);
blt(CCR0, notRecursive); // Not recursive if negative after decrement.
+
+ // Recursive unlock
std(displaced_header, in_bytes(ObjectMonitor::recursions_offset()), current_header);
if (flag == CCR0) { // Otherwise, flag is already EQ, here.
crorc(CCR0, Assembler::equal, CCR0, Assembler::equal); // Set CCR0 EQ
@@ -2722,24 +2726,57 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe
b(success);
bind(notRecursive);
+
+ // Set owner to null.
+ // Release to satisfy the JMM
+ release();
+ li(temp, 0);
+ std(temp, in_bytes(ObjectMonitor::owner_offset()), current_header);
+ // We need a full fence after clearing owner to avoid stranding.
+ // StoreLoad achieves this.
+ membar(StoreLoad);
+
+ // Check if the entry lists are empty.
ld(temp, in_bytes(ObjectMonitor::EntryList_offset()), current_header);
ld(displaced_header, in_bytes(ObjectMonitor::cxq_offset()), current_header);
orr(temp, temp, displaced_header); // Will be 0 if both are 0.
cmpdi(flag, temp, 0);
- bne(flag, failure);
- release();
- std(temp, in_bytes(ObjectMonitor::owner_offset()), current_header);
+ beq(flag, success); // If so we are done.
+
+ // Check if there is a successor.
+ ld(temp, in_bytes(ObjectMonitor::succ_offset()), current_header);
+ cmpdi(flag, temp, 0);
+ // Invert equal bit
+ crnand(flag, Assembler::equal, flag, Assembler::equal);
+ beq(flag, success); // If there is a successor we are done.
+
+ // Save the monitor pointer in the current thread, so we can try
+ // to reacquire the lock in SharedRuntime::monitor_exit_helper().
+ std(current_header, in_bytes(JavaThread::unlocked_inflated_monitor_offset()), R16_thread);
+ b(failure); // flag == NE
// flag == EQ indicates success, decrement held monitor count
// flag == NE indicates failure
bind(success);
dec_held_monitor_count(temp);
+#ifdef ASSERT
+ // Check that unlocked label is reached with flag == EQ.
+ Label flag_correct;
+ beq(flag, flag_correct);
+ stop("compiler_fast_unlock_object: Flag != EQ");
+#endif
bind(failure);
+#ifdef ASSERT
+ // Check that slow_path label is reached with flag == NE.
+ bne(flag, flag_correct);
+ stop("compiler_fast_unlock_object: Flag != NE");
+ bind(flag_correct);
+#endif
}
-void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister flag, Register obj, Register tmp1,
- Register tmp2, Register tmp3) {
- assert_different_registers(obj, tmp1, tmp2, tmp3);
+void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister flag, Register obj, Register box,
+ Register tmp1, Register tmp2, Register tmp3) {
+ assert_different_registers(obj, box, tmp1, tmp2, tmp3);
assert(flag == CCR0, "bad condition register");
// Handle inflated monitor.
@@ -2749,11 +2786,17 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla
// Finish fast lock unsuccessfully. MUST branch to with flag == EQ
Label slow_path;
+ if (UseObjectMonitorTable) {
+ // Clear cache in case fast locking succeeds.
+ li(tmp1, 0);
+ std(tmp1, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box);
+ }
+
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp1, obj);
- lwz(tmp1, in_bytes(Klass::access_flags_offset()), tmp1);
- testbitdi(flag, R0, tmp1, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
- bne(flag, slow_path);
+ lbz(tmp1, in_bytes(Klass::misc_flags_offset()), tmp1);
+ testbitdi(CCR0, R0, tmp1, exact_log2(KlassFlags::_misc_is_value_based_class));
+ bne(CCR0, slow_path);
}
const Register mark = tmp1;
@@ -2768,8 +2811,8 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla
// Check if lock-stack is full.
lwz(top, in_bytes(JavaThread::lock_stack_top_offset()), R16_thread);
- cmplwi(flag, top, LockStack::end_offset() - 1);
- bgt(flag, slow_path);
+ cmplwi(CCR0, top, LockStack::end_offset() - 1);
+ bgt(CCR0, slow_path);
// The underflow check is elided. The recursive check will always fail
// when the lock stack is empty because of the _bad_oop_sentinel field.
@@ -2777,19 +2820,19 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla
// Check if recursive.
subi(t, top, oopSize);
ldx(t, R16_thread, t);
- cmpd(flag, obj, t);
- beq(flag, push);
+ cmpd(CCR0, obj, t);
+ beq(CCR0, push);
// Check for monitor (0b10) or locked (0b00).
ld(mark, oopDesc::mark_offset_in_bytes(), obj);
andi_(t, mark, markWord::lock_mask_in_place);
- cmpldi(flag, t, markWord::unlocked_value);
- bgt(flag, inflated);
- bne(flag, slow_path);
+ cmpldi(CCR0, t, markWord::unlocked_value);
+ bgt(CCR0, inflated);
+ bne(CCR0, slow_path);
// Not inflated.
- // Try to lock. Transition lock bits 0b00 => 0b01
+ // Try to lock. Transition lock bits 0b01 => 0b00
assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid a lea");
atomically_flip_locked_state(/* is_unlock */ false, obj, mark, slow_path, MacroAssembler::MemBarAcq);
@@ -2805,31 +2848,84 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla
bind(inflated);
// mark contains the tagged ObjectMonitor*.
- const Register tagged_monitor = mark;
const uintptr_t monitor_tag = markWord::monitor_value;
+ const Register monitor = mark;
const Register owner_addr = tmp2;
+ Label monitor_locked;
+
+ if (!UseObjectMonitorTable) {
+ // Compute owner address.
+ addi(owner_addr, mark, in_bytes(ObjectMonitor::owner_offset()) - monitor_tag);
+ } else {
+ Label monitor_found;
+ Register cache_addr = tmp2;
+
+ // Load cache address
+ addi(cache_addr, R16_thread, in_bytes(JavaThread::om_cache_oops_offset()));
+
+ const int num_unrolled = 2;
+ for (int i = 0; i < num_unrolled; i++) {
+ ld(tmp3, 0, cache_addr);
+ cmpd(CCR0, tmp3, obj);
+ beq(CCR0, monitor_found);
+ addi(cache_addr, cache_addr, in_bytes(OMCache::oop_to_oop_difference()));
+ }
- // Compute owner address.
- addi(owner_addr, tagged_monitor, in_bytes(ObjectMonitor::owner_offset()) - monitor_tag);
+ Label loop;
+
+ // Search for obj in cache.
+ bind(loop);
+
+ // Check for match.
+ ld(tmp3, 0, cache_addr);
+ cmpd(CCR0, tmp3, obj);
+ beq(CCR0, monitor_found);
+
+ // Search until null encountered, guaranteed _null_sentinel at end.
+ addi(cache_addr, cache_addr, in_bytes(OMCache::oop_to_oop_difference()));
+ cmpdi(CCR1, tmp3, 0);
+ bne(CCR1, loop);
+ // Cache Miss, CCR0.NE set from cmp above
+ b(slow_path);
+
+ bind(monitor_found);
+ ld(monitor, in_bytes(OMCache::oop_to_monitor_difference()), cache_addr);
+
+ // Compute owner address.
+ addi(owner_addr, monitor, in_bytes(ObjectMonitor::owner_offset()));
+ }
// CAS owner (null => current thread).
- cmpxchgd(/*flag=*/flag,
+ cmpxchgd(/*flag=*/CCR0,
/*current_value=*/t,
/*compare_value=*/(intptr_t)0,
/*exchange_value=*/R16_thread,
/*where=*/owner_addr,
MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq,
MacroAssembler::cmpxchgx_hint_acquire_lock());
- beq(flag, locked);
+ beq(CCR0, monitor_locked);
// Check if recursive.
- cmpd(flag, t, R16_thread);
- bne(flag, slow_path);
+ cmpd(CCR0, t, R16_thread);
+ bne(CCR0, slow_path);
// Recursive.
- ld(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr);
- addi(tmp1, tmp1, 1);
- std(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr);
+ if (!UseObjectMonitorTable) {
+ assert_different_registers(tmp1, owner_addr);
+ ld(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr);
+ addi(tmp1, tmp1, 1);
+ std(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr);
+ } else {
+ assert_different_registers(tmp2, monitor);
+ ld(tmp2, in_bytes(ObjectMonitor::recursions_offset()), monitor);
+ addi(tmp2, tmp2, 1);
+ std(tmp2, in_bytes(ObjectMonitor::recursions_offset()), monitor);
+ }
+
+ bind(monitor_locked);
+ if (UseObjectMonitorTable) {
+ std(monitor, BasicLock::object_monitor_cache_offset_in_bytes(), box);
+ }
}
bind(locked);
@@ -2838,21 +2934,21 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla
#ifdef ASSERT
// Check that locked label is reached with flag == EQ.
Label flag_correct;
- beq(flag, flag_correct);
+ beq(CCR0, flag_correct);
stop("Fast Lock Flag != EQ");
#endif
bind(slow_path);
#ifdef ASSERT
// Check that slow_path label is reached with flag == NE.
- bne(flag, flag_correct);
+ bne(CCR0, flag_correct);
stop("Fast Lock Flag != NE");
bind(flag_correct);
#endif
// C2 uses the value of flag (NE vs EQ) to determine the continuation.
}
-void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister flag, Register obj, Register tmp1,
- Register tmp2, Register tmp3) {
+void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister flag, Register obj, Register box,
+ Register tmp1, Register tmp2, Register tmp3) {
assert_different_registers(obj, tmp1, tmp2, tmp3);
assert(flag == CCR0, "bad condition register");
@@ -2874,9 +2970,9 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f
lwz(top, in_bytes(JavaThread::lock_stack_top_offset()), R16_thread);
subi(top, top, oopSize);
ldx(t, R16_thread, top);
- cmpd(flag, obj, t);
+ cmpd(CCR0, obj, t);
// Top of lock stack was not obj. Must be monitor.
- bne(flag, inflated_load_monitor);
+ bne(CCR0, inflated_load_monitor);
// Pop lock-stack.
DEBUG_ONLY(li(t, 0);)
@@ -2889,15 +2985,19 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f
// Check if recursive.
subi(t, top, oopSize);
ldx(t, R16_thread, t);
- cmpd(flag, obj, t);
- beq(flag, unlocked);
+ cmpd(CCR0, obj, t);
+ beq(CCR0, unlocked);
// Not recursive.
// Check for monitor (0b10).
ld(mark, oopDesc::mark_offset_in_bytes(), obj);
andi_(t, mark, markWord::monitor_value);
- bne(CCR0, inflated);
+ if (!UseObjectMonitorTable) {
+ bne(CCR0, inflated);
+ } else {
+ bne(CCR0, push_and_slow);
+ }
#ifdef ASSERT
// Check header not unlocked (0b01).
@@ -2937,8 +3037,8 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f
cmplwi(CCR0, top, in_bytes(JavaThread::lock_stack_base_offset()));
blt(CCR0, check_done);
ldx(t, R16_thread, top);
- cmpd(flag, obj, t);
- bne(flag, inflated);
+ cmpd(CCR0, obj, t);
+ bne(CCR0, inflated);
stop("Fast Unlock lock on stack");
bind(check_done);
#endif
@@ -2947,8 +3047,15 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f
const Register monitor = mark;
const uintptr_t monitor_tag = markWord::monitor_value;
- // Untag the monitor.
- subi(monitor, mark, monitor_tag);
+ if (!UseObjectMonitorTable) {
+ // Untag the monitor.
+ subi(monitor, mark, monitor_tag);
+ } else {
+ ld(monitor, BasicLock::object_monitor_cache_offset_in_bytes(), box);
+ // null check with Flags == NE, no valid pointer below alignof(ObjectMonitor*)
+ cmpldi(CCR0, monitor, checked_cast(alignof(ObjectMonitor*)));
+ blt(CCR0, slow_path);
+ }
const Register recursions = tmp2;
Label not_recursive;
@@ -2965,27 +3072,35 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f
bind(not_recursive);
- Label release_;
const Register t2 = tmp2;
+ // Set owner to null.
+ // Release to satisfy the JMM
+ release();
+ li(t, 0);
+ std(t, in_bytes(ObjectMonitor::owner_offset()), monitor);
+ // We need a full fence after clearing owner to avoid stranding.
+ // StoreLoad achieves this.
+ membar(StoreLoad);
+
// Check if the entry lists are empty.
ld(t, in_bytes(ObjectMonitor::EntryList_offset()), monitor);
ld(t2, in_bytes(ObjectMonitor::cxq_offset()), monitor);
orr(t, t, t2);
- cmpdi(flag, t, 0);
- beq(flag, release_);
+ cmpdi(CCR0, t, 0);
+ beq(CCR0, unlocked); // If so we are done.
- // The owner may be anonymous and we removed the last obj entry in
- // the lock-stack. This loses the information about the owner.
- // Write the thread to the owner field so the runtime knows the owner.
- std(R16_thread, in_bytes(ObjectMonitor::owner_offset()), monitor);
- b(slow_path);
+ // Check if there is a successor.
+ ld(t, in_bytes(ObjectMonitor::succ_offset()), monitor);
+ cmpdi(CCR0, t, 0);
+ // Invert equal bit
+ crnand(flag, Assembler::equal, flag, Assembler::equal);
+ beq(CCR0, unlocked); // If there is a successor we are done.
- bind(release_);
- // Set owner to null.
- release();
- // t contains 0
- std(t, in_bytes(ObjectMonitor::owner_offset()), monitor);
+ // Save the monitor pointer in the current thread, so we can try
+ // to reacquire the lock in SharedRuntime::monitor_exit_helper().
+ std(monitor, in_bytes(JavaThread::unlocked_inflated_monitor_offset()), R16_thread);
+ b(slow_path); // flag == NE
}
bind(unlocked);
@@ -2994,13 +3109,13 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f
#ifdef ASSERT
// Check that unlocked label is reached with flag == EQ.
Label flag_correct;
- beq(flag, flag_correct);
+ beq(CCR0, flag_correct);
stop("Fast Lock Flag != EQ");
#endif
bind(slow_path);
#ifdef ASSERT
// Check that slow_path label is reached with flag == NE.
- bne(flag, flag_correct);
+ bne(CCR0, flag_correct);
stop("Fast Lock Flag != NE");
bind(flag_correct);
#endif
@@ -4629,15 +4744,21 @@ void MacroAssembler::atomically_flip_locked_state(bool is_unlock, Register obj,
//
// - obj: the object to be locked
// - t1, t2: temporary register
-void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, Label& slow) {
+void MacroAssembler::lightweight_lock(Register box, Register obj, Register t1, Register t2, Label& slow) {
assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking");
- assert_different_registers(obj, t1, t2);
+ assert_different_registers(box, obj, t1, t2);
Label push;
const Register top = t1;
const Register mark = t2;
const Register t = R0;
+ if (UseObjectMonitorTable) {
+ // Clear cache in case fast locking succeeds.
+ li(t, 0);
+ std(t, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box);
+ }
+
// Check if the lock-stack is full.
lwz(top, in_bytes(JavaThread::lock_stack_top_offset()), R16_thread);
cmplwi(CCR0, top, LockStack::end_offset());
@@ -4658,7 +4779,7 @@ void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, La
andi_(t, t, markWord::lock_mask_in_place);
bne(CCR0, slow);
- // Try to lock. Transition lock bits 0b00 => 0b01
+ // Try to lock. Transition lock bits 0b01 => 0b00
atomically_flip_locked_state(/* is_unlock */ false, obj, mark, slow, MacroAssembler::MemBarAcq);
bind(push);
diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp
index 15b5e26f8f6..224e7bff995 100644
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp
@@ -359,7 +359,7 @@ class MacroAssembler: public Assembler {
address call_c(Register function_entry);
// For tail calls: only branch, don't link, so callee returns to caller of this function.
address call_c_and_return_to_caller(Register function_entry);
- address call_c(address function_entry, relocInfo::relocType rt);
+ address call_c(address function_entry, relocInfo::relocType rt = relocInfo::none);
#else
// Call a C function via a function descriptor and use full C
// calling conventions. Updates and returns _last_calls_return_pc.
@@ -367,6 +367,9 @@ class MacroAssembler: public Assembler {
// For tail calls: only branch, don't link, so callee returns to caller of this function.
address call_c_and_return_to_caller(Register function_descriptor);
address call_c(const FunctionDescriptor* function_descriptor, relocInfo::relocType rt);
+ address call_c(address function_entry, relocInfo::relocType rt = relocInfo::none) {
+ return call_c((const FunctionDescriptor*)function_entry, rt);
+ }
address call_c_using_toc(const FunctionDescriptor* function_descriptor, relocInfo::relocType rt,
Register toc);
#endif
@@ -482,13 +485,14 @@ class MacroAssembler: public Assembler {
Register addr_base, Register tmp1, Register tmp2, Register tmp3,
bool cmpxchgx_hint, bool is_add, int size);
void cmpxchg_loop_body(ConditionRegister flag, Register dest_current_value,
- Register compare_value, Register exchange_value,
+ RegisterOrConstant compare_value, Register exchange_value,
Register addr_base, Register tmp1, Register tmp2,
Label &retry, Label &failed, bool cmpxchgx_hint, int size);
- void cmpxchg_generic(ConditionRegister flag,
- Register dest_current_value, Register compare_value, Register exchange_value, Register addr_base,
- Register tmp1, Register tmp2,
- int semantics, bool cmpxchgx_hint, Register int_flag_success, bool contention_hint, bool weak, int size);
+ void cmpxchg_generic(ConditionRegister flag, Register dest_current_value,
+ RegisterOrConstant compare_value, Register exchange_value,
+ Register addr_base, Register tmp1, Register tmp2,
+ int semantics, bool cmpxchgx_hint, Register int_flag_success,
+ Label* failed_ext, bool contention_hint, bool weak, int size);
public:
// Temps and addr_base are killed if processor does not support Power 8 instructions.
// Result will be sign extended.
@@ -528,33 +532,37 @@ class MacroAssembler: public Assembler {
Register tmp, bool cmpxchgx_hint);
// Temps, addr_base and exchange_value are killed if processor does not support Power 8 instructions.
// compare_value must be at least 32 bit sign extended. Result will be sign extended.
- void cmpxchgb(ConditionRegister flag,
- Register dest_current_value, Register compare_value, Register exchange_value, Register addr_base,
- Register tmp1, Register tmp2, int semantics, bool cmpxchgx_hint = false,
- Register int_flag_success = noreg, bool contention_hint = false, bool weak = false) {
+ void cmpxchgb(ConditionRegister flag, Register dest_current_value,
+ RegisterOrConstant compare_value, Register exchange_value,
+ Register addr_base, Register tmp1, Register tmp2,
+ int semantics, bool cmpxchgx_hint = false, Register int_flag_success = noreg,
+ Label* failed = nullptr, bool contention_hint = false, bool weak = false) {
cmpxchg_generic(flag, dest_current_value, compare_value, exchange_value, addr_base, tmp1, tmp2,
- semantics, cmpxchgx_hint, int_flag_success, contention_hint, weak, 1);
+ semantics, cmpxchgx_hint, int_flag_success, failed, contention_hint, weak, 1);
}
// Temps, addr_base and exchange_value are killed if processor does not support Power 8 instructions.
// compare_value must be at least 32 bit sign extended. Result will be sign extended.
- void cmpxchgh(ConditionRegister flag,
- Register dest_current_value, Register compare_value, Register exchange_value, Register addr_base,
- Register tmp1, Register tmp2, int semantics, bool cmpxchgx_hint = false,
- Register int_flag_success = noreg, bool contention_hint = false, bool weak = false) {
+ void cmpxchgh(ConditionRegister flag, Register dest_current_value,
+ RegisterOrConstant compare_value, Register exchange_value,
+ Register addr_base, Register tmp1, Register tmp2,
+ int semantics, bool cmpxchgx_hint = false, Register int_flag_success = noreg,
+ Label* failed = nullptr, bool contention_hint = false, bool weak = false) {
cmpxchg_generic(flag, dest_current_value, compare_value, exchange_value, addr_base, tmp1, tmp2,
- semantics, cmpxchgx_hint, int_flag_success, contention_hint, weak, 2);
+ semantics, cmpxchgx_hint, int_flag_success, failed, contention_hint, weak, 2);
}
- void cmpxchgw(ConditionRegister flag,
- Register dest_current_value, Register compare_value, Register exchange_value, Register addr_base,
- int semantics, bool cmpxchgx_hint = false,
- Register int_flag_success = noreg, bool contention_hint = false, bool weak = false) {
+ void cmpxchgw(ConditionRegister flag, Register dest_current_value,
+ RegisterOrConstant compare_value, Register exchange_value,
+ Register addr_base,
+ int semantics, bool cmpxchgx_hint = false, Register int_flag_success = noreg,
+ Label* failed = nullptr, bool contention_hint = false, bool weak = false) {
cmpxchg_generic(flag, dest_current_value, compare_value, exchange_value, addr_base, noreg, noreg,
- semantics, cmpxchgx_hint, int_flag_success, contention_hint, weak, 4);
+ semantics, cmpxchgx_hint, int_flag_success, failed, contention_hint, weak, 4);
}
- void cmpxchgd(ConditionRegister flag,
- Register dest_current_value, RegisterOrConstant compare_value, Register exchange_value,
- Register addr_base, int semantics, bool cmpxchgx_hint = false,
- Register int_flag_success = noreg, Label* failed = nullptr, bool contention_hint = false, bool weak = false);
+ void cmpxchgd(ConditionRegister flag, Register dest_current_value,
+ RegisterOrConstant compare_value, Register exchange_value,
+ Register addr_base,
+ int semantics, bool cmpxchgx_hint = false, Register int_flag_success = noreg,
+ Label* failed = nullptr, bool contention_hint = false, bool weak = false);
// interface method calling
void lookup_interface_method(Register recv_klass,
@@ -646,7 +654,7 @@ 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 lightweight_lock(Register obj, Register t1, Register t2, Label& slow);
+ void lightweight_lock(Register box, Register obj, Register t1, Register t2, Label& slow);
void lightweight_unlock(Register obj, Register t1, Label& slow);
// allocation (for C1)
@@ -667,11 +675,11 @@ class MacroAssembler: public Assembler {
void compiler_fast_unlock_object(ConditionRegister flag, Register oop, Register box,
Register tmp1, Register tmp2, Register tmp3);
- void compiler_fast_lock_lightweight_object(ConditionRegister flag, Register oop, Register tmp1,
- Register tmp2, Register tmp3);
+ void compiler_fast_lock_lightweight_object(ConditionRegister flag, Register oop, Register box,
+ Register tmp1, Register tmp2, Register tmp3);
- void compiler_fast_unlock_lightweight_object(ConditionRegister flag, Register oop, Register tmp1,
- Register tmp2, Register tmp3);
+ void compiler_fast_unlock_lightweight_object(ConditionRegister flag, Register oop, Register box,
+ Register tmp1, Register tmp2, Register tmp3);
// Check if safepoint requested and if so branch
void safepoint_poll(Label& slow_path, Register temp, bool at_return, bool in_nmethod);
diff --git a/src/hotspot/cpu/ppc/methodHandles_ppc.cpp b/src/hotspot/cpu/ppc/methodHandles_ppc.cpp
index 6e5ac325e50..ccec05e7105 100644
--- a/src/hotspot/cpu/ppc/methodHandles_ppc.cpp
+++ b/src/hotspot/cpu/ppc/methodHandles_ppc.cpp
@@ -158,8 +158,8 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth
__ bctr();
__ bind(L_no_such_method);
- assert(StubRoutines::throw_AbstractMethodError_entry() != nullptr, "not yet generated!");
- __ load_const_optimized(target, StubRoutines::throw_AbstractMethodError_entry());
+ assert(SharedRuntime::throw_AbstractMethodError_entry() != nullptr, "not yet generated!");
+ __ load_const_optimized(target, SharedRuntime::throw_AbstractMethodError_entry());
__ mtctr(target);
__ bctr();
}
@@ -489,7 +489,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
if (iid == vmIntrinsics::_linkToInterface) {
__ BIND(L_incompatible_class_change_error);
- __ load_const_optimized(temp1, StubRoutines::throw_IncompatibleClassChangeError_entry());
+ __ load_const_optimized(temp1, SharedRuntime::throw_IncompatibleClassChangeError_entry());
__ mtctr(temp1);
__ bctr();
}
diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp
index 9520f6a94f2..f61328fc736 100644
--- a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp
+++ b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp
@@ -92,10 +92,10 @@ address NativeCall::destination() const {
// Used in the runtime linkage of calls; see class CompiledIC.
//
// Add parameter assert_lock to switch off assertion
-// during code generation, where no patching lock is needed.
+// during code generation, where no lock is needed.
void NativeCall::set_destination_mt_safe(address dest, bool assert_lock) {
assert(!assert_lock ||
- (Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
+ (CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
CompiledICLocker::is_safe(addr_at(0)),
"concurrent code patching");
diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad
index 38485da9581..6d3daa025e8 100644
--- a/src/hotspot/cpu/ppc/ppc.ad
+++ b/src/hotspot/cpu/ppc/ppc.ad
@@ -1000,6 +1000,10 @@ int MachNode::compute_padding(int current_offset) const {
// Should the matcher clone input 'm' of node 'n'?
bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) {
+ if (is_encode_and_store_pattern(n, m)) {
+ mstack.push(m, Visit);
+ return true;
+ }
return false;
}
@@ -2150,10 +2154,6 @@ const RegMask* Matcher::predicate_reg_mask(void) {
return nullptr;
}
-const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) {
- return nullptr;
-}
-
// Vector calling convention not yet implemented.
bool Matcher::supports_vector_calling_convention(void) {
return false;
@@ -5407,7 +5407,7 @@ instruct loadRange(iRegIdst dst, memory mem) %{
// Load Compressed Pointer
instruct loadN(iRegNdst dst, memory mem) %{
match(Set dst (LoadN mem));
- predicate(n->as_Load()->is_unordered() || followed_by_acquire(n));
+ predicate((n->as_Load()->is_unordered() || followed_by_acquire(n)) && n->as_Load()->barrier_data() == 0);
ins_cost(MEMORY_REF_COST);
format %{ "LWZ $dst, $mem \t// load compressed ptr" %}
@@ -5419,6 +5419,7 @@ instruct loadN(iRegNdst dst, memory mem) %{
// Load Compressed Pointer acquire.
instruct loadN_ac(iRegNdst dst, memory mem) %{
match(Set dst (LoadN mem));
+ predicate(n->as_Load()->barrier_data() == 0);
ins_cost(3*MEMORY_REF_COST);
format %{ "LWZ $dst, $mem \t// load acquire compressed ptr\n\t"
@@ -5432,7 +5433,7 @@ instruct loadN_ac(iRegNdst dst, memory mem) %{
// Load Compressed Pointer and decode it if narrow_oop_shift == 0.
instruct loadN2P_unscaled(iRegPdst dst, memory mem) %{
match(Set dst (DecodeN (LoadN mem)));
- predicate(_kids[0]->_leaf->as_Load()->is_unordered() && CompressedOops::shift() == 0);
+ predicate(_kids[0]->_leaf->as_Load()->is_unordered() && CompressedOops::shift() == 0 && _kids[0]->_leaf->as_Load()->barrier_data() == 0);
ins_cost(MEMORY_REF_COST);
format %{ "LWZ $dst, $mem \t// DecodeN (unscaled)" %}
@@ -6423,6 +6424,7 @@ instruct reinterpretX(vecX dst) %{
// Store Compressed Oop
instruct storeN(memory dst, iRegN_P2N src) %{
match(Set dst (StoreN dst src));
+ predicate(n->as_Store()->barrier_data() == 0);
ins_cost(MEMORY_REF_COST);
format %{ "STW $src, $dst \t// compressed oop" %}
@@ -6476,23 +6478,6 @@ instruct storeD(memory mem, regD src) %{
ins_pipe(pipe_class_memory);
%}
-//----------Store Instructions With Zeros--------------------------------------
-
-instruct storeCM(memory mem, immI_0 zero) %{
- match(Set mem (StoreCM mem zero));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STB #0, $mem \t// CMS card-mark byte store" %}
- size(8);
- ins_encode %{
- __ li(R0, 0);
- // No release barrier: Oops are allowed to get visible after marking.
- guarantee($mem$$base$$Register != R1_SP, "use frame_slots_bias");
- __ stb(R0, $mem$$disp, $mem$$base$$Register);
- %}
- ins_pipe(pipe_class_memory);
-%}
-
// Convert oop pointer into compressed form.
// Nodes for postalloc expand.
@@ -6598,7 +6583,7 @@ instruct encodeP_not_null_Ex(iRegNdst dst, iRegPsrc src) %{
instruct encodeP_not_null_base_null(iRegNdst dst, iRegPsrc src) %{
match(Set dst (EncodeP src));
predicate(CompressedOops::shift() != 0 &&
- CompressedOops::base() ==0);
+ CompressedOops::base() == nullptr);
format %{ "SRDI $dst, $src, #3 \t// encodeP, $src != nullptr" %}
size(4);
@@ -6695,7 +6680,7 @@ instruct decodeN_Ex(iRegPdst dst, iRegNsrc src, flagsReg crx) %{
predicate((n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull &&
n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant) &&
CompressedOops::shift() != 0 &&
- CompressedOops::base() != 0);
+ CompressedOops::base() != nullptr);
ins_cost(4 * DEFAULT_COST); // Should be more expensive than decodeN_Disjoint_isel_Ex.
effect(TEMP crx);
@@ -6707,7 +6692,7 @@ instruct decodeN_Ex(iRegPdst dst, iRegNsrc src, flagsReg crx) %{
instruct decodeN_nullBase(iRegPdst dst, iRegNsrc src) %{
match(Set dst (DecodeN src));
predicate(CompressedOops::shift() != 0 &&
- CompressedOops::base() == 0);
+ CompressedOops::base() == nullptr);
format %{ "SLDI $dst, $src, #3 \t// DecodeN (zerobased)" %}
size(4);
@@ -6825,7 +6810,7 @@ instruct decodeN_notNull_addBase_Ex(iRegPdst dst, iRegNsrc src) %{
predicate((n->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull ||
n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant) &&
CompressedOops::shift() != 0 &&
- CompressedOops::base() != 0);
+ CompressedOops::base() != nullptr);
ins_cost(2 * DEFAULT_COST);
format %{ "DecodeN $dst, $src \t// $src != nullptr, postalloc expanded" %}
@@ -7390,7 +7375,7 @@ instruct compareAndSwapB_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgb(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- $res$$Register, true);
+ $res$$Register, nullptr, true);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ isync();
} else {
@@ -7409,7 +7394,7 @@ instruct compareAndSwapB4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIs
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgb(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- $res$$Register, true);
+ $res$$Register, nullptr, true);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ isync();
} else {
@@ -7428,7 +7413,7 @@ instruct compareAndSwapS_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgh(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- $res$$Register, true);
+ $res$$Register, nullptr, true);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ isync();
} else {
@@ -7447,7 +7432,7 @@ instruct compareAndSwapS4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIs
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgh(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- $res$$Register, true);
+ $res$$Register, nullptr, true);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ isync();
} else {
@@ -7465,7 +7450,7 @@ instruct compareAndSwapI_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgw(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- $res$$Register, true);
+ $res$$Register, nullptr, true);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ isync();
} else {
@@ -7477,13 +7462,14 @@ instruct compareAndSwapI_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc
instruct compareAndSwapN_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{
match(Set res (CompareAndSwapN mem_ptr (Binary src1 src2)));
+ predicate(n->as_LoadStore()->barrier_data() == 0);
effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump
format %{ "CMPXCHGW $res, $mem_ptr, $src1, $src2; as bool" %}
ins_encode %{
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgw(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- $res$$Register, true);
+ $res$$Register, nullptr, true);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ isync();
} else {
@@ -7541,7 +7527,7 @@ instruct weakCompareAndSwapB_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iReg
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgb(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg,
MacroAssembler::MemBarNone,
- MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true);
+ MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7555,7 +7541,7 @@ instruct weakCompareAndSwapB4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iR
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgb(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register,
MacroAssembler::MemBarNone,
- MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true);
+ MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7569,7 +7555,7 @@ instruct weakCompareAndSwapB_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr,
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgb(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg,
support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter,
- MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true);
+ MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7583,7 +7569,7 @@ instruct weakCompareAndSwapB4_acq_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgb(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register,
support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter,
- MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true);
+ MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7597,7 +7583,7 @@ instruct weakCompareAndSwapS_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iReg
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgh(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg,
MacroAssembler::MemBarNone,
- MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true);
+ MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7611,7 +7597,7 @@ instruct weakCompareAndSwapS4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iR
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgh(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register,
MacroAssembler::MemBarNone,
- MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true);
+ MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7625,7 +7611,7 @@ instruct weakCompareAndSwapS_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr,
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgh(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg,
support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter,
- MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true);
+ MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7639,7 +7625,7 @@ instruct weakCompareAndSwapS4_acq_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgh(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register,
support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter,
- MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true);
+ MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7653,7 +7639,7 @@ instruct weakCompareAndSwapI_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iReg
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgw(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register,
MacroAssembler::MemBarNone,
- MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true);
+ MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7669,28 +7655,28 @@ instruct weakCompareAndSwapI_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr,
// value is never passed to caller.
__ cmpxchgw(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register,
support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter,
- MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true);
+ MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true);
%}
ins_pipe(pipe_class_default);
%}
instruct weakCompareAndSwapN_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{
match(Set res (WeakCompareAndSwapN mem_ptr (Binary src1 src2)));
- predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst);
+ predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst && n->as_LoadStore()->barrier_data() == 0);
effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump
format %{ "weak CMPXCHGW $res, $mem_ptr, $src1, $src2; as bool" %}
ins_encode %{
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgw(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register,
MacroAssembler::MemBarNone,
- MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true);
+ MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true);
%}
ins_pipe(pipe_class_default);
%}
instruct weakCompareAndSwapN_acq_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{
match(Set res (WeakCompareAndSwapN mem_ptr (Binary src1 src2)));
- predicate(((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst);
+ predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && n->as_LoadStore()->barrier_data() == 0);
effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump
format %{ "weak CMPXCHGW acq $res, $mem_ptr, $src1, $src2; as bool" %}
ins_encode %{
@@ -7699,7 +7685,7 @@ instruct weakCompareAndSwapN_acq_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr,
// value is never passed to caller.
__ cmpxchgw(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register,
support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter,
- MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true);
+ MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7776,7 +7762,7 @@ instruct compareAndExchangeB_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iReg
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgb(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- noreg, true);
+ noreg, nullptr, true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7790,7 +7776,7 @@ instruct compareAndExchangeB4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iR
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgb(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, R0,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- noreg, true);
+ noreg, nullptr, true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7804,7 +7790,7 @@ instruct compareAndExchangeB_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr,
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgb(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- noreg, true);
+ noreg, nullptr, true);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ isync();
} else {
@@ -7824,7 +7810,7 @@ instruct compareAndExchangeB4_acq_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgb(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, R0,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- noreg, true);
+ noreg, nullptr, true);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ isync();
} else {
@@ -7844,7 +7830,7 @@ instruct compareAndExchangeS_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iReg
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgh(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- noreg, true);
+ noreg, nullptr, true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7858,7 +7844,7 @@ instruct compareAndExchangeS4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iR
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgh(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, R0,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- noreg, true);
+ noreg, nullptr, true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7872,7 +7858,7 @@ instruct compareAndExchangeS_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr,
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgh(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- noreg, true);
+ noreg, nullptr, true);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ isync();
} else {
@@ -7892,7 +7878,7 @@ instruct compareAndExchangeS4_acq_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgh(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, R0,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- noreg, true);
+ noreg, nullptr, true);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ isync();
} else {
@@ -7912,7 +7898,7 @@ instruct compareAndExchangeI_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iReg
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgw(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- noreg, true);
+ noreg, nullptr, true);
%}
ins_pipe(pipe_class_default);
%}
@@ -7926,7 +7912,7 @@ instruct compareAndExchangeI_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr,
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgw(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- noreg, true);
+ noreg, nullptr, true);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ isync();
} else {
@@ -7939,28 +7925,28 @@ instruct compareAndExchangeI_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr,
instruct compareAndExchangeN_regP_regN_regN(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{
match(Set res (CompareAndExchangeN mem_ptr (Binary src1 src2)));
- predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst);
+ predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst && n->as_LoadStore()->barrier_data() == 0);
effect(TEMP_DEF res, TEMP cr0);
format %{ "CMPXCHGW $res, $mem_ptr, $src1, $src2; as narrow oop" %}
ins_encode %{
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgw(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- noreg, true);
+ noreg, nullptr, true);
%}
ins_pipe(pipe_class_default);
%}
instruct compareAndExchangeN_acq_regP_regN_regN(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{
match(Set res (CompareAndExchangeN mem_ptr (Binary src1 src2)));
- predicate(((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst);
+ predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && n->as_LoadStore()->barrier_data() == 0);
effect(TEMP_DEF res, TEMP cr0);
format %{ "CMPXCHGW acq $res, $mem_ptr, $src1, $src2; as narrow oop" %}
ins_encode %{
// CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'.
__ cmpxchgw(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register,
MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(),
- noreg, true);
+ noreg, nullptr, true);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ isync();
} else {
@@ -8262,6 +8248,7 @@ instruct getAndSetP(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src, flagsRegCR0 cr
instruct getAndSetN(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src, flagsRegCR0 cr0) %{
match(Set res (GetAndSetN mem_ptr src));
+ predicate(n->as_LoadStore()->barrier_data() == 0);
effect(TEMP_DEF res, TEMP cr0);
format %{ "GetAndSetN $res, $mem_ptr, $src" %}
ins_encode %{
@@ -12106,10 +12093,10 @@ instruct cmpFastUnlock(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp
ins_pipe(pipe_class_compare);
%}
-instruct cmpFastLockLightweight(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2) %{
+instruct cmpFastLockLightweight(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR1 cr1) %{
predicate(LockingMode == LM_LIGHTWEIGHT);
match(Set crx (FastLock oop box));
- effect(TEMP tmp1, TEMP tmp2);
+ effect(TEMP tmp1, TEMP tmp2, KILL cr1);
format %{ "FASTLOCK $oop, $box, $tmp1, $tmp2" %}
ins_encode %{
@@ -12281,7 +12268,7 @@ instruct string_equalsL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt, iRegIdst
%}
instruct array_equalsB(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result,
- iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR0 cr1) %{
+ iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR1 cr1) %{
predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL);
match(Set result (AryEq ary1 ary2));
effect(TEMP_DEF result, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0, KILL cr1);
@@ -12296,7 +12283,7 @@ instruct array_equalsB(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result,
%}
instruct array_equalsC(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result,
- iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR0 cr1) %{
+ iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR1 cr1) %{
predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU);
match(Set result (AryEq ary1 ary2));
effect(TEMP_DEF result, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0, KILL cr1);
@@ -14534,6 +14521,21 @@ instruct tailjmpInd(iRegPdstNoScratch jump_target, rarg1RegP ex_oop) %{
ins_pipe(pipe_class_call);
%}
+// Forward exception.
+instruct ForwardExceptionjmp()
+%{
+ match(ForwardException);
+ ins_cost(CALL_COST);
+
+ format %{ "Jmp forward_exception_stub" %}
+ ins_encode %{
+ __ set_inst_mark();
+ __ b64_patchable(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type);
+ __ clear_inst_mark();
+ %}
+ ins_pipe(pipe_class_call);
+%}
+
// Create exception oop: created by stack-crawling runtime code.
// Created exception is now available to this handler, and is setup
// just prior to jumping to this handler. No code emitted.
diff --git a/src/hotspot/cpu/ppc/register_ppc.hpp b/src/hotspot/cpu/ppc/register_ppc.hpp
index 302d49884fa..b7ba4f053b5 100644
--- a/src/hotspot/cpu/ppc/register_ppc.hpp
+++ b/src/hotspot/cpu/ppc/register_ppc.hpp
@@ -27,6 +27,7 @@
#define CPU_PPC_REGISTER_PPC_HPP
#include "asm/register.hpp"
+#include "utilities/count_trailing_zeros.hpp"
// forward declaration
class VMRegImpl;
@@ -555,4 +556,12 @@ constexpr Register R29_TOC = R29;
constexpr Register R11_scratch1 = R11;
constexpr Register R12_scratch2 = R12;
+template <>
+inline Register AbstractRegSet::first() {
+ if (_bitset == 0) { return noreg; }
+ return as_Register(count_trailing_zeros(_bitset));
+}
+
+typedef AbstractRegSet RegSet;
+
#endif // CPU_PPC_REGISTER_PPC_HPP
diff --git a/src/hotspot/cpu/ppc/runtime_ppc.cpp b/src/hotspot/cpu/ppc/runtime_ppc.cpp
index 8c3bfd4f37b..dbdc16ee5f1 100644
--- a/src/hotspot/cpu/ppc/runtime_ppc.cpp
+++ b/src/hotspot/cpu/ppc/runtime_ppc.cpp
@@ -99,12 +99,7 @@ void OptoRuntime::generate_exception_blob() {
__ set_last_Java_frame(/*sp=*/R1_SP, noreg);
__ mr(R3_ARG1, R16_thread);
-#if defined(ABI_ELFv2)
- __ call_c((address) OptoRuntime::handle_exception_C, relocInfo::none);
-#else
- __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, OptoRuntime::handle_exception_C),
- relocInfo::none);
-#endif
+ __ call_c((address) OptoRuntime::handle_exception_C);
address calls_return_pc = __ last_calls_return_pc();
# ifdef ASSERT
__ cmpdi(CCR0, R3_RET, 0);
diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
index 9b5a86bc45b..aa8ae6070b6 100644
--- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
+++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
@@ -44,6 +44,7 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/signature.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/timerTrace.hpp"
#include "runtime/vframeArray.hpp"
#include "utilities/align.hpp"
#include "utilities/macros.hpp"
@@ -2398,7 +2399,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
// Try fastpath for locking.
if (LockingMode == LM_LIGHTWEIGHT) {
// fast_lock kills r_temp_1, r_temp_2, r_temp_3.
- __ compiler_fast_lock_lightweight_object(CCR0, r_oop, r_temp_1, r_temp_2, r_temp_3);
+ __ compiler_fast_lock_lightweight_object(CCR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3);
} else {
// fast_lock kills r_temp_1, r_temp_2, r_temp_3.
__ compiler_fast_lock_object(CCR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3);
@@ -2443,12 +2444,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
// The JNI call
// --------------------------------------------------------------------------
-#if defined(ABI_ELFv2)
__ call_c(native_func, relocInfo::runtime_call_type);
-#else
- FunctionDescriptor* fd_native_method = (FunctionDescriptor*) native_func;
- __ call_c(fd_native_method, relocInfo::runtime_call_type);
-#endif
// Now, we are back from the native code.
@@ -2609,7 +2605,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
// Try fastpath for unlocking.
if (LockingMode == LM_LIGHTWEIGHT) {
- __ compiler_fast_unlock_lightweight_object(CCR0, r_oop, r_temp_1, r_temp_2, r_temp_3);
+ __ compiler_fast_unlock_lightweight_object(CCR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3);
} else {
__ compiler_fast_unlock_object(CCR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3);
}
@@ -2860,7 +2856,8 @@ void SharedRuntime::generate_deopt_blob() {
// Allocate space for the code
ResourceMark rm;
// Setup code generation tools
- CodeBuffer buffer("deopt_blob", 2048, 1024);
+ const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id);
+ CodeBuffer buffer(name, 2048, 1024);
InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer);
Label exec_mode_initialized;
int frame_size_in_words;
@@ -3078,7 +3075,7 @@ void SharedRuntime::generate_deopt_blob() {
}
#ifdef COMPILER2
-void SharedRuntime::generate_uncommon_trap_blob() {
+void OptoRuntime::generate_uncommon_trap_blob() {
// Allocate space for the code.
ResourceMark rm;
// Setup code generation tools.
@@ -3144,7 +3141,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
#ifdef ASSERT
__ lwz(R22_tmp2, in_bytes(Deoptimization::UnrollBlock::unpack_kind_offset()), unroll_block_reg);
__ cmpdi(CCR0, R22_tmp2, (unsigned)Deoptimization::Unpack_uncommon_trap);
- __ asm_assert_eq("SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap");
+ __ asm_assert_eq("OptoRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap");
#endif
// Freezing continuation frames requires that the caller is trimmed to unextended sp if compiled.
@@ -3210,23 +3207,25 @@ void SharedRuntime::generate_uncommon_trap_blob() {
#endif // COMPILER2
// Generate a special Compile2Runtime blob that saves all registers, and setup oopmap.
-SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) {
+SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) {
assert(StubRoutines::forward_exception_entry() != nullptr,
"must be generated before");
+ assert(is_polling_page_id(id), "expected a polling page stub id");
ResourceMark rm;
OopMapSet *oop_maps = new OopMapSet();
OopMap* map;
// Allocate space for the code. Setup code generation tools.
- CodeBuffer buffer("handler_blob", 2048, 1024);
+ const char* name = SharedRuntime::stub_name(id);
+ CodeBuffer buffer(name, 2048, 1024);
MacroAssembler* masm = new MacroAssembler(&buffer);
address start = __ pc();
int frame_size_in_bytes = 0;
RegisterSaver::ReturnPCLocation return_pc_location;
- bool cause_return = (poll_type == POLL_AT_RETURN);
+ bool cause_return = (id == SharedStubId::polling_page_return_handler_id);
if (cause_return) {
// Nothing to do here. The frame has already been popped in MachEpilogNode.
// Register LR already contains the return pc.
@@ -3236,7 +3235,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
return_pc_location = RegisterSaver::return_pc_is_thread_saved_exception_pc;
}
- bool save_vectors = (poll_type == POLL_AT_VECTOR_LOOP);
+ bool save_vectors = (id == SharedStubId::polling_page_vectors_safepoint_handler_id);
// Save registers, fpu state, and flags. Set R31 = return pc.
map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
@@ -3323,11 +3322,13 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
// but since this is generic code we don't know what they are and the caller
// must do any gc of the args.
//
-RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) {
+RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) {
+ assert(is_resolve_id(id), "expected a resolve stub id");
// allocate space for the code
ResourceMark rm;
+ const char* name = SharedRuntime::stub_name(id);
CodeBuffer buffer(name, 1000, 512);
MacroAssembler* masm = new MacroAssembler(&buffer);
@@ -3404,6 +3405,100 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha
oop_maps, true);
}
+// Continuation point for throwing of implicit exceptions that are
+// not handled in the current activation. Fabricates an exception
+// oop and initiates normal exception dispatching in this
+// frame. Only callee-saved registers are preserved (through the
+// normal register window / RegisterMap handling). If the compiler
+// needs all registers to be preserved between the fault point and
+// the exception handler then it must assume responsibility for that
+// in AbstractCompiler::continuation_for_implicit_null_exception or
+// continuation_for_implicit_division_by_zero_exception. All other
+// implicit exceptions (e.g., NullPointerException or
+// AbstractMethodError on entry) are either at call sites or
+// otherwise assume that stack unwinding will be initiated, so
+// caller saved registers were assumed volatile in the compiler.
+//
+// Note that we generate only this stub into a RuntimeStub, because
+// it needs to be properly traversed and ignored during GC, so we
+// change the meaning of the "__" macro within this method.
+//
+// Note: the routine set_pc_not_at_call_for_caller in
+// SharedRuntime.cpp requires that this code be generated into a
+// RuntimeStub.
+RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) {
+ assert(is_throw_id(id), "expected a throw stub id");
+
+ const char* name = SharedRuntime::stub_name(id);
+
+ ResourceMark rm;
+ const char* timer_msg = "SharedRuntime generate_throw_exception";
+ TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime));
+
+ CodeBuffer code(name, 1024 DEBUG_ONLY(+ 512), 0);
+ MacroAssembler* masm = new MacroAssembler(&code);
+
+ OopMapSet* oop_maps = new OopMapSet();
+ int frame_size_in_bytes = frame::native_abi_reg_args_size;
+ OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0);
+
+ address start = __ pc();
+
+ __ save_LR(R11_scratch1);
+
+ // Push a frame.
+ __ push_frame_reg_args(0, R11_scratch1);
+
+ address frame_complete_pc = __ pc();
+
+ // Note that we always have a runtime stub frame on the top of
+ // stack by this point. Remember the offset of the instruction
+ // whose address will be moved to R11_scratch1.
+ address gc_map_pc = __ get_PC_trash_LR(R11_scratch1);
+
+ __ set_last_Java_frame(/*sp*/R1_SP, /*pc*/R11_scratch1);
+
+ __ mr(R3_ARG1, R16_thread);
+ __ call_c(runtime_entry);
+
+ // Set an oopmap for the call site.
+ oop_maps->add_gc_map((int)(gc_map_pc - start), map);
+
+ __ reset_last_Java_frame();
+
+#ifdef ASSERT
+ // Make sure that this code is only executed if there is a pending
+ // exception.
+ {
+ Label L;
+ __ ld(R0,
+ in_bytes(Thread::pending_exception_offset()),
+ R16_thread);
+ __ cmpdi(CCR0, R0, 0);
+ __ bne(CCR0, L);
+ __ stop("SharedRuntime::throw_exception: no pending exception");
+ __ bind(L);
+ }
+#endif
+
+ // Pop frame.
+ __ pop_frame();
+
+ __ restore_LR(R11_scratch1);
+
+ __ load_const(R11_scratch1, StubRoutines::forward_exception_entry());
+ __ mtctr(R11_scratch1);
+ __ bctr();
+
+ // Create runtime stub with OopMap.
+ RuntimeStub* stub =
+ RuntimeStub::new_runtime_stub(name, &code,
+ /*frame_complete=*/ (int)(frame_complete_pc - start),
+ frame_size_in_bytes/wordSize,
+ oop_maps,
+ false);
+ return stub;
+}
//------------------------------Montgomery multiplication------------------------
//
@@ -3647,3 +3742,81 @@ void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints,
reverse_words(m, (unsigned long *)m_ints, longwords);
}
+
+#if INCLUDE_JFR
+
+// For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
+// It returns a jobject handle to the event writer.
+// The handle is dereferenced and the return value is the event writer oop.
+RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() {
+ const char* name = SharedRuntime::stub_name(SharedStubId::jfr_write_checkpoint_id);
+ CodeBuffer code(name, 512, 64);
+ MacroAssembler* masm = new MacroAssembler(&code);
+
+ Register tmp1 = R10_ARG8;
+ Register tmp2 = R9_ARG7;
+
+ int framesize = frame::native_abi_reg_args_size / VMRegImpl::stack_slot_size;
+ address start = __ pc();
+ __ mflr(tmp1);
+ __ std(tmp1, _abi0(lr), R1_SP); // save return pc
+ __ push_frame_reg_args(0, tmp1);
+ int frame_complete = __ pc() - start;
+ __ set_last_Java_frame(R1_SP, noreg);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), R16_thread);
+ address calls_return_pc = __ last_calls_return_pc();
+ __ reset_last_Java_frame();
+ // The handle is dereferenced through a load barrier.
+ __ resolve_global_jobject(R3_RET, tmp1, tmp2, MacroAssembler::PRESERVATION_NONE);
+ __ pop_frame();
+ __ ld(tmp1, _abi0(lr), R1_SP);
+ __ mtlr(tmp1);
+ __ blr();
+
+ OopMapSet* oop_maps = new OopMapSet();
+ OopMap* map = new OopMap(framesize, 0);
+ oop_maps->add_gc_map(calls_return_pc - start, map);
+
+ RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
+ RuntimeStub::new_runtime_stub(name, &code, frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps, false);
+ return stub;
+}
+
+// For c2: call to return a leased buffer.
+RuntimeStub* SharedRuntime::generate_jfr_return_lease() {
+ const char* name = SharedRuntime::stub_name(SharedStubId::jfr_return_lease_id);
+ CodeBuffer code(name, 512, 64);
+ MacroAssembler* masm = new MacroAssembler(&code);
+
+ Register tmp1 = R10_ARG8;
+ Register tmp2 = R9_ARG7;
+
+ int framesize = frame::native_abi_reg_args_size / VMRegImpl::stack_slot_size;
+ address start = __ pc();
+ __ mflr(tmp1);
+ __ std(tmp1, _abi0(lr), R1_SP); // save return pc
+ __ push_frame_reg_args(0, tmp1);
+ int frame_complete = __ pc() - start;
+ __ set_last_Java_frame(R1_SP, noreg);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), R16_thread);
+ address calls_return_pc = __ last_calls_return_pc();
+ __ reset_last_Java_frame();
+ __ pop_frame();
+ __ ld(tmp1, _abi0(lr), R1_SP);
+ __ mtlr(tmp1);
+ __ blr();
+
+ OopMapSet* oop_maps = new OopMapSet();
+ OopMap* map = new OopMap(framesize, 0);
+ oop_maps->add_gc_map(calls_return_pc - start, map);
+
+ RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
+ RuntimeStub::new_runtime_stub(name, &code, frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps, false);
+ return stub;
+}
+
+#endif // INCLUDE_JFR
diff --git a/src/hotspot/cpu/ppc/smallRegisterMap_ppc.inline.hpp b/src/hotspot/cpu/ppc/smallRegisterMap_ppc.inline.hpp
index 8c96f51fd88..a6246cd7e74 100644
--- a/src/hotspot/cpu/ppc/smallRegisterMap_ppc.inline.hpp
+++ b/src/hotspot/cpu/ppc/smallRegisterMap_ppc.inline.hpp
@@ -30,9 +30,16 @@
// Java frames don't have callee saved registers, so we can use a smaller RegisterMap
class SmallRegisterMap {
+ constexpr SmallRegisterMap() = default;
+ ~SmallRegisterMap() = default;
+ NONCOPYABLE(SmallRegisterMap);
+
public:
- static constexpr SmallRegisterMap* instance = nullptr;
-public:
+ static const SmallRegisterMap* instance() {
+ static constexpr SmallRegisterMap the_instance{};
+ return &the_instance;
+ }
+
// as_RegisterMap is used when we didn't want to templatize and abstract over RegisterMap type to support SmallRegisterMap
// Consider enhancing SmallRegisterMap to support those cases
const RegisterMap* as_RegisterMap() const { return nullptr; }
@@ -44,19 +51,6 @@ class SmallRegisterMap {
return map;
}
- SmallRegisterMap() {}
-
- SmallRegisterMap(const RegisterMap* map) {
-#ifdef ASSERT
- for(int i = 0; i < RegisterMap::reg_count; i++) {
- VMReg r = VMRegImpl::as_VMReg(i);
- if (map->location(r, (intptr_t*)nullptr) != nullptr) {
- assert(false, "Reg: %s", r->name()); // Should not reach here
- }
- }
-#endif
- }
-
inline address location(VMReg reg, intptr_t* sp) const {
assert(false, "Reg: %s", reg->name());
return nullptr;
diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp
index 8da7cf7e791..206c161287f 100644
--- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp
+++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp
@@ -517,109 +517,6 @@ class StubGenerator: public StubCodeGenerator {
}
#undef __
-#define __ masm->
- // Continuation point for throwing of implicit exceptions that are
- // not handled in the current activation. Fabricates an exception
- // oop and initiates normal exception dispatching in this
- // frame. Only callee-saved registers are preserved (through the
- // normal register window / RegisterMap handling). If the compiler
- // needs all registers to be preserved between the fault point and
- // the exception handler then it must assume responsibility for that
- // in AbstractCompiler::continuation_for_implicit_null_exception or
- // continuation_for_implicit_division_by_zero_exception. All other
- // implicit exceptions (e.g., NullPointerException or
- // AbstractMethodError on entry) are either at call sites or
- // otherwise assume that stack unwinding will be initiated, so
- // caller saved registers were assumed volatile in the compiler.
- //
- // Note that we generate only this stub into a RuntimeStub, because
- // it needs to be properly traversed and ignored during GC, so we
- // change the meaning of the "__" macro within this method.
- //
- // Note: the routine set_pc_not_at_call_for_caller in
- // SharedRuntime.cpp requires that this code be generated into a
- // RuntimeStub.
- address generate_throw_exception(const char* name, address runtime_entry, bool restore_saved_exception_pc,
- Register arg1 = noreg, Register arg2 = noreg) {
- CodeBuffer code(name, 1024 DEBUG_ONLY(+ 512), 0);
- MacroAssembler* masm = new MacroAssembler(&code);
-
- OopMapSet* oop_maps = new OopMapSet();
- int frame_size_in_bytes = frame::native_abi_reg_args_size;
- OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0);
-
- address start = __ pc();
-
- __ save_LR(R11_scratch1);
-
- // Push a frame.
- __ push_frame_reg_args(0, R11_scratch1);
-
- address frame_complete_pc = __ pc();
-
- if (restore_saved_exception_pc) {
- __ unimplemented("StubGenerator::throw_exception with restore_saved_exception_pc");
- }
-
- // Note that we always have a runtime stub frame on the top of
- // stack by this point. Remember the offset of the instruction
- // whose address will be moved to R11_scratch1.
- address gc_map_pc = __ get_PC_trash_LR(R11_scratch1);
-
- __ set_last_Java_frame(/*sp*/R1_SP, /*pc*/R11_scratch1);
-
- __ mr(R3_ARG1, R16_thread);
- if (arg1 != noreg) {
- __ mr(R4_ARG2, arg1);
- }
- if (arg2 != noreg) {
- __ mr(R5_ARG3, arg2);
- }
-#if defined(ABI_ELFv2)
- __ call_c(runtime_entry, relocInfo::none);
-#else
- __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry), relocInfo::none);
-#endif
-
- // Set an oopmap for the call site.
- oop_maps->add_gc_map((int)(gc_map_pc - start), map);
-
- __ reset_last_Java_frame();
-
-#ifdef ASSERT
- // Make sure that this code is only executed if there is a pending
- // exception.
- {
- Label L;
- __ ld(R0,
- in_bytes(Thread::pending_exception_offset()),
- R16_thread);
- __ cmpdi(CCR0, R0, 0);
- __ bne(CCR0, L);
- __ stop("StubRoutines::throw_exception: no pending exception");
- __ bind(L);
- }
-#endif
-
- // Pop frame.
- __ pop_frame();
-
- __ restore_LR(R11_scratch1);
-
- __ load_const(R11_scratch1, StubRoutines::forward_exception_entry());
- __ mtctr(R11_scratch1);
- __ bctr();
-
- // Create runtime stub with OopMap.
- RuntimeStub* stub =
- RuntimeStub::new_runtime_stub(name, &code,
- /*frame_complete=*/ (int)(frame_complete_pc - start),
- frame_size_in_bytes/wordSize,
- oop_maps,
- false);
- return stub->entry_point();
- }
-#undef __
#define __ _masm->
@@ -4616,7 +4513,7 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) {
Label thaw_success;
__ cmpdi(CCR0, R3_RET, 0);
__ bne(CCR0, thaw_success);
- __ load_const_optimized(tmp1, (StubRoutines::throw_StackOverflowError_entry()), R0);
+ __ load_const_optimized(tmp1, (SharedRuntime::throw_StackOverflowError_entry()), R0);
__ mtctr(tmp1); __ bctr();
__ bind(thaw_success);
@@ -4675,84 +4572,6 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) {
return generate_cont_thaw("Cont thaw return barrier exception", Continuation::thaw_return_barrier_exception);
}
-#if INCLUDE_JFR
-
- // For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
- // It returns a jobject handle to the event writer.
- // The handle is dereferenced and the return value is the event writer oop.
- RuntimeStub* generate_jfr_write_checkpoint() {
- CodeBuffer code("jfr_write_checkpoint", 512, 64);
- MacroAssembler* _masm = new MacroAssembler(&code);
-
- Register tmp1 = R10_ARG8;
- Register tmp2 = R9_ARG7;
-
- int framesize = frame::native_abi_reg_args_size / VMRegImpl::stack_slot_size;
- address start = __ pc();
- __ mflr(tmp1);
- __ std(tmp1, _abi0(lr), R1_SP); // save return pc
- __ push_frame_reg_args(0, tmp1);
- int frame_complete = __ pc() - start;
- __ set_last_Java_frame(R1_SP, noreg);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), R16_thread);
- address calls_return_pc = __ last_calls_return_pc();
- __ reset_last_Java_frame();
- // The handle is dereferenced through a load barrier.
- __ resolve_global_jobject(R3_RET, tmp1, tmp2, MacroAssembler::PRESERVATION_NONE);
- __ pop_frame();
- __ ld(tmp1, _abi0(lr), R1_SP);
- __ mtlr(tmp1);
- __ blr();
-
- OopMapSet* oop_maps = new OopMapSet();
- OopMap* map = new OopMap(framesize, 0);
- oop_maps->add_gc_map(calls_return_pc - start, map);
-
- RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
- RuntimeStub::new_runtime_stub(code.name(),
- &code, frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps, false);
- return stub;
- }
-
- // For c2: call to return a leased buffer.
- RuntimeStub* generate_jfr_return_lease() {
- CodeBuffer code("jfr_return_lease", 512, 64);
- MacroAssembler* _masm = new MacroAssembler(&code);
-
- Register tmp1 = R10_ARG8;
- Register tmp2 = R9_ARG7;
-
- int framesize = frame::native_abi_reg_args_size / VMRegImpl::stack_slot_size;
- address start = __ pc();
- __ mflr(tmp1);
- __ std(tmp1, _abi0(lr), R1_SP); // save return pc
- __ push_frame_reg_args(0, tmp1);
- int frame_complete = __ pc() - start;
- __ set_last_Java_frame(R1_SP, noreg);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), R16_thread);
- address calls_return_pc = __ last_calls_return_pc();
- __ reset_last_Java_frame();
- __ pop_frame();
- __ ld(tmp1, _abi0(lr), R1_SP);
- __ mtlr(tmp1);
- __ blr();
-
- OopMapSet* oop_maps = new OopMapSet();
- OopMap* map = new OopMap(framesize, 0);
- oop_maps->add_gc_map(calls_return_pc - start, map);
-
- RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
- RuntimeStub::new_runtime_stub(code.name(),
- &code, frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps, false);
- return stub;
- }
-
-#endif // INCLUDE_JFR
-
// exception handler for upcall stubs
address generate_upcall_stub_exception_handler() {
StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler");
@@ -4768,6 +4587,30 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) {
return start;
}
+ // load Method* target of MethodHandle
+ // R3_ARG1 = jobject receiver
+ // R19_method = result Method*
+ address generate_upcall_stub_load_target() {
+
+ StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target");
+ address start = __ pc();
+
+ __ resolve_global_jobject(R3_ARG1, R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS);
+ // Load target method from receiver
+ __ load_heap_oop(R19_method, java_lang_invoke_MethodHandle::form_offset(), R3_ARG1,
+ R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS, IS_NOT_NULL);
+ __ load_heap_oop(R19_method, java_lang_invoke_LambdaForm::vmentry_offset(), R19_method,
+ R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS, IS_NOT_NULL);
+ __ load_heap_oop(R19_method, java_lang_invoke_MemberName::method_offset(), R19_method,
+ R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS, IS_NOT_NULL);
+ __ ld(R19_method, java_lang_invoke_ResolvedMethodName::vmtarget_offset(), R19_method);
+ __ std(R19_method, in_bytes(JavaThread::callee_target_offset()), R16_thread); // just in case callee is deoptimized
+
+ __ blr();
+
+ return start;
+ }
+
// Initialization
void generate_initial_stubs() {
// Generates all stubs and initializes the entry points
@@ -4786,14 +4629,6 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) {
UnsafeMemoryAccess::create_table(8 + 4); // 8 for copyMemory; 4 for setMemory
}
- // Build this early so it's available for the interpreter.
- StubRoutines::_throw_StackOverflowError_entry =
- generate_throw_exception("StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false);
- StubRoutines::_throw_delayed_StackOverflowError_entry =
- generate_throw_exception("delayed StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError), false);
-
// CRC32 Intrinsics.
if (UseCRC32Intrinsics) {
StubRoutines::_crc_table_adr = StubRoutines::ppc::generate_crc_constants(REVERSE_CRC32_POLY);
@@ -4812,29 +4647,11 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) {
StubRoutines::_cont_thaw = generate_cont_thaw();
StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier();
StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception();
-
- JFR_ONLY(generate_jfr_stubs();)
- }
-
-#if INCLUDE_JFR
- void generate_jfr_stubs() {
- StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint();
- StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point();
- StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease();
- StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point();
}
-#endif // INCLUDE_JFR
void generate_final_stubs() {
// Generates all stubs and initializes the entry points
- // These entry points require SharedInfo::stack0 to be set up in
- // non-core builds
- StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError), false);
- // Handle IncompatibleClassChangeError in itable stubs.
- StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false);
- StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false);
-
// support for verify_oop (must happen after universe_init)
StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop();
@@ -4858,6 +4675,7 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) {
}
StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler();
+ StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target();
}
void generate_compiler_stubs() {
diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp
index 4caae200253..cf3dd4cbd34 100644
--- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp
+++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp
@@ -783,8 +783,8 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rmem_f
__ bgt(CCR0/*is_stack_overflow*/, done);
// The stack overflows. Load target address of the runtime stub and call it.
- assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "generated in wrong order");
- __ load_const_optimized(Rscratch1, (StubRoutines::throw_StackOverflowError_entry()), R0);
+ assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "generated in wrong order");
+ __ load_const_optimized(Rscratch1, (SharedRuntime::throw_StackOverflowError_entry()), R0);
__ mtctr(Rscratch1);
// Restore caller_sp (c2i adapter may exist, but no shrinking of interpreted caller frame).
#ifdef ASSERT
@@ -1078,6 +1078,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
case Interpreter::java_lang_math_sin : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin); break;
case Interpreter::java_lang_math_cos : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos); break;
case Interpreter::java_lang_math_tan : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan); break;
+ case Interpreter::java_lang_math_tanh : /* run interpreted */ break;
case Interpreter::java_lang_math_abs : /* run interpreted */ break;
case Interpreter::java_lang_math_sqrt : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsqrt); break;
case Interpreter::java_lang_math_log : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog); break;
@@ -1464,13 +1465,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
// native result across the call. No oop is present.
__ mr(R3_ARG1, R16_thread);
-#if defined(ABI_ELFv2)
- __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans),
- relocInfo::none);
-#else
- __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans),
- relocInfo::none);
-#endif
+ __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans));
__ bind(sync_check_done);
diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp
index 0ee9348dde8..a55f30eb67d 100644
--- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp
+++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp
@@ -2130,8 +2130,8 @@ void TemplateTable::_return(TosState state) {
// Load klass of this obj.
__ load_klass(Rklass, R17_tos);
- __ lwz(Rklass_flags, in_bytes(Klass::access_flags_offset()), Rklass);
- __ testbitdi(CCR0, R0, Rklass_flags, exact_log2(JVM_ACC_HAS_FINALIZER));
+ __ lbz(Rklass_flags, in_bytes(Klass::misc_flags_offset()), Rklass);
+ __ testbitdi(CCR0, R0, Rklass_flags, exact_log2(KlassFlags::_misc_has_finalizer));
__ bfalse(CCR0, Lskip_register_finalizer);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), R17_tos /* obj */);
diff --git a/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp b/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp
index b60fd4f16d1..635bab900d1 100644
--- a/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp
+++ b/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
+#include "classfile/javaClasses.hpp"
#include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
#include "prims/upcallLinker.hpp"
@@ -118,7 +119,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr
static const int upcall_stub_code_base_size = 1024;
static const int upcall_stub_size_per_arg = 16; // arg save & restore + move
-address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
+address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
@@ -221,7 +222,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
__ block_comment("{ on_entry");
__ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry), R0);
__ addi(R3_ARG1, R1_SP, frame_data_offset);
- __ load_const_optimized(R4_ARG2, (intptr_t)receiver, R0);
__ call_c(call_target_address);
__ mr(R16_thread, R3_RET);
__ block_comment("} on_entry");
@@ -236,12 +236,12 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
arg_shuffle.generate(_masm, as_VMStorage(callerSP), frame::native_abi_minframe_size, frame::jit_out_preserve_size);
__ block_comment("} argument shuffle");
- __ block_comment("{ receiver ");
- __ get_vm_result(R3_ARG1);
- __ block_comment("} receiver ");
-
- __ load_const_optimized(R19_method, (intptr_t)entry);
- __ std(R19_method, in_bytes(JavaThread::callee_target_offset()), R16_thread);
+ __ block_comment("{ load target ");
+ __ load_const_optimized(call_target_address, StubRoutines::upcall_stub_load_target(), R0);
+ __ load_const_optimized(R3_ARG1, (intptr_t)receiver, R0);
+ __ mtctr(call_target_address);
+ __ bctrl(); // loads target Method* into R19_method
+ __ block_comment("} load target ");
__ push_cont_fastpath();
@@ -326,7 +326,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
#ifndef PRODUCT
stringStream ss;
- ss.print("upcall_stub_%s", entry->signature()->as_C_string());
+ ss.print("upcall_stub_%s", signature->as_C_string());
const char* name = _masm->code_string(ss.as_string());
#else // PRODUCT
const char* name = "upcall_stub";
diff --git a/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp b/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp
index 28ba04d833b..1e6f748dec8 100644
--- a/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp
+++ b/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp
@@ -195,7 +195,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
#ifndef PRODUCT
if (DebugVtables) {
Label ok;
- __ cmpd(CCR0, R19_method, 0);
+ __ cmpdi(CCR0, R19_method, 0);
__ bne(CCR0, ok);
__ stop("method is null");
__ bind(ok);
diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp
index e4280ab34e1..23046419460 100644
--- a/src/hotspot/cpu/riscv/assembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp
@@ -46,8 +46,10 @@
class Argument {
public:
enum {
- n_int_register_parameters_c = 8, // x10, x11, ... x17 (c_rarg0, c_rarg1, ...)
- n_float_register_parameters_c = 8, // f10, f11, ... f17 (c_farg0, c_farg1, ... )
+ // check more info at https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc
+ n_int_register_parameters_c = 8, // x10, x11, ... x17 (c_rarg0, c_rarg1, ...)
+ n_float_register_parameters_c = 8, // f10, f11, ... f17 (c_farg0, c_farg1, ... )
+ n_vector_register_parameters_c = 16, // v8, v9, ... v23
n_int_register_parameters_j = 8, // x11, ... x17, x10 (j_rarg0, j_rarg1, ...)
n_float_register_parameters_j = 8 // f10, f11, ... f17 (j_farg0, j_farg1, ...)
@@ -143,6 +145,10 @@ constexpr Register x19_sender_sp = x19; // Sender's SP while in interpreter
constexpr Register t0 = x5;
constexpr Register t1 = x6;
constexpr Register t2 = x7;
+constexpr Register t3 = x28;
+constexpr Register t4 = x29;
+constexpr Register t5 = x30;
+constexpr Register t6 = x31;
const Register g_INTArgReg[Argument::n_int_register_parameters_c] = {
c_rarg0, c_rarg1, c_rarg2, c_rarg3, c_rarg4, c_rarg5, c_rarg6, c_rarg7
@@ -705,6 +711,16 @@ class Assembler : public AbstractAssembler {
emit(insn);
}
+ void fencei() {
+ unsigned insn = 0;
+ patch((address)&insn, 6, 0, 0b0001111); // opcode
+ patch((address)&insn, 11, 7, 0b00000); // rd
+ patch((address)&insn, 14, 12, 0b001); // func
+ patch((address)&insn, 19, 15, 0b00000); // rs1
+ patch((address)&insn, 31, 20, 0b000000000000); // fm
+ emit(insn);
+ }
+
#define INSN(NAME, op, funct3, funct7) \
void NAME() { \
unsigned insn = 0; \
@@ -1267,6 +1283,7 @@ enum VectorMask {
INSN(viota_m, 0b1010111, 0b010, 0b10000, 0b010100);
// Vector Single-Width Floating-Point/Integer Type-Convert Instructions
+ INSN(vfcvt_x_f_v, 0b1010111, 0b001, 0b00001, 0b010010);
INSN(vfcvt_f_x_v, 0b1010111, 0b001, 0b00011, 0b010010);
INSN(vfcvt_rtz_x_f_v, 0b1010111, 0b001, 0b00111, 0b010010);
@@ -1828,6 +1845,21 @@ enum Nf {
#undef INSN
+#define INSN(NAME, op, width, umop, mop, mew, nf) \
+ void NAME(VectorRegister Vd_or_Vs3, Register Rs1, VectorMask vm = unmasked) { \
+ patch_VLdSt(op, Vd_or_Vs3, width, Rs1, umop, vm, mop, mew, nf); \
+ }
+
+ // Vector Unit-Stride Segment Load Instructions
+ INSN(vlseg3e8_v, 0b0000111, 0b000, 0b00000, 0b00, 0b0, g3);
+ INSN(vlseg4e8_v, 0b0000111, 0b000, 0b00000, 0b00, 0b0, g4);
+
+ // Vector Unit-Stride Segment Store Instructions
+ INSN(vsseg3e8_v, 0b0100111, 0b000, 0b00000, 0b00, 0b0, g3);
+ INSN(vsseg4e8_v, 0b0100111, 0b000, 0b00000, 0b00, 0b0, g4);
+
+#undef INSN
+
#define INSN(NAME, op, width, mop, mew) \
void NAME(VectorRegister Vd, Register Rs1, VectorRegister Vs2, VectorMask vm = unmasked, Nf nf = g1) { \
patch_VLdSt(op, Vd, width, Rs1, Vs2->raw_encoding(), vm, mop, mew, nf); \
@@ -2860,8 +2892,9 @@ enum Nf {
// Unconditional branch instructions
// --------------------------
protected:
- // All calls and jumps must go via MASM.
+ // All calls and jumps must go via MASM. Only use x1 (aka ra) as link register for now.
void jalr(Register Rd, Register Rs, const int32_t offset) {
+ assert(Rd != x5 && Rs != x5, "Register x5 must not be used for calls/jumps.");
/* jalr -> c.jr/c.jalr */
if (do_compress() && (offset == 0 && Rs != x0)) {
if (Rd == x1) {
@@ -2876,6 +2909,7 @@ enum Nf {
}
void jal(Register Rd, const int32_t offset) {
+ assert(Rd != x5, "Register x5 must not be used for calls/jumps.");
/* jal -> c.j, note c.jal is RV32C only */
if (do_compress() &&
Rd == x0 &&
@@ -2883,7 +2917,6 @@ enum Nf {
c_j(offset);
return;
}
-
_jal(Rd, offset);
}
diff --git a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp
index b7e1b7863ef..c5764bcebf7 100644
--- a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -62,7 +62,7 @@ void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
__ mov_metadata(t0, m);
ce->store_parameter(t0, 1);
ce->store_parameter(_bci, 0);
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::counter_overflow_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::counter_overflow_id)));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
__ j(_continuation);
@@ -71,7 +71,7 @@ void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
void RangeCheckStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
if (_info->deoptimize_on_exception()) {
- address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ address a = Runtime1::entry_for(C1StubId::predicate_failed_trap_id);
__ far_call(RuntimeAddress(a));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
@@ -84,16 +84,16 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
} else {
__ mv(t0, _index->as_jint());
}
- Runtime1::StubID stub_id;
+ C1StubId stub_id;
if (_throw_index_out_of_bounds_exception) {
- stub_id = Runtime1::throw_index_exception_id;
+ stub_id = C1StubId::throw_index_exception_id;
} else {
assert(_array != LIR_Opr::nullOpr(), "sanity");
__ mv(t1, _array->as_pointer_register());
- stub_id = Runtime1::throw_range_check_failed_id;
+ stub_id = C1StubId::throw_range_check_failed_id;
}
// t0 and t1 are used as args in generate_exception_throw,
- // so use ra as the tmp register for rt_call.
+ // so use x1/ra as the tmp register for rt_call.
__ rt_call(Runtime1::entry_for(stub_id), ra);
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
@@ -106,7 +106,7 @@ PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ address a = Runtime1::entry_for(C1StubId::predicate_failed_trap_id);
__ far_call(RuntimeAddress(a));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
@@ -118,7 +118,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) {
ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
}
__ bind(_entry);
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::throw_div0_exception_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::throw_div0_exception_id)));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
#ifdef ASSERT
@@ -127,14 +127,14 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) {
}
// Implementation of NewInstanceStub
-NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) {
+NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, C1StubId stub_id) {
_result = result;
_klass = klass;
_klass_reg = klass_reg;
_info = new CodeEmitInfo(info);
- assert(stub_id == Runtime1::new_instance_id ||
- stub_id == Runtime1::fast_new_instance_id ||
- stub_id == Runtime1::fast_new_instance_init_check_id,
+ assert(stub_id == C1StubId::new_instance_id ||
+ stub_id == C1StubId::fast_new_instance_id ||
+ stub_id == C1StubId::fast_new_instance_init_check_id,
"need new_instance id");
_stub_id = stub_id;
}
@@ -163,7 +163,7 @@ void NewTypeArrayStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
assert(_length->as_register() == x9, "length must in x9");
assert(_klass_reg->as_register() == x13, "klass_reg must in x13");
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_type_array_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::new_type_array_id)));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
assert(_result->as_register() == x10, "result must in x10");
@@ -183,7 +183,7 @@ void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
assert(_length->as_register() == x9, "length must in x9");
assert(_klass_reg->as_register() == x13, "klass_reg must in x13");
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_object_array_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::new_object_array_id)));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
assert(_result->as_register() == x10, "result must in x10");
@@ -195,11 +195,11 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
ce->store_parameter(_obj_reg->as_register(), 1);
ce->store_parameter(_lock_reg->as_register(), 0);
- Runtime1::StubID enter_id;
+ C1StubId enter_id;
if (ce->compilation()->has_fpu_code()) {
- enter_id = Runtime1::monitorenter_id;
+ enter_id = C1StubId::monitorenter_id;
} else {
- enter_id = Runtime1::monitorenter_nofpu_id;
+ enter_id = C1StubId::monitorenter_nofpu_id;
}
__ far_call(RuntimeAddress(Runtime1::entry_for(enter_id)));
ce->add_call_info_here(_info);
@@ -215,11 +215,11 @@ void MonitorExitStub::emit_code(LIR_Assembler* ce) {
}
ce->store_parameter(_lock_reg->as_register(), 0);
// note: non-blocking leaf routine => no call info needed
- Runtime1::StubID exit_id;
+ C1StubId exit_id;
if (ce->compilation()->has_fpu_code()) {
- exit_id = Runtime1::monitorexit_id;
+ exit_id = C1StubId::monitorexit_id;
} else {
- exit_id = Runtime1::monitorexit_nofpu_id;
+ exit_id = C1StubId::monitorexit_nofpu_id;
}
__ la(ra, _continuation);
__ far_jump(RuntimeAddress(Runtime1::entry_for(exit_id)));
@@ -244,7 +244,7 @@ void PatchingStub::emit_code(LIR_Assembler* ce) {
void DeoptimizeStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
ce->store_parameter(_trap_request, 0);
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::deoptimize_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::deoptimize_id)));
ce->add_call_info_here(_info);
DEBUG_ONLY(__ should_not_reach_here());
}
@@ -253,9 +253,9 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
address a = nullptr;
if (_info->deoptimize_on_exception()) {
// Deoptimize, do not throw the exception, because it is probably wrong to do it here.
- a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ a = Runtime1::entry_for(C1StubId::predicate_failed_trap_id);
} else {
- a = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id);
+ a = Runtime1::entry_for(C1StubId::throw_null_pointer_exception_id);
}
ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
@@ -275,7 +275,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) {
if (_obj->is_cpu_register()) {
__ mv(t0, _obj->as_register());
}
- __ far_call(RuntimeAddress(Runtime1::entry_for(_stub)), t1);
+ __ far_call(RuntimeAddress(Runtime1::entry_for(_stub)));
ce->add_call_info_here(_info);
debug_only(__ should_not_reach_here());
}
diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp
index a8f260acae8..01293218938 100644
--- a/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.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) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -223,7 +223,7 @@ void LIR_Assembler::arraycopy_type_check(Register src, Register src_pos, Registe
__ check_klass_subtype_fast_path(src, dst, tmp, &cont, &slow, nullptr);
PUSH(src, dst);
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::slow_subtype_check_id)));
POP(src, dst);
__ bnez(dst, cont);
diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp
index 798679185d3..828f70e4dec 100644
--- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp
@@ -305,7 +305,7 @@ int LIR_Assembler::emit_exception_handler() {
__ verify_not_null_oop(x10);
// search an exception handler (x10: exception oop, x13: throwing pc)
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::handle_exception_from_callee_id)));
__ should_not_reach_here();
guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
__ end_a_stub();
@@ -361,7 +361,7 @@ int LIR_Assembler::emit_unwind_handler() {
// remove the activation and dispatch to the unwind handler
__ block_comment("remove_frame and dispatch to the unwind handler");
__ remove_frame(initial_frame_size_in_bytes());
- __ far_jump(RuntimeAddress(Runtime1::entry_for(Runtime1::unwind_exception_id)));
+ __ far_jump(RuntimeAddress(Runtime1::entry_for(C1StubId::unwind_exception_id)));
// Emit the slow path assembly
if (stub != nullptr) {
@@ -542,7 +542,7 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi
insn = &MacroAssembler::sw; break;
case T_OBJECT: // fall through
case T_ARRAY:
- assert(c->as_jobject() == 0, "should be");
+ assert(c->as_jobject() == nullptr, "should be");
if (UseCompressedOops && !wide) {
insn = &MacroAssembler::sw;
} else {
@@ -980,6 +980,7 @@ void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) {
if (op->init_check()) {
__ lbu(t0, Address(op->klass()->as_register(),
InstanceKlass::init_state_offset()));
+ __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
__ mv(t1, (u1)InstanceKlass::fully_initialized);
add_debug_info_for_null_check_here(op->stub()->info());
__ bne(t0, t1, *op->stub()->entry(), /* is_far */ true);
@@ -1088,7 +1089,7 @@ void LIR_Assembler::typecheck_helper_slowcheck(ciKlass *k, Register obj, Registe
__ addi(sp, sp, -2 * wordSize); // 2: store k_RInfo and klass_RInfo
__ sd(k_RInfo, Address(sp, 0)); // sub klass
__ sd(klass_RInfo, Address(sp, wordSize)); // super klass
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::slow_subtype_check_id)));
// load result to k_RInfo
__ ld(k_RInfo, Address(sp, 0));
__ addi(sp, sp, 2 * wordSize); // 2: pop out k_RInfo and klass_RInfo
@@ -1103,7 +1104,7 @@ void LIR_Assembler::typecheck_helper_slowcheck(ciKlass *k, Register obj, Registe
__ addi(sp, sp, -2 * wordSize); // 2: store k_RInfo and klass_RInfo
__ sd(klass_RInfo, Address(sp, wordSize)); // sub klass
__ sd(k_RInfo, Address(sp, 0)); // super klass
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::slow_subtype_check_id)));
// load result to k_RInfo
__ ld(k_RInfo, Address(sp, 0));
__ addi(sp, sp, 2 * wordSize); // 2: pop out k_RInfo and klass_RInfo
@@ -1391,7 +1392,7 @@ void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmit
// exception object is not added to oop map by LinearScan
// (LinearScan assumes that no oops are in fixed registers)
info->add_register_oop(exceptionOop);
- Runtime1::StubID unwind_id;
+ C1StubId unwind_id;
// get current pc information
// pc is only needed if the method has an exception handler, the unwind code does not need it.
@@ -1414,9 +1415,9 @@ void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmit
__ verify_not_null_oop(x10);
// search an exception handler (x10: exception oop, x13: throwing pc)
if (compilation()->has_fpu_code()) {
- unwind_id = Runtime1::handle_exception_id;
+ unwind_id = C1StubId::handle_exception_id;
} else {
- unwind_id = Runtime1::handle_exception_nofpu_id;
+ unwind_id = C1StubId::handle_exception_nofpu_id;
}
__ far_call(RuntimeAddress(Runtime1::entry_for(unwind_id)));
__ nop();
@@ -2054,16 +2055,16 @@ void LIR_Assembler::deoptimize_trap(CodeEmitInfo *info) {
switch (patching_id(info)) {
case PatchingStub::access_field_id:
- target = Runtime1::entry_for(Runtime1::access_field_patching_id);
+ target = Runtime1::entry_for(C1StubId::access_field_patching_id);
break;
case PatchingStub::load_klass_id:
- target = Runtime1::entry_for(Runtime1::load_klass_patching_id);
+ target = Runtime1::entry_for(C1StubId::load_klass_patching_id);
break;
case PatchingStub::load_mirror_id:
- target = Runtime1::entry_for(Runtime1::load_mirror_patching_id);
+ target = Runtime1::entry_for(C1StubId::load_mirror_patching_id);
break;
case PatchingStub::load_appendix_id:
- target = Runtime1::entry_for(Runtime1::load_appendix_patching_id);
+ target = Runtime1::entry_for(C1StubId::load_appendix_patching_id);
break;
default: ShouldNotReachHere();
}
@@ -2152,7 +2153,7 @@ void LIR_Assembler::lir_store_slowcheck(Register k_RInfo, Register klass_RInfo,
__ addi(sp, sp, -2 * wordSize); // 2: store k_RInfo and klass_RInfo
__ sd(klass_RInfo, Address(sp, wordSize)); // sub klass
__ sd(k_RInfo, Address(sp, 0)); // super klass
- __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
+ __ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::slow_subtype_check_id)));
// load result to k_RInfo
__ ld(k_RInfo, Address(sp, 0));
__ addi(sp, sp, 2 * wordSize); // 2: pop out k_RInfo and klass_RInfo
diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp
index 4388d0cf4d7..4ce7eb2bf73 100644
--- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp
@@ -62,8 +62,6 @@ friend class ArrayCopyStub;
void caswu(Register addr, Register newval, Register cmpval);
void casl(Register addr, Register newval, Register cmpval);
- void poll_for_safepoint(relocInfo::relocType rtype, CodeEmitInfo* info = nullptr);
-
void deoptimize_trap(CodeEmitInfo *info);
enum {
diff --git a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp
index 409e8dc0a0d..b328d457192 100644
--- a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.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.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -1030,7 +1030,7 @@ void LIRGenerator::do_NewMultiArray(NewMultiArray* x) {
args->append(rank);
args->append(varargs);
LIR_Opr reg = result_register_for(x->type());
- __ call_runtime(Runtime1::entry_for(Runtime1::new_multi_array_id),
+ __ call_runtime(Runtime1::entry_for(C1StubId::new_multi_array_id),
LIR_OprFact::illegalOpr,
reg, args, info);
@@ -1062,7 +1062,7 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
CodeStub* stub = nullptr;
if (x->is_incompatible_class_change_check()) {
assert(patching_info == nullptr, "can't patch this");
- stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr,
+ stub = new SimpleExceptionStub(C1StubId::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr,
info_for_exception);
} else if (x->is_invokespecial_receiver_check()) {
assert(patching_info == nullptr, "can't patch this");
@@ -1070,7 +1070,7 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
Deoptimization::Reason_class_check,
Deoptimization::Action_none);
} else {
- stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception);
+ stub = new SimpleExceptionStub(C1StubId::throw_class_cast_exception_id, obj.result(), info_for_exception);
}
LIR_Opr reg = rlock_result(x);
LIR_Opr tmp3 = LIR_OprFact::illegalOpr;
diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp
index 547e80c7e47..1e4b66069ee 100644
--- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp
@@ -64,13 +64,13 @@ 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(temp, hdr, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
+ lbu(hdr, Address(hdr, Klass::misc_flags_offset()));
+ test_bit(temp, hdr, exact_log2(KlassFlags::_misc_is_value_based_class));
bnez(temp, slow_case, true /* is_far */);
}
if (LockingMode == LM_LIGHTWEIGHT) {
- lightweight_lock(obj, hdr, temp, t1, slow_case);
+ lightweight_lock(disp_hdr, obj, hdr, temp, t1, slow_case);
} else if (LockingMode == LM_LEGACY) {
Label done;
// Load object header
@@ -276,7 +276,7 @@ void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register
if (CURRENT_ENV->dtrace_alloc_probes()) {
assert(obj == x10, "must be");
- far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)));
+ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::dtrace_object_alloc_id)));
}
verify_oop(obj);
@@ -316,7 +316,7 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register tmp1
if (CURRENT_ENV->dtrace_alloc_probes()) {
assert(obj == x10, "must be");
- far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)));
+ far_call(RuntimeAddress(Runtime1::entry_for(C1StubId::dtrace_object_alloc_id)));
}
verify_oop(obj);
diff --git a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp
index 9fa8939837a..5e4031727c8 100644
--- a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -98,10 +98,10 @@ int StubAssembler::call_RT(Register oop_result, Register metadata_result, addres
if (frame_size() == no_frame_size) {
leave();
far_jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
- } else if (_stub_id == Runtime1::forward_exception_id) {
+ } else if (_stub_id == (int)C1StubId::forward_exception_id) {
should_not_reach_here();
} else {
- far_jump(RuntimeAddress(Runtime1::entry_for(Runtime1::forward_exception_id)));
+ far_jump(RuntimeAddress(Runtime1::entry_for(C1StubId::forward_exception_id)));
}
bind(L);
}
@@ -223,8 +223,6 @@ StubFrame::~StubFrame() {
#define __ sasm->
-const int float_regs_as_doubles_size_in_slots = pd_nof_fpu_regs_frame_map * 2;
-
// Stack layout for saving/restoring all the registers needed during a runtime
// call (this includes deoptimization)
// Note: note that users of this frame may well have arguments to some runtime
@@ -378,7 +376,7 @@ OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address targe
return oop_maps;
}
-OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
+OopMapSet* Runtime1::generate_handle_exception(C1StubId id, StubAssembler *sasm) {
__ block_comment("generate_handle_exception");
// incoming parameters
@@ -390,7 +388,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
OopMap* oop_map = nullptr;
switch (id) {
- case forward_exception_id:
+ case C1StubId::forward_exception_id:
// We're handling an exception in the context of a compiled frame.
// The registers have been saved in the standard places. Perform
// an exception lookup in the caller and dispatch to the handler
@@ -409,12 +407,12 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
__ sd(zr, Address(xthread, JavaThread::vm_result_offset()));
__ sd(zr, Address(xthread, JavaThread::vm_result_2_offset()));
break;
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
// At this point all registers MAY be live.
- oop_map = save_live_registers(sasm, id != handle_exception_nofpu_id);
+ oop_map = save_live_registers(sasm, id != C1StubId::handle_exception_nofpu_id);
break;
- case handle_exception_from_callee_id: {
+ case C1StubId::handle_exception_from_callee_id: {
// At this point all registers except exception oop (x10) and
// exception pc (ra) are dead.
const int frame_size = 2 /* fp, return address */;
@@ -471,13 +469,13 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
__ sd(x10, Address(fp, frame::return_addr_offset * BytesPerWord));
switch (id) {
- case forward_exception_id:
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::forward_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
// Restore the registers that were saved at the beginning.
- restore_live_registers(sasm, id != handle_exception_nofpu_id);
+ restore_live_registers(sasm, id != C1StubId::handle_exception_nofpu_id);
break;
- case handle_exception_from_callee_id:
+ case C1StubId::handle_exception_from_callee_id:
break;
default: ShouldNotReachHere();
}
@@ -623,7 +621,7 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
return oop_maps;
}
-OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
+OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) {
// for better readability
const bool dont_gc_arguments = false;
@@ -634,7 +632,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
OopMapSet* oop_maps = nullptr;
switch (id) {
{
- case forward_exception_id:
+ case C1StubId::forward_exception_id:
{
oop_maps = generate_handle_exception(id, sasm);
__ leave();
@@ -642,32 +640,32 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case throw_div0_exception_id:
+ case C1StubId::throw_div0_exception_id:
{
StubFrame f(sasm, "throw_div0_exception", dont_gc_arguments, does_not_return);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false);
}
break;
- case throw_null_pointer_exception_id:
+ case C1StubId::throw_null_pointer_exception_id:
{ StubFrame f(sasm, "throw_null_pointer_exception", dont_gc_arguments, does_not_return);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false);
}
break;
- case new_instance_id:
- case fast_new_instance_id:
- case fast_new_instance_init_check_id:
+ case C1StubId::new_instance_id:
+ case C1StubId::fast_new_instance_id:
+ case C1StubId::fast_new_instance_init_check_id:
{
Register klass = x13; // Incoming
Register obj = x10; // Result
- if (id == new_instance_id) {
+ if (id == C1StubId::new_instance_id) {
__ set_info("new_instance", dont_gc_arguments);
- } else if (id == fast_new_instance_id) {
+ } else if (id == C1StubId::fast_new_instance_id) {
__ set_info("fast new_instance", dont_gc_arguments);
} else {
- assert(id == fast_new_instance_init_check_id, "bad StubID");
+ assert(id == C1StubId::fast_new_instance_init_check_id, "bad C1StubId");
__ set_info("fast new_instance init check", dont_gc_arguments);
}
@@ -688,7 +686,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
break;
- case counter_overflow_id:
+ case C1StubId::counter_overflow_id:
{
Register bci = x10;
Register method = x11;
@@ -712,14 +710,14 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case new_type_array_id:
- case new_object_array_id:
+ case C1StubId::new_type_array_id:
+ case C1StubId::new_object_array_id:
{
Register length = x9; // Incoming
Register klass = x13; // Incoming
Register obj = x10; // Result
- if (id == new_type_array_id) {
+ if (id == C1StubId::new_type_array_id) {
__ set_info("new_type_array", dont_gc_arguments);
} else {
__ set_info("new_object_array", dont_gc_arguments);
@@ -732,7 +730,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
Register tmp = obj;
__ lwu(tmp, Address(klass, Klass::layout_helper_offset()));
__ sraiw(tmp, tmp, Klass::_lh_array_tag_shift);
- int tag = ((id == new_type_array_id) ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_obj_value);
+ int tag = ((id == C1StubId::new_type_array_id) ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_obj_value);
__ mv(t0, tag);
__ beq(t0, tmp, ok);
__ stop("assert(is an array klass)");
@@ -745,7 +743,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
OopMap* map = save_live_registers(sasm);
assert_cond(map != nullptr);
int call_offset = 0;
- if (id == new_type_array_id) {
+ if (id == C1StubId::new_type_array_id) {
call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_type_array), klass, length);
} else {
call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length);
@@ -764,7 +762,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case new_multi_array_id:
+ case C1StubId::new_multi_array_id:
{
StubFrame f(sasm, "new_multi_array", dont_gc_arguments);
// x10: klass
@@ -787,7 +785,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case register_finalizer_id:
+ case C1StubId::register_finalizer_id:
{
__ set_info("register_finalizer", dont_gc_arguments);
@@ -799,8 +797,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
Label register_finalizer;
Register t = x15;
__ load_klass(t, x10);
- __ lwu(t, Address(t, Klass::access_flags_offset()));
- __ test_bit(t0, t, exact_log2(JVM_ACC_HAS_FINALIZER));
+ __ lbu(t, Address(t, Klass::misc_flags_offset()));
+ __ test_bit(t0, t, exact_log2(KlassFlags::_misc_has_finalizer));
__ bnez(t0, register_finalizer);
__ ret();
@@ -821,14 +819,14 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case throw_class_cast_exception_id:
+ case C1StubId::throw_class_cast_exception_id:
{
StubFrame f(sasm, "throw_class_cast_exception", dont_gc_arguments, does_not_return);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true);
}
break;
- case throw_incompatible_class_change_error_id:
+ case C1StubId::throw_incompatible_class_change_error_id:
{
StubFrame f(sasm, "throw_incompatible_class_cast_exception", dont_gc_arguments, does_not_return);
oop_maps = generate_exception_throw(sasm,
@@ -836,7 +834,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case slow_subtype_check_id:
+ case C1StubId::slow_subtype_check_id:
{
// Typical calling sequence:
// push klass_RInfo (object klass or other subclass)
@@ -876,10 +874,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case monitorenter_nofpu_id:
+ case C1StubId::monitorenter_nofpu_id:
save_fpu_registers = false;
// fall through
- case monitorenter_id:
+ case C1StubId::monitorenter_id:
{
StubFrame f(sasm, "monitorenter", dont_gc_arguments);
OopMap* map = save_live_registers(sasm, save_fpu_registers);
@@ -898,10 +896,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case monitorexit_nofpu_id:
+ case C1StubId::monitorexit_nofpu_id:
save_fpu_registers = false;
// fall through
- case monitorexit_id:
+ case C1StubId::monitorexit_id:
{
StubFrame f(sasm, "monitorexit", dont_gc_arguments);
OopMap* map = save_live_registers(sasm, save_fpu_registers);
@@ -922,7 +920,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case deoptimize_id:
+ case C1StubId::deoptimize_id:
{
StubFrame f(sasm, "deoptimize", dont_gc_arguments, does_not_return);
OopMap* oop_map = save_live_registers(sasm);
@@ -941,14 +939,14 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case throw_range_check_failed_id:
+ case C1StubId::throw_range_check_failed_id:
{
StubFrame f(sasm, "range_check_failed", dont_gc_arguments, does_not_return);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), true);
}
break;
- case unwind_exception_id:
+ case C1StubId::unwind_exception_id:
{
__ set_info("unwind_exception", dont_gc_arguments);
// note: no stubframe since we are about to leave the current
@@ -957,7 +955,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case access_field_patching_id:
+ case C1StubId::access_field_patching_id:
{
StubFrame f(sasm, "access_field_patching", dont_gc_arguments, does_not_return);
// we should set up register map
@@ -965,7 +963,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case load_klass_patching_id:
+ case C1StubId::load_klass_patching_id:
{
StubFrame f(sasm, "load_klass_patching", dont_gc_arguments, does_not_return);
// we should set up register map
@@ -973,7 +971,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case load_mirror_patching_id:
+ case C1StubId::load_mirror_patching_id:
{
StubFrame f(sasm, "load_mirror_patching", dont_gc_arguments, does_not_return);
// we should set up register map
@@ -981,7 +979,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case load_appendix_patching_id:
+ case C1StubId::load_appendix_patching_id:
{
StubFrame f(sasm, "load_appendix_patching", dont_gc_arguments, does_not_return);
// we should set up register map
@@ -989,29 +987,29 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
{
StubFrame f(sasm, "handle_exception", dont_gc_arguments);
oop_maps = generate_handle_exception(id, sasm);
}
break;
- case handle_exception_from_callee_id:
+ case C1StubId::handle_exception_from_callee_id:
{
StubFrame f(sasm, "handle_exception_from_callee", dont_gc_arguments);
oop_maps = generate_handle_exception(id, sasm);
}
break;
- case throw_index_exception_id:
+ case C1StubId::throw_index_exception_id:
{
StubFrame f(sasm, "index_range_check_failed", dont_gc_arguments, does_not_return);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true);
}
break;
- case throw_array_store_exception_id:
+ case C1StubId::throw_array_store_exception_id:
{
StubFrame f(sasm, "throw_array_store_exception", dont_gc_arguments, does_not_return);
// tos + 0: link
@@ -1020,7 +1018,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case predicate_failed_trap_id:
+ case C1StubId::predicate_failed_trap_id:
{
StubFrame f(sasm, "predicate_failed_trap", dont_gc_arguments, does_not_return);
@@ -1040,7 +1038,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case dtrace_object_alloc_id:
+ case C1StubId::dtrace_object_alloc_id:
{ // c_rarg0: object
StubFrame f(sasm, "dtrace_object_alloc", dont_gc_arguments);
save_live_registers(sasm);
@@ -1066,4 +1064,4 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
#undef __
-const char *Runtime1::pd_name_for_address(address entry) { Unimplemented(); return 0; }
+const char *Runtime1::pd_name_for_address(address entry) { Unimplemented(); }
diff --git a/src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp b/src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp
index 7995750aba9..db18525b89c 100644
--- a/src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp
@@ -71,32 +71,4 @@ void C2EntryBarrierStub::emit(C2_MacroAssembler& masm) {
__ emit_int32(0); // nmethod guard value
}
-int C2HandleAnonOMOwnerStub::max_size() const {
- // Max size of stub has been determined by testing with 0 without using RISC-V compressed
- // instruction-set extension, in which case C2CodeStubList::emit() will throw an assertion
- // and report the actual size that is needed.
- return 20 DEBUG_ONLY(+8);
-}
-
-void C2HandleAnonOMOwnerStub::emit(C2_MacroAssembler& masm) {
- __ bind(entry());
- Register mon = monitor();
- Register t = tmp();
- assert(t != noreg, "need tmp register");
-
- // Fix owner to be the current thread.
- __ sd(xthread, Address(mon, ObjectMonitor::owner_offset()));
-
- // Pop owner object from lock-stack.
- __ lwu(t, Address(xthread, JavaThread::lock_stack_top_offset()));
- __ subw(t, t, oopSize);
-#ifdef ASSERT
- __ add(t0, xthread, t);
- __ sd(zr, Address(t0, 0));
-#endif
- __ sw(t, Address(xthread, JavaThread::lock_stack_top_offset()));
-
- __ j(continuation());
-}
-
#undef __
diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
index d88e4bf320d..75f87e35adf 100644
--- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
@@ -68,8 +68,8 @@ void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg,
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp, oop);
- lwu(tmp, Address(tmp, Klass::access_flags_offset()));
- test_bit(tmp, tmp, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
+ lbu(tmp, Address(tmp, Klass::misc_flags_offset()));
+ test_bit(tmp, tmp, exact_log2(KlassFlags::_misc_is_value_based_class));
bnez(tmp, slow_path);
}
@@ -165,6 +165,7 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg,
Register oop = objectReg;
Register box = boxReg;
Register disp_hdr = tmp1Reg;
+ Register owner_addr = tmp1Reg;
Register tmp = tmp2Reg;
Label object_has_monitor;
// Finish fast lock successfully. MUST branch to with flag == 0
@@ -222,15 +223,33 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg,
j(unlocked);
bind(notRecursive);
- ld(t0, Address(tmp, ObjectMonitor::EntryList_offset()));
- ld(disp_hdr, Address(tmp, ObjectMonitor::cxq_offset()));
- orr(t0, t0, disp_hdr); // Will be 0 if both are 0.
- bnez(t0, slow_path);
+ // Compute owner address.
+ la(owner_addr, Address(tmp, ObjectMonitor::owner_offset()));
- // need a release store here
- la(tmp, Address(tmp, ObjectMonitor::owner_offset()));
+ // Set owner to null.
+ // Release to satisfy the JMM
membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore);
- sd(zr, Address(tmp)); // set unowned
+ sd(zr, Address(owner_addr));
+ // We need a full fence after clearing owner to avoid stranding.
+ // StoreLoad achieves this.
+ membar(StoreLoad);
+
+ // Check if the entry lists are empty.
+ ld(t0, Address(tmp, ObjectMonitor::EntryList_offset()));
+ ld(tmp1Reg, Address(tmp, ObjectMonitor::cxq_offset()));
+ orr(t0, t0, tmp1Reg);
+ beqz(t0, unlocked); // If so we are done.
+
+ // Check if there is a successor.
+ ld(t0, Address(tmp, ObjectMonitor::succ_offset()));
+ bnez(t0, unlocked); // If so we are done.
+
+ // Save the monitor pointer in the current thread, so we can try to
+ // reacquire the lock in SharedRuntime::monitor_exit_helper().
+ sd(tmp, Address(xthread, JavaThread::unlocked_inflated_monitor_offset()));
+
+ mv(flag, 1);
+ j(slow_path);
bind(unlocked);
mv(flag, zr);
@@ -253,12 +272,13 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg,
// C2 uses the value of flag (0 vs !0) to determine the continuation.
}
-void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register tmp1, Register tmp2, Register tmp3) {
+void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box,
+ Register tmp1, Register tmp2, Register tmp3) {
// Flag register, zero for success; non-zero for failure.
Register flag = t1;
assert(LockingMode == LM_LIGHTWEIGHT, "must be");
- assert_different_registers(obj, tmp1, tmp2, tmp3, flag, t0);
+ assert_different_registers(obj, box, tmp1, tmp2, tmp3, flag, t0);
mv(flag, 1);
@@ -269,14 +289,20 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register tmp1, Regis
// Finish fast lock unsuccessfully. slow_path MUST branch to with flag != 0
Label slow_path;
+ if (UseObjectMonitorTable) {
+ // Clear cache in case fast locking succeeds.
+ sd(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
+ }
+
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp1, obj);
- lwu(tmp1, Address(tmp1, Klass::access_flags_offset()));
- test_bit(tmp1, tmp1, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
+ lbu(tmp1, Address(tmp1, Klass::misc_flags_offset()));
+ test_bit(tmp1, tmp1, exact_log2(KlassFlags::_misc_is_value_based_class));
bnez(tmp1, slow_path);
}
const Register tmp1_mark = tmp1;
+ const Register tmp3_t = tmp3;
{ // Lightweight locking
@@ -284,7 +310,6 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register tmp1, Regis
Label push;
const Register tmp2_top = tmp2;
- const Register tmp3_t = tmp3;
// Check if lock-stack is full.
lwu(tmp2_top, Address(xthread, JavaThread::lock_stack_top_offset()));
@@ -323,25 +348,68 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register tmp1, Regis
{ // Handle inflated monitor.
bind(inflated);
- // mark contains the tagged ObjectMonitor*.
- const Register tmp1_tagged_monitor = tmp1_mark;
- const uintptr_t monitor_tag = markWord::monitor_value;
+ const Register tmp1_monitor = tmp1;
+ if (!UseObjectMonitorTable) {
+ assert(tmp1_monitor == tmp1_mark, "should be the same here");
+ } else {
+ Label monitor_found;
+
+ // Load cache address
+ la(tmp3_t, Address(xthread, JavaThread::om_cache_oops_offset()));
+
+ const int num_unrolled = 2;
+ for (int i = 0; i < num_unrolled; i++) {
+ ld(tmp1, Address(tmp3_t));
+ beq(obj, tmp1, monitor_found);
+ add(tmp3_t, tmp3_t, in_bytes(OMCache::oop_to_oop_difference()));
+ }
+
+ Label loop;
+
+ // Search for obj in cache.
+ bind(loop);
+
+ // Check for match.
+ ld(tmp1, Address(tmp3_t));
+ beq(obj, tmp1, monitor_found);
+
+ // Search until null encountered, guaranteed _null_sentinel at end.
+ add(tmp3_t, tmp3_t, in_bytes(OMCache::oop_to_oop_difference()));
+ bnez(tmp1, loop);
+ // Cache Miss. Take the slowpath.
+ j(slow_path);
+
+ bind(monitor_found);
+ ld(tmp1_monitor, Address(tmp3_t, OMCache::oop_to_monitor_difference()));
+ }
+
const Register tmp2_owner_addr = tmp2;
const Register tmp3_owner = tmp3;
+ const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value));
+ const Address owner_address(tmp1_monitor, ObjectMonitor::owner_offset() - monitor_tag);
+ const Address recursions_address(tmp1_monitor, ObjectMonitor::recursions_offset() - monitor_tag);
+
+ Label monitor_locked;
+
// Compute owner address.
- la(tmp2_owner_addr, Address(tmp1_tagged_monitor, (in_bytes(ObjectMonitor::owner_offset()) - monitor_tag)));
+ la(tmp2_owner_addr, owner_address);
// CAS owner (null => current thread).
cmpxchg(/*addr*/ tmp2_owner_addr, /*expected*/ zr, /*new*/ xthread, Assembler::int64,
/*acquire*/ Assembler::aq, /*release*/ Assembler::relaxed, /*result*/ tmp3_owner);
- beqz(tmp3_owner, locked);
+ beqz(tmp3_owner, monitor_locked);
// Check if recursive.
bne(tmp3_owner, xthread, slow_path);
// Recursive.
- increment(Address(tmp1_tagged_monitor, in_bytes(ObjectMonitor::recursions_offset()) - monitor_tag), 1, tmp2, tmp3);
+ increment(recursions_address, 1, tmp2, tmp3);
+
+ bind(monitor_locked);
+ if (UseObjectMonitorTable) {
+ sd(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
+ }
}
bind(locked);
@@ -365,18 +433,18 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register tmp1, Regis
// C2 uses the value of flag (0 vs !0) to determine the continuation.
}
-void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register tmp1, Register tmp2,
- Register tmp3) {
+void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box,
+ Register tmp1, Register tmp2, Register tmp3) {
// Flag register, zero for success; non-zero for failure.
Register flag = t1;
assert(LockingMode == LM_LIGHTWEIGHT, "must be");
- assert_different_registers(obj, tmp1, tmp2, tmp3, flag, t0);
+ assert_different_registers(obj, box, tmp1, tmp2, tmp3, flag, t0);
mv(flag, 1);
// Handle inflated monitor.
- Label inflated, inflated_load_monitor;
+ Label inflated, inflated_load_mark;
// Finish fast unlock successfully. unlocked MUST branch to with flag == 0
Label unlocked;
// Finish fast unlock unsuccessfully. MUST branch to with flag != 0
@@ -387,6 +455,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register tmp1, Reg
const Register tmp3_t = tmp3;
{ // Lightweight unlock
+ Label push_and_slow_path;
// Check if obj is top of lock-stack.
lwu(tmp2_top, Address(xthread, JavaThread::lock_stack_top_offset()));
@@ -394,7 +463,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register tmp1, Reg
add(tmp3_t, xthread, tmp2_top);
ld(tmp3_t, Address(tmp3_t));
// Top of lock stack was not obj. Must be monitor.
- bne(obj, tmp3_t, inflated_load_monitor);
+ bne(obj, tmp3_t, inflated_load_mark);
// Pop lock-stack.
DEBUG_ONLY(add(tmp3_t, xthread, tmp2_top);)
@@ -411,8 +480,11 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register tmp1, Reg
ld(tmp1_mark, Address(obj, oopDesc::mark_offset_in_bytes()));
// Check header for monitor (0b10).
+ // Because we got here by popping (meaning we pushed in locked)
+ // there will be no monitor in the box. So we need to push back the obj
+ // so that the runtime can fix any potential anonymous owner.
test_bit(tmp3_t, tmp1_mark, exact_log2(markWord::monitor_value));
- bnez(tmp3_t, inflated);
+ bnez(tmp3_t, UseObjectMonitorTable ? push_and_slow_path : inflated);
// Try to unlock. Transition lock bits 0b00 => 0b01
assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid lea");
@@ -421,6 +493,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register tmp1, Reg
/*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, /*result*/ tmp3_t);
beq(tmp1_mark, tmp3_t, unlocked);
+ bind(push_and_slow_path);
// Compare and exchange failed.
// Restore lock-stack and handle the unlock in runtime.
DEBUG_ONLY(add(tmp3_t, xthread, tmp2_top);)
@@ -431,7 +504,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register tmp1, Reg
}
{ // Handle inflated monitor.
- bind(inflated_load_monitor);
+ bind(inflated_load_mark);
ld(tmp1_mark, Address(obj, oopDesc::mark_offset_in_bytes()));
#ifdef ASSERT
test_bit(tmp3_t, tmp1_mark, exact_log2(markWord::monitor_value));
@@ -453,12 +526,18 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register tmp1, Reg
bind(check_done);
#endif
- // mark contains the tagged ObjectMonitor*.
- const Register tmp1_monitor = tmp1_mark;
- const uintptr_t monitor_tag = markWord::monitor_value;
+ const Register tmp1_monitor = tmp1;
- // Untag the monitor.
- sub(tmp1_monitor, tmp1_mark, monitor_tag);
+ if (!UseObjectMonitorTable) {
+ assert(tmp1_monitor == tmp1_mark, "should be the same here");
+ // Untag the monitor.
+ add(tmp1_monitor, tmp1_mark, -(int)markWord::monitor_value);
+ } else {
+ ld(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
+ // No valid pointer below alignof(ObjectMonitor*). Take the slow path.
+ mv(tmp3_t, alignof(ObjectMonitor*));
+ bltu(tmp1_monitor, tmp3_t, slow_path);
+ }
const Register tmp2_recursions = tmp2;
Label not_recursive;
@@ -474,28 +553,35 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register tmp1, Reg
bind(not_recursive);
- Label release;
const Register tmp2_owner_addr = tmp2;
// Compute owner address.
la(tmp2_owner_addr, Address(tmp1_monitor, ObjectMonitor::owner_offset()));
+ // Set owner to null.
+ // Release to satisfy the JMM
+ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore);
+ sd(zr, Address(tmp2_owner_addr));
+ // We need a full fence after clearing owner to avoid stranding.
+ // StoreLoad achieves this.
+ membar(StoreLoad);
+
// Check if the entry lists are empty.
ld(t0, Address(tmp1_monitor, ObjectMonitor::EntryList_offset()));
ld(tmp3_t, Address(tmp1_monitor, ObjectMonitor::cxq_offset()));
orr(t0, t0, tmp3_t);
- beqz(t0, release);
+ beqz(t0, unlocked); // If so we are done.
- // The owner may be anonymous and we removed the last obj entry in
- // the lock-stack. This loses the information about the owner.
- // Write the thread to the owner field so the runtime knows the owner.
- sd(xthread, Address(tmp2_owner_addr));
- j(slow_path);
+ // Check if there is a successor.
+ ld(tmp3_t, Address(tmp1_monitor, ObjectMonitor::succ_offset()));
+ bnez(tmp3_t, unlocked); // If so we are done.
- bind(release);
- // Set owner to null.
- membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore);
- sd(zr, Address(tmp2_owner_addr));
+ // Save the monitor pointer in the current thread, so we can try
+ // to reacquire the lock in SharedRuntime::monitor_exit_helper().
+ sd(tmp1_monitor, Address(xthread, JavaThread::unlocked_inflated_monitor_offset()));
+
+ mv(flag, 1);
+ j(slow_path);
}
bind(unlocked);
@@ -2325,6 +2411,74 @@ void C2_MacroAssembler::expand_bits_l_v(Register dst, Register src, Register mas
expand_bits_v(dst, src, mask, /* is_long */ true);
}
+// j.l.Math.round(float)
+// Returns the closest int to the argument, with ties rounding to positive infinity.
+// We need to handle 3 special cases defined by java api spec:
+// NaN,
+// float >= Integer.MAX_VALUE,
+// float <= Integer.MIN_VALUE.
+void C2_MacroAssembler::java_round_float_v(VectorRegister dst, VectorRegister src, FloatRegister ftmp,
+ BasicType bt, uint vector_length) {
+ // In riscv, there is no straight corresponding rounding mode to satisfy the behaviour defined,
+ // in java api spec, i.e. any rounding mode can not handle some corner cases, e.g.
+ // RNE is the closest one, but it ties to "even", which means 1.5/2.5 both will be converted
+ // to 2, instead of 2 and 3 respectively.
+ // RUP does not work either, although java api requires "rounding to positive infinity",
+ // but both 1.3/1.8 will be converted to 2, instead of 1 and 2 respectively.
+ //
+ // The optimal solution for non-NaN cases is:
+ // src+0.5 => dst, with rdn rounding mode,
+ // convert dst from float to int, with rnd rounding mode.
+ // and, this solution works as expected for float >= Integer.MAX_VALUE and float <= Integer.MIN_VALUE.
+ //
+ // But, we still need to handle NaN explicilty with vector mask instructions.
+ //
+ // Check MacroAssembler::java_round_float and C2_MacroAssembler::vector_round_sve in aarch64 for more details.
+
+ csrwi(CSR_FRM, C2_MacroAssembler::rdn);
+ vsetvli_helper(bt, vector_length);
+
+ // don't rearrage the instructions sequence order without performance testing.
+ // check MacroAssembler::java_round_float in riscv64 for more details.
+ mv(t0, jint_cast(0.5f));
+ fmv_w_x(ftmp, t0);
+
+ // replacing vfclass with feq as performance optimization
+ vmfeq_vv(v0, src, src);
+ // set dst = 0 in cases of NaN
+ vmv_v_x(dst, zr);
+
+ // dst = (src + 0.5) rounded down towards negative infinity
+ vfadd_vf(dst, src, ftmp, Assembler::v0_t);
+ vfcvt_x_f_v(dst, dst, Assembler::v0_t); // in RoundingMode::rdn
+
+ csrwi(CSR_FRM, C2_MacroAssembler::rne);
+}
+
+// java.lang.Math.round(double a)
+// Returns the closest long to the argument, with ties rounding to positive infinity.
+void C2_MacroAssembler::java_round_double_v(VectorRegister dst, VectorRegister src, FloatRegister ftmp,
+ BasicType bt, uint vector_length) {
+ // check C2_MacroAssembler::java_round_float_v above for more details.
+
+ csrwi(CSR_FRM, C2_MacroAssembler::rdn);
+ vsetvli_helper(bt, vector_length);
+
+ mv(t0, julong_cast(0.5));
+ fmv_d_x(ftmp, t0);
+
+ // replacing vfclass with feq as performance optimization
+ vmfeq_vv(v0, src, src);
+ // set dst = 0 in cases of NaN
+ vmv_v_x(dst, zr);
+
+ // dst = (src + 0.5) rounded down towards negative infinity
+ vfadd_vf(dst, src, ftmp, Assembler::v0_t);
+ vfcvt_x_f_v(dst, dst, Assembler::v0_t); // in RoundingMode::rdn
+
+ csrwi(CSR_FRM, C2_MacroAssembler::rne);
+}
+
void C2_MacroAssembler::element_compare(Register a1, Register a2, Register result, Register cnt, Register tmp1, Register tmp2,
VectorRegister vr1, VectorRegister vr2, VectorRegister vrs, bool islatin, Label &DONE,
Assembler::LMUL lmul) {
diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
index 07041fe0850..38351565cc6 100644
--- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
@@ -47,8 +47,8 @@
void fast_lock(Register object, Register box, Register tmp1, Register tmp2, Register tmp3);
void fast_unlock(Register object, Register box, Register tmp1, Register tmp2);
// Code used by cmpFastLockLightweight and cmpFastUnlockLightweight mach instructions in .ad file.
- void fast_lock_lightweight(Register object, Register tmp1, Register tmp2, Register tmp3);
- void fast_unlock_lightweight(Register object, Register tmp1, Register tmp2, Register tmp3);
+ void fast_lock_lightweight(Register object, Register box, Register tmp1, Register tmp2, Register tmp3);
+ void fast_unlock_lightweight(Register object, Register box, Register tmp1, Register tmp2, Register tmp3);
void string_compare(Register str1, Register str2,
Register cnt1, Register cnt2, Register result,
@@ -187,6 +187,9 @@
void expand_bits_i_v(Register dst, Register src, Register mask);
void expand_bits_l_v(Register dst, Register src, Register mask);
+ void java_round_float_v(VectorRegister dst, VectorRegister src, FloatRegister ftmp, BasicType bt, uint vector_length);
+ void java_round_double_v(VectorRegister dst, VectorRegister src, FloatRegister ftmp, BasicType bt, uint vector_length);
+
void float16_to_float_v(VectorRegister dst, VectorRegister src, uint vector_length);
void float_to_float16_v(VectorRegister dst, VectorRegister src, VectorRegister vtmp, Register tmp, uint vector_length);
diff --git a/src/hotspot/cpu/riscv/frame_riscv.cpp b/src/hotspot/cpu/riscv/frame_riscv.cpp
index 32825a02c5e..96dca4704ad 100644
--- a/src/hotspot/cpu/riscv/frame_riscv.cpp
+++ b/src/hotspot/cpu/riscv/frame_riscv.cpp
@@ -269,7 +269,7 @@ void frame::patch_pc(Thread* thread, address pc) {
// Either the return address is the original one or we are going to
// patch in the same address that's already there.
- assert(_pc == pc_old || pc == pc_old || pc_old == 0, "must be");
+ assert(_pc == pc_old || pc == pc_old || pc_old == nullptr, "must be");
DEBUG_ONLY(address old_pc = _pc;)
*pc_addr = pc;
_pc = pc; // must be set before call to get_deopt_original_pc
diff --git a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp
index 062f8029062..5493882be72 100644
--- a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
+ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,10 @@
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "gc/g1/c1/g1BarrierSetC1.hpp"
-#endif
+#endif // COMPILER1
+#ifdef COMPILER2
+#include "gc/g1/c2/g1BarrierSetC2.hpp"
+#endif // COMPILER2
#define __ masm->
@@ -96,6 +99,55 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas
__ pop_reg(saved_regs, sp);
}
+static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime,
+ const Register thread, const Register value, const Register tmp1, const Register tmp2) {
+ // Can we store a value in the given thread's buffer?
+ // (The index field is typed as size_t.)
+ __ ld(tmp1, Address(thread, in_bytes(index_offset))); // tmp1 := *(index address)
+ __ beqz(tmp1, runtime); // jump to runtime if index == 0 (full buffer)
+ // The buffer is not full, store value into it.
+ __ sub(tmp1, tmp1, wordSize); // tmp1 := next index
+ __ sd(tmp1, Address(thread, in_bytes(index_offset))); // *(index address) := next index
+ __ ld(tmp2, Address(thread, in_bytes(buffer_offset))); // tmp2 := buffer address
+ __ add(tmp2, tmp2, tmp1);
+ __ sd(value, Address(tmp2)); // *(buffer address + next index) := value
+}
+
+static void generate_pre_barrier_fast_path(MacroAssembler* masm,
+ const Register thread,
+ const Register tmp1) {
+ Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
+ // Is marking active?
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ lwu(tmp1, in_progress);
+ } else {
+ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ lbu(tmp1, in_progress);
+ }
+}
+
+static void generate_pre_barrier_slow_path(MacroAssembler* masm,
+ const Register obj,
+ const Register pre_val,
+ const Register thread,
+ const Register tmp1,
+ const Register tmp2,
+ Label& done,
+ Label& runtime) {
+ // Do we need to load the previous value?
+ if (obj != noreg) {
+ __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);
+ }
+ // Is the previous value null?
+ __ beqz(pre_val, done, true);
+ generate_queue_test_and_insertion(masm,
+ G1ThreadLocalData::satb_mark_queue_index_offset(),
+ G1ThreadLocalData::satb_mark_queue_buffer_offset(),
+ runtime,
+ thread, pre_val, tmp1, tmp2);
+ __ j(done);
+}
+
void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
Register obj,
Register pre_val,
@@ -116,43 +168,10 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
assert_different_registers(obj, pre_val, tmp1, tmp2);
assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register");
- Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
- Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
- Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
-
- // Is marking active?
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { // 4-byte width
- __ lwu(tmp1, in_progress);
- } else {
- assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- __ lbu(tmp1, in_progress);
- }
+ generate_pre_barrier_fast_path(masm, thread, tmp1);
+ // If marking is not active (*(mark queue active address) == 0), jump to done
__ beqz(tmp1, done);
-
- // Do we need to load the previous value?
- if (obj != noreg) {
- __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);
- }
-
- // Is the previous value null?
- __ beqz(pre_val, done);
-
- // Can we store original value in the thread's buffer?
- // Is index == 0?
- // (The index field is typed as size_t.)
-
- __ ld(tmp1, index); // tmp := *index_adr
- __ beqz(tmp1, runtime); // tmp == 0?
- // If yes, goto runtime
-
- __ sub(tmp1, tmp1, wordSize); // tmp := tmp - wordSize
- __ sd(tmp1, index); // *index_adr := tmp
- __ ld(tmp2, buffer);
- __ add(tmp1, tmp1, tmp2); // tmp := tmp + *buffer_adr
-
- // Record the previous value
- __ sd(pre_val, Address(tmp1, 0));
- __ j(done);
+ generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, done, runtime);
__ bind(runtime);
@@ -171,6 +190,49 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
}
+static void generate_post_barrier_fast_path(MacroAssembler* masm,
+ const Register store_addr,
+ const Register new_val,
+ const Register tmp1,
+ const Register tmp2,
+ Label& done,
+ bool new_val_may_be_null) {
+ // Does store cross heap regions?
+ __ xorr(tmp1, store_addr, new_val); // tmp1 := store address ^ new value
+ __ srli(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
+ __ beqz(tmp1, done);
+ // Crosses regions, storing null?
+ if (new_val_may_be_null) {
+ __ beqz(new_val, done);
+ }
+ // Storing region crossing non-null, is card young?
+ __ srli(tmp1, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base
+ __ load_byte_map_base(tmp2); // tmp2 := card table base address
+ __ add(tmp1, tmp1, tmp2); // tmp1 := card address
+ __ lbu(tmp2, Address(tmp1)); // tmp2 := card
+}
+
+static void generate_post_barrier_slow_path(MacroAssembler* masm,
+ const Register thread,
+ const Register tmp1,
+ const Register tmp2,
+ Label& done,
+ Label& runtime) {
+ __ membar(MacroAssembler::StoreLoad); // StoreLoad membar
+ __ lbu(tmp2, Address(tmp1)); // tmp2 := card
+ __ beqz(tmp2, done, true);
+ // Storing a region crossing, non-null oop, card is clean.
+ // Dirty card and log.
+ STATIC_ASSERT(CardTable::dirty_card_val() == 0);
+ __ sb(zr, Address(tmp1)); // *(card address) := dirty_card_val
+ generate_queue_test_and_insertion(masm,
+ G1ThreadLocalData::dirty_card_queue_index_offset(),
+ G1ThreadLocalData::dirty_card_queue_buffer_offset(),
+ runtime,
+ thread, tmp1, tmp2, t0);
+ __ j(done);
+}
+
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
Register store_addr,
Register new_val,
@@ -179,73 +241,119 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
Register tmp2) {
assert(thread == xthread, "must be");
assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, t0);
- assert(store_addr != noreg && new_val != noreg && tmp1 != noreg &&
- tmp2 != noreg, "expecting a register");
-
- Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
- Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
-
- BarrierSet* bs = BarrierSet::barrier_set();
- CardTableBarrierSet* ctbs = barrier_set_cast(bs);
+ assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg,
+ "expecting a register");
Label done;
Label runtime;
- // Does store cross heap regions?
+ generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */);
+ // If card is young, jump to done (tmp2 holds the card value)
+ __ mv(t0, (int)G1CardTable::g1_young_card_val());
+ __ beq(tmp2, t0, done); // card == young_card_val?
+ generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, done, runtime);
- __ xorr(tmp1, store_addr, new_val);
- __ srli(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes);
- __ beqz(tmp1, done);
+ __ bind(runtime);
+ // save the live input values
+ RegSet saved = RegSet::of(store_addr);
+ __ push_reg(saved, sp);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp1, thread);
+ __ pop_reg(saved, sp);
- // crosses regions, storing null?
+ __ bind(done);
+}
- __ beqz(new_val, done);
+#if defined(COMPILER2)
- // storing region crossing non-null, is card already dirty?
+static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) {
+ SaveLiveRegisters save_registers(masm, stub);
+ if (c_rarg0 != arg) {
+ __ mv(c_rarg0, arg);
+ }
+ __ mv(c_rarg1, xthread);
+ __ mv(t1, runtime_path);
+ __ jalr(t1);
+}
- const Register card_addr = tmp1;
+void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2,
+ G1PreBarrierStubC2* stub) {
+ assert(thread == xthread, "must be");
+ assert_different_registers(obj, pre_val, tmp1, tmp2);
+ assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register");
- __ srli(card_addr, store_addr, CardTable::card_shift());
+ stub->initialize_registers(obj, pre_val, thread, tmp1, tmp2);
- // get the address of the card
- __ load_byte_map_base(tmp2);
- __ add(card_addr, card_addr, tmp2);
- __ lbu(tmp2, Address(card_addr));
- __ mv(t0, (int)G1CardTable::g1_young_card_val());
- __ beq(tmp2, t0, done);
+ generate_pre_barrier_fast_path(masm, thread, tmp1);
+ // If marking is active (*(mark queue active address) != 0), jump to stub (slow path)
+ __ bnez(tmp1, *stub->entry(), true);
- assert((int)CardTable::dirty_card_val() == 0, "must be 0");
+ __ bind(*stub->continuation());
+}
- __ membar(MacroAssembler::StoreLoad);
+void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
+ G1PreBarrierStubC2* stub) const {
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ Label runtime;
+ Register obj = stub->obj();
+ Register pre_val = stub->pre_val();
+ Register thread = stub->thread();
+ Register tmp1 = stub->tmp1();
+ Register tmp2 = stub->tmp2();
- __ lbu(tmp2, Address(card_addr));
- __ beqz(tmp2, done);
+ __ bind(*stub->entry());
+ generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, *stub->continuation(), runtime);
- // storing a region crossing, non-null oop, card is clean.
- // dirty card and log.
+ __ bind(runtime);
+ generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry));
+ __ j(*stub->continuation());
+}
- __ sb(zr, Address(card_addr));
+void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2,
+ G1PostBarrierStubC2* stub) {
+ assert(thread == xthread, "must be");
+ assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, t0);
+ assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg,
+ "expecting a register");
- __ ld(t0, queue_index);
- __ beqz(t0, runtime);
- __ sub(t0, t0, wordSize);
- __ sd(t0, queue_index);
+ stub->initialize_registers(thread, tmp1, tmp2);
- __ ld(tmp2, buffer);
- __ add(t0, tmp2, t0);
- __ sd(card_addr, Address(t0, 0));
- __ j(done);
+ bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0;
+ generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null);
+ // If card is not young, jump to stub (slow path) (tmp2 holds the card value)
+ __ mv(t0, (int)G1CardTable::g1_young_card_val());
+ __ bne(tmp2, t0, *stub->entry(), true);
- __ bind(runtime);
- // save the live input values
- RegSet saved = RegSet::of(store_addr);
- __ push_reg(saved, sp);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread);
- __ pop_reg(saved, sp);
+ __ bind(*stub->continuation());
+}
- __ bind(done);
+void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
+ G1PostBarrierStubC2* stub) const {
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ Label runtime;
+ Register thread = stub->thread();
+ Register tmp1 = stub->tmp1(); // tmp1 holds the card address.
+ Register tmp2 = stub->tmp2();
+
+ __ bind(*stub->entry());
+ generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, *stub->continuation(), runtime);
+
+ __ bind(runtime);
+ generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry));
+ __ j(*stub->continuation());
}
+#endif // COMPILER2
+
void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Address src, Register tmp1, Register tmp2) {
bool on_oop = is_reference_type(type);
diff --git a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp
index 96568994079..c7bee2ef6f3 100644
--- a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved.
+ * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,8 @@ class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
class G1PostBarrierStub;
+class G1PreBarrierStubC2;
+class G1PostBarrierStubC2;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@@ -72,6 +74,27 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
#endif
+#ifdef COMPILER2
+ void g1_write_barrier_pre_c2(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2,
+ G1PreBarrierStubC2* c2_stub);
+ void generate_c2_pre_barrier_stub(MacroAssembler* masm,
+ G1PreBarrierStubC2* stub) const;
+ void g1_write_barrier_post_c2(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2,
+ G1PostBarrierStubC2* c2_stub);
+ void generate_c2_post_barrier_stub(MacroAssembler* masm,
+ G1PostBarrierStubC2* stub) const;
+#endif
+
void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Address src, Register tmp1, Register tmp2);
};
diff --git a/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad b/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad
new file mode 100644
index 00000000000..7a525323021
--- /dev/null
+++ b/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad
@@ -0,0 +1,564 @@
+//
+// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2024, Huawei Technologies Co., Ltd. All rights reserved.
+// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+//
+// This code is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 2 only, as
+// published by the Free Software Foundation.
+//
+// This code is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// version 2 for more details (a copy is included in the LICENSE file that
+// accompanied this code).
+//
+// You should have received a copy of the GNU General Public License version
+// 2 along with this work; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+// or visit www.oracle.com if you need additional information or have any
+// questions.
+//
+
+source_hpp %{
+
+#include "gc/g1/c2/g1BarrierSetC2.hpp"
+#include "gc/shared/gc_globals.hpp"
+
+%}
+
+source %{
+
+#include "gc/g1/g1BarrierSetAssembler_riscv.hpp"
+#include "gc/g1/g1BarrierSetRuntime.hpp"
+
+static void write_barrier_pre(MacroAssembler* masm,
+ const MachNode* node,
+ Register obj,
+ Register pre_val,
+ Register tmp1,
+ Register tmp2,
+ RegSet preserve = RegSet(),
+ RegSet no_preserve = RegSet()) {
+ if (!G1PreBarrierStubC2::needs_barrier(node)) {
+ return;
+ }
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
+ G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node);
+ for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) {
+ stub->preserve(*reg);
+ }
+ for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) {
+ stub->dont_preserve(*reg);
+ }
+ g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, xthread, tmp1, tmp2, stub);
+}
+
+static void write_barrier_post(MacroAssembler* masm,
+ const MachNode* node,
+ Register store_addr,
+ Register new_val,
+ Register tmp1,
+ Register tmp2) {
+ if (!G1PostBarrierStubC2::needs_barrier(node)) {
+ return;
+ }
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
+ G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
+ g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, xthread, tmp1, tmp2, stub);
+}
+
+%}
+
+instruct g1StoreP(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreP mem src));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(STORE_COST);
+ format %{ "sd $src, $mem\t# ptr" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ __ sd($src$$Register, Address($mem$$Register));
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $src$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(istore_reg_mem);
+%}
+
+instruct g1StoreN(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreN mem src));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(STORE_COST);
+ format %{ "sw $src, $mem\t# compressed ptr" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ __ sw($src$$Register, Address($mem$$Register));
+ if ((barrier_data() & G1C2BarrierPost) != 0) {
+ if ((barrier_data() & G1C2BarrierPostNotNull) == 0) {
+ __ decode_heap_oop($tmp1$$Register, $src$$Register);
+ } else {
+ __ decode_heap_oop_not_null($tmp1$$Register, $src$$Register);
+ }
+ }
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(istore_reg_mem);
+%}
+
+instruct g1EncodePAndStoreN(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreN mem (EncodeP src)));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(STORE_COST);
+ format %{ "encode_heap_oop $tmp1, $src\n\t"
+ "sw $tmp1, $mem\t# compressed ptr" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ if ((barrier_data() & G1C2BarrierPostNotNull) == 0) {
+ __ encode_heap_oop($tmp1$$Register, $src$$Register);
+ } else {
+ __ encode_heap_oop_not_null($tmp1$$Register, $src$$Register);
+ }
+ __ sw($tmp1$$Register, Address($mem$$Register));
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $src$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(istore_reg_mem);
+%}
+
+instruct g1CompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(2 * VOLATILE_REF_COST);
+ format %{ "cmpxchg $res = $mem, $oldval, $newval\t# ptr" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ // Pass $oldval to the pre-barrier (instead of loading from $mem), because
+ // $oldval is the only value that can be overwritten.
+ // The same holds for g1CompareAndSwapP and its Acq variant.
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $oldval$$Register /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64,
+ /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct g1CompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# ptr" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ // Pass $oldval to the pre-barrier (instead of loading from $mem), because
+ // $oldval is the only value that can be overwritten.
+ // The same holds for g1CompareAndSwapP and its Acq variant.
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $oldval$$Register /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64,
+ /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct g1CompareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(2 * VOLATILE_REF_COST);
+ format %{ "cmpxchg $res = $mem, $oldval, $newval\t# narrow oop" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::uint32,
+ /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct g1CompareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# narrow oop" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::uint32,
+ /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct g1CompareAndSwapP(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapP mem (Binary oldval newval)));
+ match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(2 * VOLATILE_REF_COST);
+ format %{ "cmpxchg $mem, $oldval, $newval\t# (ptr)\n\t"
+ "mv $res, $res == $oldval" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $oldval$$Register /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64,
+ /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register,
+ /*result as bool*/ true);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct g1CompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapP mem (Binary oldval newval)));
+ match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (ptr)\n\t"
+ "mv $res, $res == $oldval" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $oldval$$Register /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64,
+ /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register,
+ /*result as bool*/ true);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct g1CompareAndSwapN(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapN mem (Binary oldval newval)));
+ match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(2 * VOLATILE_REF_COST);
+ format %{ "cmpxchg $mem, $oldval, $newval\t# (narrow oop)\n\t"
+ "mv $res, $res == $oldval" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::uint32,
+ /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register,
+ /*result as bool*/ true);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct g1CompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapN mem (Binary oldval newval)));
+ match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (narrow oop)\n\t"
+ "mv $res, $res == $oldval" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ assert_different_registers($newval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::uint32,
+ /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register,
+ /*result as bool*/ true);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct g1GetAndSetP(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set preval (GetAndSetP mem newval));
+ effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(2 * VOLATILE_REF_COST);
+ format %{ "atomic_xchg $preval, $newval, [$mem]" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ assert_different_registers($mem$$Register, $newval$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $preval$$Register /* pre_val (as a temporary register) */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */);
+ __ atomic_xchg($preval$$Register, $newval$$Register, $mem$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_serial);
+%}
+
+instruct g1GetAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set preval (GetAndSetP mem newval));
+ effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "atomic_xchg_acq $preval, $newval, [$mem]" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ assert_different_registers($mem$$Register, $newval$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $preval$$Register /* pre_val (as a temporary register) */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */);
+ __ atomic_xchgal($preval$$Register, $newval$$Register, $mem$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_serial);
+%}
+
+instruct g1GetAndSetN(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set preval (GetAndSetN mem newval));
+ effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(2 * VOLATILE_REF_COST);
+ format %{ "atomic_xchgwu $preval, $newval, [$mem]" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ assert_different_registers($mem$$Register, $newval$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */);
+ __ atomic_xchgwu($preval$$Register, $newval$$Register, $mem$$Register);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_serial);
+%}
+
+instruct g1GetAndSetNAcq(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
+ match(Set preval (GetAndSetN mem newval));
+ effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(VOLATILE_REF_COST);
+ format %{ "atomic_xchgwu_acq $preval, $newval, [$mem]" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ assert_different_registers($mem$$Register, $newval$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */,
+ RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */);
+ __ atomic_xchgalwu($preval$$Register, $newval$$Register, $mem$$Register);
+ __ decode_heap_oop($tmp1$$Register, $newval$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_serial);
+%}
+
+instruct g1LoadP(iRegPNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_Load()->barrier_data() != 0);
+ match(Set dst (LoadP mem));
+ effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(LOAD_COST + BRANCH_COST);
+ format %{ "ld $dst, $mem\t# ptr" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ __ ld($dst$$Register, Address($mem$$Register));
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $dst$$Register /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(iload_reg_mem);
+%}
+
+instruct g1LoadN(iRegNNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_Load()->barrier_data() != 0);
+ match(Set dst (LoadN mem));
+ effect(TEMP dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(LOAD_COST + BRANCH_COST);
+ format %{ "lwu $dst, $mem\t# compressed ptr" %}
+ ins_encode %{
+ guarantee($mem$$disp == 0, "impossible encoding");
+ __ lwu($dst$$Register, Address($mem$$Register));
+ if ((barrier_data() & G1C2BarrierPre) != 0) {
+ __ decode_heap_oop($tmp1$$Register, $dst$$Register);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ }
+ %}
+ ins_pipe(iload_reg_mem);
+%}
diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp
index 0f385080977..d96d405aa22 100644
--- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -265,7 +265,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo
}
case NMethodPatchingType::conc_instruction_and_data_patch:
{
- // If we patch code we need both a code patching and a loadload
+ // If we patch code we need both a cmodx fence and a loadload
// fence. It's not super cheap, so we use a global epoch mechanism
// to hide them in a slow path.
// The high level idea of the global epoch mechanism is to detect
@@ -273,11 +273,19 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo
// last nmethod was disarmed. This implies that the required
// fencing has been performed for all preceding nmethod disarms
// as well. Therefore, we do not need any further fencing.
+
__ la(t1, ExternalAddress((address)&_patching_epoch));
- // Embed an artificial data dependency to order the guard load
- // before the epoch load.
- __ srli(ra, t0, 32);
- __ orr(t1, t1, ra);
+ if (!UseZtso) {
+ // Embed a synthetic data dependency between the load of the guard and
+ // the load of the epoch. This guarantees that these loads occur in
+ // order, while allowing other independent instructions to be reordered.
+ // Note: This may be slower than using a membar(load|load) (fence r,r).
+ // Because processors will not start the second load until the first comes back.
+ // This means you can’t overlap the two loads,
+ // which is stronger than needed for ordering (stronger than TSO).
+ __ srli(ra, t0, 32);
+ __ orr(t1, t1, ra);
+ }
// Read the global epoch value.
__ lwu(t1, t1);
// Combine the guard value (low order) with the epoch value (high order).
@@ -326,7 +334,7 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) {
__ load_method_holder_cld(t0, xmethod);
// Is it a strong CLD?
- __ lwu(t1, Address(t0, ClassLoaderData::keep_alive_offset()));
+ __ lwu(t1, Address(t0, ClassLoaderData::keep_alive_ref_count_offset()));
__ bnez(t1, method_live);
// Is it a weak but alive CLD?
diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp
index cd568cc723f..f503cb762e7 100644
--- a/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp
+++ b/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp
@@ -41,8 +41,6 @@ void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler* masm) {
Register tmp2 = _tmp2->as_register();
Register result = result_opr()->as_register();
- ShenandoahBarrierSet::assembler()->iu_barrier(masm->masm(), newval, t1);
-
if (UseCompressedOops) {
__ encode_heap_oop(tmp1, cmpval);
cmpval = tmp1;
@@ -94,10 +92,6 @@ LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRIt
value.load_item();
LIR_Opr value_opr = value.result();
- if (access.is_oop()) {
- value_opr = iu_barrier(access.gen(), value_opr, access.access_emit_info(), access.decorators());
- }
-
assert(type == T_INT || is_reference_type(type) LP64_ONLY( || type == T_LONG ), "unexpected type");
LIR_Opr tmp = gen->new_register(T_INT);
__ xchg(access.resolved_addr(), value_opr, result, tmp);
diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp
index 9be8259e7e8..cc73d14a756 100644
--- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp
@@ -48,7 +48,7 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec
Register src, Register dst, Register count, RegSet saved_regs) {
if (is_oop) {
bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
- if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahIUBarrier || ShenandoahLoadRefBarrier) {
+ if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) {
Label done;
@@ -70,10 +70,10 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec
__ push_reg(saved_regs, sp);
if (UseCompressedOops) {
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry),
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop),
src, dst, count);
} else {
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry), src, dst, count);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop), src, dst, count);
}
__ pop_reg(saved_regs, sp);
__ bind(done);
@@ -165,9 +165,9 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
// expand_call should be passed true.
if (expand_call) {
assert(pre_val != c_rarg1, "smashed arg");
- __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread);
+ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
} else {
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
}
__ pop_reg(saved, sp);
@@ -308,16 +308,6 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
__ leave();
}
-void ShenandoahBarrierSetAssembler::iu_barrier(MacroAssembler* masm, Register dst, Register tmp) {
- if (ShenandoahIUBarrier) {
- __ push_call_clobbered_registers();
-
- satb_write_barrier_pre(masm, noreg, dst, xthread, tmp, t0, true, false);
-
- __ pop_call_clobbered_registers();
- }
-}
-
//
// Arguments:
//
@@ -420,8 +410,7 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet
if (val == noreg) {
BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp3, 0), noreg, noreg, noreg, noreg);
} else {
- iu_barrier(masm, val, tmp1);
- // G1 barrier needs uncompressed oop for region cross check.
+ // Barrier needs uncompressed oop for region cross check.
Register new_val = val;
if (UseCompressedOops) {
new_val = t1;
@@ -656,7 +645,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss
__ bind(runtime);
__ push_call_clobbered_registers();
__ load_parameter(0, pre_val);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
__ pop_call_clobbered_registers();
__ bind(done);
diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp
index 0ae352f325d..bfdea7f607e 100644
--- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp
@@ -63,8 +63,6 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler {
public:
- void iu_barrier(MacroAssembler* masm, Register dst, Register tmp);
-
virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_data_patch; }
#ifdef COMPILER1
diff --git a/src/hotspot/cpu/riscv/gc/x/xBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/x/xBarrierSetAssembler_riscv.cpp
index 7306492970b..eb8d4c44b88 100644
--- a/src/hotspot/cpu/riscv/gc/x/xBarrierSetAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/gc/x/xBarrierSetAssembler_riscv.cpp
@@ -339,8 +339,8 @@ void XBarrierSetAssembler::generate_c2_load_barrier_stub(MacroAssembler* masm, X
XSaveLiveRegisters save_live_registers(masm, stub);
XSetupArguments setup_arguments(masm, stub);
- __ mv(t0, stub->slow_path());
- __ jalr(t0);
+ __ mv(t1, stub->slow_path());
+ __ jalr(t1);
}
// Stub exit
diff --git a/src/hotspot/cpu/riscv/gc/x/x_riscv.ad b/src/hotspot/cpu/riscv/gc/x/x_riscv.ad
index ef02f301c6a..b93b7066425 100644
--- a/src/hotspot/cpu/riscv/gc/x/x_riscv.ad
+++ b/src/hotspot/cpu/riscv/gc/x/x_riscv.ad
@@ -52,11 +52,11 @@ static void x_load_barrier_slow_path(MacroAssembler* masm, const MachNode* node,
%}
// Load Pointer
-instruct xLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp)
+instruct xLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp, rFlagsReg cr)
%{
match(Set dst (LoadP mem));
predicate(UseZGC && !ZGenerational && (n->as_Load()->barrier_data() != 0));
- effect(TEMP dst, TEMP tmp);
+ effect(TEMP dst, TEMP tmp, KILL cr);
ins_cost(4 * DEFAULT_COST);
@@ -71,11 +71,11 @@ instruct xLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp)
ins_pipe(iload_reg_mem);
%}
-instruct xCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{
+instruct xCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{
match(Set res (CompareAndSwapP mem (Binary oldval newval)));
match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
predicate(UseZGC && !ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong);
- effect(TEMP_DEF res, TEMP tmp);
+ effect(TEMP_DEF res, TEMP tmp, KILL cr);
ins_cost(2 * VOLATILE_REF_COST);
@@ -105,11 +105,11 @@ instruct xCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newva
ins_pipe(pipe_slow);
%}
-instruct xCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{
+instruct xCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{
match(Set res (CompareAndSwapP mem (Binary oldval newval)));
match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
predicate(UseZGC && !ZGenerational && needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() == XLoadBarrierStrong));
- effect(TEMP_DEF res, TEMP tmp);
+ effect(TEMP_DEF res, TEMP tmp, KILL cr);
ins_cost(2 * VOLATILE_REF_COST);
@@ -139,10 +139,10 @@ instruct xCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne
ins_pipe(pipe_slow);
%}
-instruct xCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{
+instruct xCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{
match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
predicate(UseZGC && !ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong);
- effect(TEMP_DEF res, TEMP tmp);
+ effect(TEMP_DEF res, TEMP tmp, KILL cr);
ins_cost(2 * VOLATILE_REF_COST);
@@ -167,10 +167,10 @@ instruct xCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP n
ins_pipe(pipe_slow);
%}
-instruct xCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp) %{
+instruct xCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{
match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
predicate(UseZGC && !ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == XLoadBarrierStrong);
- effect(TEMP_DEF res, TEMP tmp);
+ effect(TEMP_DEF res, TEMP tmp, KILL cr);
ins_cost(2 * VOLATILE_REF_COST);
@@ -195,10 +195,10 @@ instruct xCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iReg
ins_pipe(pipe_slow);
%}
-instruct xGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{
+instruct xGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp, rFlagsReg cr) %{
match(Set prev (GetAndSetP mem newv));
predicate(UseZGC && !ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
- effect(TEMP_DEF prev, TEMP tmp);
+ effect(TEMP_DEF prev, TEMP tmp, KILL cr);
ins_cost(2 * VOLATILE_REF_COST);
@@ -212,10 +212,10 @@ instruct xGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{
ins_pipe(pipe_serial);
%}
-instruct xGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{
+instruct xGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp, rFlagsReg cr) %{
match(Set prev (GetAndSetP mem newv));
predicate(UseZGC && !ZGenerational && needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() != 0));
- effect(TEMP_DEF prev, TEMP tmp);
+ effect(TEMP_DEF prev, TEMP tmp, KILL cr);
ins_cost(VOLATILE_REF_COST);
diff --git a/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp b/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp
index ef13676b02e..df111723d56 100644
--- a/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp
+++ b/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp
@@ -92,7 +92,7 @@ static size_t probe_valid_max_address_bit() {
}
size_t ZPlatformAddressOffsetBits() {
- const static size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1;
+ static const size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1;
const size_t max_address_offset_bits = valid_max_address_offset_bits - 3;
const size_t min_address_offset_bits = max_address_offset_bits - 2;
const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio);
diff --git a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp
index 8fbeaa45371..cd83eafcaeb 100644
--- a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp
@@ -636,8 +636,20 @@ void ZBarrierSetAssembler::patch_barrier_relocation(address addr, int format) {
ShouldNotReachHere();
}
- // A full fence is generated before icache_flush by default in invalidate_word
- ICache::invalidate_range(addr, bytes);
+ // If we are using UseCtxFencei no ICache invalidation is needed here.
+ // Instead every hart will preform an fence.i either by a Java thread
+ // (due to patching epoch will take it to slow path),
+ // or by the kernel when a Java thread is moved to a hart.
+ // The instruction streams changes must only happen before the disarm of
+ // the nmethod barrier. Where the disarm have a leading full two way fence.
+ // If this is performed during a safepoint, all Java threads will emit a fence.i
+ // before transitioning to 'Java', e.g. leaving native or the safepoint wait barrier.
+ if (!UseCtxFencei) {
+ // ICache invalidation is a serialization point.
+ // The above patching of instructions happens before the invalidation.
+ // Hence it have a leading full two way fence (wr, wr).
+ ICache::invalidate_range(addr, bytes);
+ }
}
#ifdef COMPILER2
@@ -712,8 +724,8 @@ void ZBarrierSetAssembler::generate_c2_load_barrier_stub(MacroAssembler* masm, Z
{
SaveLiveRegisters save_live_registers(masm, stub);
ZSetupArguments setup_arguments(masm, stub);
- __ mv(t0, stub->slow_path());
- __ jalr(t0);
+ __ mv(t1, stub->slow_path());
+ __ jalr(t1);
}
// Stub exit
@@ -746,13 +758,14 @@ void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm,
__ la(c_rarg0, stub->ref_addr());
if (stub->is_native()) {
- __ la(t0, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr()));
+ __ rt_call(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr());
} else if (stub->is_atomic()) {
- __ la(t0, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr()));
+ __ rt_call(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr());
+ } else if (stub->is_nokeepalive()) {
+ __ rt_call(ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr());
} else {
- __ la(t0, RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr()));
+ __ rt_call(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr());
}
- __ jalr(t0);
}
// Stub exit
diff --git a/src/hotspot/cpu/riscv/gc/z/z_riscv.ad b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad
index 4c94e504475..24669f45eb4 100644
--- a/src/hotspot/cpu/riscv/gc/z/z_riscv.ad
+++ b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad
@@ -82,7 +82,8 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address
z_color(masm, node, rnew_zpointer, rnew_zaddress, tmp);
} else {
bool is_native = (node->barrier_data() & ZBarrierNative) != 0;
- ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic);
+ bool is_nokeepalive = (node->barrier_data() & ZBarrierNoKeepalive) != 0;
+ ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic, is_nokeepalive);
ZBarrierSetAssembler* bs_asm = ZBarrierSet::assembler();
bs_asm->store_barrier_fast(masm, ref_addr, rnew_zaddress, rnew_zpointer, tmp, true /* in_nmethod */, is_atomic, *stub->entry(), *stub->continuation());
}
@@ -90,11 +91,11 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address
%}
// Load Pointer
-instruct zLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp)
+instruct zLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp, rFlagsReg cr)
%{
match(Set dst (LoadP mem));
predicate(UseZGC && ZGenerational && n->as_Load()->barrier_data() != 0);
- effect(TEMP dst, TEMP tmp);
+ effect(TEMP dst, TEMP tmp, KILL cr);
ins_cost(4 * DEFAULT_COST);
@@ -110,11 +111,11 @@ instruct zLoadP(iRegPNoSp dst, memory mem, iRegPNoSp tmp)
%}
// Store Pointer
-instruct zStoreP(memory mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2)
+instruct zStoreP(memory mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr)
%{
predicate(UseZGC && ZGenerational && n->as_Store()->barrier_data() != 0);
match(Set mem (StoreP mem src));
- effect(TEMP tmp1, TEMP tmp2);
+ effect(TEMP tmp1, TEMP tmp2, KILL cr);
ins_cost(125); // XXX
format %{ "sd $mem, $src\t# ptr" %}
@@ -127,11 +128,11 @@ instruct zStoreP(memory mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2)
%}
instruct zCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval,
- iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{
+ iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1, rFlagsReg cr) %{
match(Set res (CompareAndSwapP mem (Binary oldval newval)));
match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
predicate(UseZGC && ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
- effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res);
+ effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res, KILL cr);
ins_cost(2 * VOLATILE_REF_COST);
@@ -150,11 +151,11 @@ instruct zCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newva
%}
instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval,
- iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{
+ iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1, rFlagsReg cr) %{
match(Set res (CompareAndSwapP mem (Binary oldval newval)));
match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
predicate(UseZGC && ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
- effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res);
+ effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res, KILL cr);
ins_cost(2 * VOLATILE_REF_COST);
@@ -173,10 +174,10 @@ instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne
%}
instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval,
- iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{
+ iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1, rFlagsReg cr) %{
match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
predicate(UseZGC && ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
- effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res);
+ effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res, KILL cr);
ins_cost(2 * VOLATILE_REF_COST);
@@ -195,10 +196,10 @@ instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP n
%}
instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval,
- iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1) %{
+ iRegPNoSp oldval_tmp, iRegPNoSp newval_tmp, iRegPNoSp tmp1, rFlagsReg cr) %{
match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
predicate(UseZGC && ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
- effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res);
+ effect(TEMP oldval_tmp, TEMP newval_tmp, TEMP tmp1, TEMP_DEF res, KILL cr);
ins_cost(2 * VOLATILE_REF_COST);
@@ -216,10 +217,10 @@ instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iReg
ins_pipe(pipe_slow);
%}
-instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{
+instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp, rFlagsReg cr) %{
match(Set prev (GetAndSetP mem newv));
predicate(UseZGC && ZGenerational && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
- effect(TEMP_DEF prev, TEMP tmp);
+ effect(TEMP_DEF prev, TEMP tmp, KILL cr);
ins_cost(2 * VOLATILE_REF_COST);
@@ -234,10 +235,10 @@ instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{
ins_pipe(pipe_serial);
%}
-instruct zGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp) %{
+instruct zGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, iRegPNoSp tmp, rFlagsReg cr) %{
match(Set prev (GetAndSetP mem newv));
predicate(UseZGC && ZGenerational && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0);
- effect(TEMP_DEF prev, TEMP tmp);
+ effect(TEMP_DEF prev, TEMP tmp, KILL cr);
ins_cost(2 * VOLATILE_REF_COST);
diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp
index c2585f2d161..dd31de14704 100644
--- a/src/hotspot/cpu/riscv/globals_riscv.hpp
+++ b/src/hotspot/cpu/riscv/globals_riscv.hpp
@@ -122,6 +122,8 @@ define_pd_global(intx, InlineSmallCode, 1000);
product(bool, UseRVVForBigIntegerShiftIntrinsics, true, \
"Use RVV instructions for left/right shift of BigInteger") \
product(bool, UseTrampolines, false, EXPERIMENTAL, \
- "Far calls uses jal to trampoline.")
+ "Far calls uses jal to trampoline.") \
+ product(bool, UseCtxFencei, false, EXPERIMENTAL, \
+ "Use PR_RISCV_CTX_SW_FENCEI_ON to avoid explicit icache flush")
#endif // CPU_RISCV_GLOBALS_RISCV_HPP
diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp
index af6d043d1d6..fd75bde7655 100644
--- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp
+++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -421,13 +421,13 @@ void InterpreterMacroAssembler::jump_from_interpreted(Register method) {
// interp_only_mode if these events CAN be enabled.
lwu(t0, Address(xthread, JavaThread::interp_only_mode_offset()));
beqz(t0, run_compiled_code);
- ld(t0, Address(method, Method::interpreter_entry_offset()));
- jr(t0);
+ ld(t1, Address(method, Method::interpreter_entry_offset()));
+ jr(t1);
bind(run_compiled_code);
}
- ld(t0, Address(method, Method::from_interpreted_offset()));
- jr(t0);
+ ld(t1, Address(method, Method::from_interpreted_offset()));
+ jr(t1);
}
// The following two routines provide a hook so that an implementation
@@ -750,13 +750,13 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg)
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp, obj_reg);
- lwu(tmp, Address(tmp, Klass::access_flags_offset()));
- test_bit(tmp, tmp, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
+ lbu(tmp, Address(tmp, Klass::misc_flags_offset()));
+ test_bit(tmp, tmp, exact_log2(KlassFlags::_misc_is_value_based_class));
bnez(tmp, slow_case);
}
if (LockingMode == LM_LIGHTWEIGHT) {
- lightweight_lock(obj_reg, tmp, tmp2, tmp3, slow_case);
+ lightweight_lock(lock_reg, obj_reg, tmp, tmp2, tmp3, slow_case);
j(count);
} else if (LockingMode == LM_LEGACY) {
// Load (object->mark() | 1) into swap_reg
@@ -792,15 +792,9 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg)
bind(slow_case);
// Call the runtime routine for slow case
- if (LockingMode == LM_LIGHTWEIGHT) {
- call_VM(noreg,
- CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj),
- obj_reg);
- } else {
- call_VM(noreg,
- CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter),
- lock_reg);
- }
+ call_VM(noreg,
+ CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter),
+ lock_reg);
j(done);
bind(count);
diff --git a/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp b/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp
index 312e5cad963..a0ff429b87a 100644
--- a/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp
+++ b/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp
@@ -74,6 +74,16 @@ InterpreterRuntime::SignatureHandlerGenerator::SignatureHandlerGenerator(
_stack_offset = 0;
}
+// The C ABI specifies:
+// "integer scalars narrower than XLEN bits are widened according to the sign
+// of their type up to 32 bits, then sign-extended to XLEN bits."
+// Applies for both passed in register and stack.
+//
+// Java uses 32-bit stack slots; jint, jshort, jchar, jbyte uses one slot.
+// Native uses 64-bit stack slots for all integer scalar types.
+//
+// lw loads the Java stack slot, sign-extends and
+// sd store this widened integer into a 64 bit native stack slot.
void InterpreterRuntime::SignatureHandlerGenerator::pass_int() {
const Address src(from(), Interpreter::local_offset_in_bytes(offset()));
@@ -82,7 +92,7 @@ void InterpreterRuntime::SignatureHandlerGenerator::pass_int() {
__ lw(reg, src);
} else {
__ lw(x10, src);
- __ sw(x10, Address(to(), next_stack_offset()));
+ __ sd(x10, Address(to(), next_stack_offset()));
}
}
diff --git a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp
index 8423ecad8a3..f7d702c6310 100644
--- a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp
+++ b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -173,12 +173,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
{
__ enter();
- ExternalAddress target(slow_case_addr);
- __ relocate(target.rspec(), [&] {
- int32_t offset;
- __ la(t0, target.target(), offset);
- __ jalr(t0, offset);
- });
+ __ rt_call(slow_case_addr);
__ leave();
__ ret();
}
diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
index e349eab3177..7101f7d726e 100644
--- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
@@ -146,18 +146,6 @@ bool MacroAssembler::is_li32_at(address instr) {
check_li32_data_dependency(instr);
}
-bool MacroAssembler::is_li64_at(address instr) {
- return is_lui_at(instr) && // lui
- is_addi_at(instr + instruction_size) && // addi
- is_slli_shift_at(instr + instruction_size * 2, 12) && // Slli Rd, Rs, 12
- is_addi_at(instr + instruction_size * 3) && // addi
- is_slli_shift_at(instr + instruction_size * 4, 12) && // Slli Rd, Rs, 12
- is_addi_at(instr + instruction_size * 5) && // addi
- is_slli_shift_at(instr + instruction_size * 6, 8) && // Slli Rd, Rs, 8
- is_addi_at(instr + instruction_size * 7) && // addi
- check_li64_data_dependency(instr);
-}
-
bool MacroAssembler::is_lwu_to_zr(address instr) {
assert_cond(instr != nullptr);
return (extract_opcode(instr) == 0b0000011 &&
@@ -466,12 +454,7 @@ void MacroAssembler::call_VM_base(Register oop_result,
ld(t0, Address(java_thread, in_bytes(Thread::pending_exception_offset())));
Label ok;
beqz(t0, ok);
- RuntimeAddress target(StubRoutines::forward_exception_entry());
- relocate(target.rspec(), [&] {
- int32_t offset;
- la(t0, target.target(), offset);
- jr(t0, offset);
- });
+ j(RuntimeAddress(StubRoutines::forward_exception_entry()));
bind(ok);
}
@@ -505,6 +488,7 @@ void MacroAssembler::clinit_barrier(Register klass, Register tmp, Label* L_fast_
// Fast path check: class is fully initialized
lbu(tmp, Address(klass, InstanceKlass::init_state_offset()));
+ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
sub(tmp, tmp, InstanceKlass::fully_initialized);
beqz(tmp, *L_fast_path);
@@ -547,7 +531,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file,
}
// call indirectly to solve generation ordering problem
- ExternalAddress target(StubRoutines::verify_oop_subroutine_entry_address());
+ RuntimeAddress target(StubRoutines::verify_oop_subroutine_entry_address());
relocate(target.rspec(), [&] {
int32_t offset;
la(t1, target.target(), offset);
@@ -592,7 +576,7 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f
}
// call indirectly to solve generation ordering problem
- ExternalAddress target(StubRoutines::verify_oop_subroutine_entry_address());
+ RuntimeAddress target(StubRoutines::verify_oop_subroutine_entry_address());
relocate(target.rspec(), [&] {
int32_t offset;
la(t1, target.target(), offset);
@@ -771,21 +755,21 @@ void MacroAssembler::emit_static_call_stub() {
// Jump to the entry point of the c2i stub.
int32_t offset = 0;
- movptr(t0, 0, offset, t1); // lui + lui + slli + add
- jr(t0, offset);
+ movptr(t1, 0, offset, t0); // lui + lui + slli + add
+ jr(t1, offset);
}
void MacroAssembler::call_VM_leaf_base(address entry_point,
int number_of_arguments,
Label *retaddr) {
int32_t offset = 0;
- push_reg(RegSet::of(t0, xmethod), sp); // push << t0 & xmethod >> to sp
- mv(t0, entry_point, offset);
- jalr(t0, offset);
+ push_reg(RegSet::of(t1, xmethod), sp); // push << t1 & xmethod >> to sp
+ mv(t1, entry_point, offset);
+ jalr(t1, offset);
if (retaddr != nullptr) {
bind(*retaddr);
}
- pop_reg(RegSet::of(t0, xmethod), sp); // pop << t0 & xmethod >> from sp
+ pop_reg(RegSet::of(t1, xmethod), sp); // pop << t1 & xmethod >> from sp
}
void MacroAssembler::call_VM_leaf(address entry_point, int number_of_arguments) {
@@ -909,37 +893,9 @@ void MacroAssembler::li32(Register Rd, int32_t imm) {
upper = (int32_t)upper;
// lui Rd, imm[31:12] + imm[11]
lui(Rd, upper);
- // use addiw to distinguish li32 to li64
addiw(Rd, Rd, lower);
}
-void MacroAssembler::li64(Register Rd, int64_t imm) {
- // Load upper 32 bits. upper = imm[63:32], but if imm[31] == 1 or
- // (imm[31:20] == 0x7ff && imm[19] == 1), upper = imm[63:32] + 1.
- int64_t lower = imm & 0xffffffff;
- lower -= ((lower << 44) >> 44);
- int64_t tmp_imm = ((uint64_t)(imm & 0xffffffff00000000)) + (uint64_t)lower;
- int32_t upper = (tmp_imm - (int32_t)lower) >> 32;
-
- // Load upper 32 bits
- int64_t up = upper, lo = upper;
- lo = (lo << 52) >> 52;
- up -= lo;
- up = (int32_t)up;
- lui(Rd, up);
- addi(Rd, Rd, lo);
-
- // Load the rest 32 bits.
- slli(Rd, Rd, 12);
- addi(Rd, Rd, (int32_t)lower >> 20);
- slli(Rd, Rd, 12);
- lower = ((int32_t)imm << 12) >> 20;
- addi(Rd, Rd, lower);
- slli(Rd, Rd, 8);
- lower = imm & 0xff;
- addi(Rd, Rd, lower);
-}
-
void MacroAssembler::li(Register Rd, int64_t imm) {
// int64_t is in range 0x8000 0000 0000 0000 ~ 0x7fff ffff ffff ffff
// li -> c.li
@@ -980,6 +936,7 @@ void MacroAssembler::li(Register Rd, int64_t imm) {
void MacroAssembler::load_link_jump(const address source, Register temp) {
assert(temp != noreg && temp != x0, "expecting a register");
+ assert(temp != x5, "temp register must not be x5.");
assert_cond(source != nullptr);
int64_t distance = source - pc();
assert(is_simm32(distance), "Must be");
@@ -1007,24 +964,27 @@ void MacroAssembler::j(const address dest, Register temp) {
if (is_simm21(distance) && ((distance % 2) == 0)) {
Assembler::jal(x0, distance);
} else {
- assert(temp != noreg && temp != x0, "expecting a register");
+ assert(temp != noreg && temp != x0, "Expecting a register");
+ assert(temp != x1 && temp != x5, "temp register must not be x1/x5.");
int32_t offset = 0;
la(temp, dest, offset);
jr(temp, offset);
}
}
-void MacroAssembler::j(const Address &adr, Register temp) {
- switch (adr.getMode()) {
+void MacroAssembler::j(const Address &dest, Register temp) {
+ switch (dest.getMode()) {
case Address::literal: {
- relocate(adr.rspec(), [&] {
- j(adr.target(), temp);
+ relocate(dest.rspec(), [&] {
+ int32_t offset;
+ la(temp, dest.target(), offset);
+ jr(temp, offset);
});
break;
}
case Address::base_plus_offset: {
- int32_t offset = ((int32_t)adr.offset() << 20) >> 20;
- la(temp, Address(adr.base(), adr.offset() - offset));
+ int32_t offset = ((int32_t)dest.offset() << 20) >> 20;
+ la(temp, Address(dest.base(), dest.offset() - offset));
jr(temp, offset);
break;
}
@@ -1045,12 +1005,14 @@ void MacroAssembler::j(Label &lab, Register temp) {
void MacroAssembler::jr(Register Rd, int32_t offset) {
assert(Rd != noreg, "expecting a register");
+ assert(Rd != x1 && Rd != x5, "Rd register must not be x1/x5.");
Assembler::jalr(x0, Rd, offset);
}
void MacroAssembler::call(const address dest, Register temp) {
assert_cond(dest != nullptr);
assert(temp != noreg, "expecting a register");
+ assert(temp != x5, "temp register must not be x5.");
int32_t offset = 0;
la(temp, dest, offset);
jalr(temp, offset);
@@ -1058,10 +1020,12 @@ void MacroAssembler::call(const address dest, Register temp) {
void MacroAssembler::jalr(Register Rs, int32_t offset) {
assert(Rs != noreg, "expecting a register");
+ assert(Rs != x5, "Rs register must not be x5.");
Assembler::jalr(x1, Rs, offset);
}
void MacroAssembler::rt_call(address dest, Register tmp) {
+ assert(tmp != x5, "tmp register must not be x5.");
CodeBlob *cb = CodeCache::find_blob(dest);
RuntimeAddress target(dest);
if (cb) {
@@ -1494,6 +1458,105 @@ void MacroAssembler::update_word_crc32(Register crc, Register v, Register tmp1,
xorr(crc, crc, tmp2);
}
+
+#ifdef COMPILER2
+// This improvement (vectorization) is based on java.base/share/native/libzip/zlib/zcrc32.c.
+// To make it, following steps are taken:
+// 1. in zcrc32.c, modify N to 16 and related code,
+// 2. re-generate the tables needed, we use tables of (N == 16, W == 4)
+// 3. finally vectorize the code (original implementation in zcrc32.c is just scalar code).
+// New tables for vector version is after table3.
+void MacroAssembler::vector_update_crc32(Register crc, Register buf, Register len,
+ Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5,
+ Register table0, Register table3) {
+ assert_different_registers(t1, crc, buf, len, tmp1, tmp2, tmp3, tmp4, tmp5, table0, table3);
+ const int N = 16, W = 4;
+ const int64_t single_table_size = 256;
+ const Register blks = tmp2;
+ const Register tmpTable = tmp3, tableN16 = tmp4;
+ const VectorRegister vcrc = v4, vword = v8, vtmp = v12;
+ Label VectorLoop;
+ Label LastBlock;
+
+ add(tableN16, table3, 1*single_table_size*sizeof(juint), tmp1);
+ mv(tmp5, 0xff);
+
+ if (MaxVectorSize == 16) {
+ vsetivli(zr, N, Assembler::e32, Assembler::m4, Assembler::ma, Assembler::ta);
+ } else if (MaxVectorSize == 32) {
+ vsetivli(zr, N, Assembler::e32, Assembler::m2, Assembler::ma, Assembler::ta);
+ } else {
+ assert(MaxVectorSize > 32, "sanity");
+ vsetivli(zr, N, Assembler::e32, Assembler::m1, Assembler::ma, Assembler::ta);
+ }
+
+ vmv_v_x(vcrc, zr);
+ vmv_s_x(vcrc, crc);
+
+ // multiple of 64
+ srli(blks, len, 6);
+ slli(t1, blks, 6);
+ sub(len, len, t1);
+ sub(blks, blks, 1);
+ blez(blks, LastBlock);
+
+ bind(VectorLoop);
+ {
+ mv(tmpTable, tableN16);
+
+ vle32_v(vword, buf);
+ vxor_vv(vword, vword, vcrc);
+
+ addi(buf, buf, N*4);
+
+ vand_vx(vtmp, vword, tmp5);
+ vsll_vi(vtmp, vtmp, 2);
+ vluxei32_v(vcrc, tmpTable, vtmp);
+
+ mv(tmp1, 1);
+ for (int k = 1; k < W; k++) {
+ addi(tmpTable, tmpTable, single_table_size*4);
+
+ slli(t1, tmp1, 3);
+ vsrl_vx(vtmp, vword, t1);
+
+ vand_vx(vtmp, vtmp, tmp5);
+ vsll_vi(vtmp, vtmp, 2);
+ vluxei32_v(vtmp, tmpTable, vtmp);
+
+ vxor_vv(vcrc, vcrc, vtmp);
+
+ addi(tmp1, tmp1, 1);
+ }
+
+ sub(blks, blks, 1);
+ bgtz(blks, VectorLoop);
+ }
+
+ bind(LastBlock);
+ {
+ vle32_v(vtmp, buf);
+ vxor_vv(vcrc, vcrc, vtmp);
+ mv(crc, zr);
+ for (int i = 0; i < N; i++) {
+ vmv_x_s(tmp2, vcrc);
+ // in vmv_x_s, the value is sign-extended to SEW bits, but we need zero-extended here.
+ zext_w(tmp2, tmp2);
+ vslidedown_vi(vcrc, vcrc, 1);
+ xorr(crc, crc, tmp2);
+ for (int j = 0; j < W; j++) {
+ andr(t1, crc, tmp5);
+ shadd(t1, t1, table0, tmp1, 2);
+ lwu(t1, Address(t1, 0));
+ srli(tmp2, crc, 8);
+ xorr(crc, tmp2, t1);
+ }
+ }
+ addi(buf, buf, N*4);
+ }
+}
+#endif // COMPILER2
+
/**
* @param crc register containing existing CRC (32-bit)
* @param buf register pointing to input byte buffer (byte*)
@@ -1505,33 +1568,41 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len,
Register table0, Register table1, Register table2, Register table3,
Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6) {
assert_different_registers(crc, buf, len, table0, table1, table2, table3, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6);
- Label L_by16_loop, L_unroll_loop, L_unroll_loop_entry, L_by4, L_by4_loop, L_by1, L_by1_loop, L_exit;
+ Label L_vector_entry,
+ L_unroll_loop,
+ L_by4_loop_entry, L_by4_loop,
+ L_by1_loop, L_exit;
+ const int64_t single_table_size = 256;
const int64_t unroll = 16;
const int64_t unroll_words = unroll*wordSize;
mv(tmp5, right_32_bits);
- subw(len, len, unroll_words);
andn(crc, tmp5, crc);
const ExternalAddress table_addr = StubRoutines::crc_table_addr();
la(table0, table_addr);
- add(table1, table0, 1*256*sizeof(juint), tmp1);
- add(table2, table0, 2*256*sizeof(juint), tmp1);
- add(table3, table2, 1*256*sizeof(juint), tmp1);
+ add(table1, table0, 1*single_table_size*sizeof(juint), tmp1);
+ add(table2, table0, 2*single_table_size*sizeof(juint), tmp1);
+ add(table3, table2, 1*single_table_size*sizeof(juint), tmp1);
+
+#ifdef COMPILER2
+ if (UseRVV) {
+ const int64_t tmp_limit = MaxVectorSize >= 32 ? unroll_words*3 : unroll_words*5;
+ mv(tmp1, tmp_limit);
+ bge(len, tmp1, L_vector_entry);
+ }
+#endif // COMPILER2
+
+ mv(tmp1, unroll_words);
+ blt(len, tmp1, L_by4_loop_entry);
- bge(len, zr, L_unroll_loop_entry);
- addiw(len, len, unroll_words-4);
- bge(len, zr, L_by4_loop);
- addiw(len, len, 4);
- bgt(len, zr, L_by1_loop);
- j(L_exit);
+ const Register loop_buf_end = tmp3;
align(CodeEntryAlignment);
- bind(L_unroll_loop_entry);
- const Register buf_end = tmp3;
- add(buf_end, buf, len); // buf_end will be used as endpoint for loop below
+ // Entry for L_unroll_loop
+ add(loop_buf_end, buf, len); // loop_buf_end will be used as endpoint for loop below
andi(len, len, unroll_words-1); // len = (len % unroll_words)
- sub(len, len, unroll_words); // Length after all iterations
+ sub(loop_buf_end, loop_buf_end, len);
bind(L_unroll_loop);
for (int i = 0; i < unroll; i++) {
ld(tmp1, Address(buf, i*wordSize));
@@ -1540,44 +1611,52 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len,
}
addi(buf, buf, unroll_words);
- ble(buf, buf_end, L_unroll_loop);
- addiw(len, len, unroll_words-4);
- bge(len, zr, L_by4_loop);
- addiw(len, len, 4);
- bgt(len, zr, L_by1_loop);
- j(L_exit);
-
+ blt(buf, loop_buf_end, L_unroll_loop);
+
+ bind(L_by4_loop_entry);
+ mv(tmp1, 4);
+ blt(len, tmp1, L_by1_loop);
+ add(loop_buf_end, buf, len); // loop_buf_end will be used as endpoint for loop below
+ andi(len, len, 3);
+ sub(loop_buf_end, loop_buf_end, len);
bind(L_by4_loop);
lwu(tmp1, Address(buf));
update_word_crc32(crc, tmp1, tmp2, tmp4, tmp6, table0, table1, table2, table3, false);
- subw(len, len, 4);
addi(buf, buf, 4);
- bge(len, zr, L_by4_loop);
- addiw(len, len, 4);
- ble(len, zr, L_exit);
+ blt(buf, loop_buf_end, L_by4_loop);
bind(L_by1_loop);
+ beqz(len, L_exit);
+
subw(len, len, 1);
lwu(tmp1, Address(buf));
andi(tmp2, tmp1, right_8_bits);
update_byte_crc32(crc, tmp2, table0);
- ble(len, zr, L_exit);
+ beqz(len, L_exit);
subw(len, len, 1);
srli(tmp2, tmp1, 8);
andi(tmp2, tmp2, right_8_bits);
update_byte_crc32(crc, tmp2, table0);
- ble(len, zr, L_exit);
+ beqz(len, L_exit);
subw(len, len, 1);
srli(tmp2, tmp1, 16);
andi(tmp2, tmp2, right_8_bits);
update_byte_crc32(crc, tmp2, table0);
- ble(len, zr, L_exit);
- srli(tmp2, tmp1, 24);
- andi(tmp2, tmp2, right_8_bits);
- update_byte_crc32(crc, tmp2, table0);
+#ifdef COMPILER2
+ // put vector code here, otherwise "offset is too large" error occurs.
+ if (UseRVV) {
+ // only need to jump exit when UseRVV == true, it's a jump from end of block `L_by1_loop`.
+ j(L_exit);
+
+ bind(L_vector_entry);
+ vector_update_crc32(crc, buf, len, tmp1, tmp2, tmp3, tmp4, tmp6, table0, table3);
+
+ bgtz(len, L_by4_loop_entry);
+ }
+#endif // COMPILER2
bind(L_exit);
andn(crc, tmp5, crc);
@@ -1686,7 +1765,7 @@ void MacroAssembler::pop_CPU_state(bool restore_vectors, int vector_size_in_byte
static int patch_offset_in_jal(address branch, int64_t offset) {
assert(Assembler::is_simm21(offset) && ((offset % 2) == 0),
- "offset is too large to be patched in one jal instruction!\n");
+ "offset (%ld) is too large to be patched in one jal instruction!\n", offset);
Assembler::patch(branch, 31, 31, (offset >> 20) & 0x1); // offset[20] ==> branch[31]
Assembler::patch(branch, 30, 21, (offset >> 1) & 0x3ff); // offset[10:1] ==> branch[30:21]
Assembler::patch(branch, 20, 20, (offset >> 11) & 0x1); // offset[11] ==> branch[20]
@@ -1741,27 +1820,6 @@ static int patch_addr_in_movptr2(address instruction_address, address target) {
return MacroAssembler::movptr2_instruction_size;
}
-static int patch_imm_in_li64(address branch, address target) {
- const int LI64_INSTRUCTIONS_NUM = 8; // lui + addi + slli + addi + slli + addi + slli + addi
- int64_t lower = (intptr_t)target & 0xffffffff;
- lower = lower - ((lower << 44) >> 44);
- int64_t tmp_imm = ((uint64_t)((intptr_t)target & 0xffffffff00000000)) + (uint64_t)lower;
- int32_t upper = (tmp_imm - (int32_t)lower) >> 32;
- int64_t tmp_upper = upper, tmp_lower = upper;
- tmp_lower = (tmp_lower << 52) >> 52;
- tmp_upper -= tmp_lower;
- tmp_upper >>= 12;
- // Load upper 32 bits. Upper = target[63:32], but if target[31] = 1 or (target[31:20] == 0x7ff && target[19] == 1),
- // upper = target[63:32] + 1.
- Assembler::patch(branch + 0, 31, 12, tmp_upper & 0xfffff); // Lui.
- Assembler::patch(branch + 4, 31, 20, tmp_lower & 0xfff); // Addi.
- // Load the rest 32 bits.
- Assembler::patch(branch + 12, 31, 20, ((int32_t)lower >> 20) & 0xfff); // Addi.
- Assembler::patch(branch + 20, 31, 20, (((intptr_t)target << 44) >> 52) & 0xfff); // Addi.
- Assembler::patch(branch + 28, 31, 20, (intptr_t)target & 0xff); // Addi.
- return LI64_INSTRUCTIONS_NUM * MacroAssembler::instruction_size;
-}
-
static int patch_imm_in_li16u(address branch, uint16_t target) {
Assembler::patch(branch, 31, 12, target); // patch lui only
return MacroAssembler::instruction_size;
@@ -1832,16 +1890,6 @@ static address get_target_of_movptr2(address insn_addr) {
return ret;
}
-static address get_target_of_li64(address insn_addr) {
- assert_cond(insn_addr != nullptr);
- intptr_t target_address = (((int64_t)Assembler::sextract(Assembler::ld_instr(insn_addr), 31, 12)) & 0xfffff) << 44; // Lui.
- target_address += ((int64_t)Assembler::sextract(Assembler::ld_instr(insn_addr + 4), 31, 20)) << 32; // Addi.
- target_address += ((int64_t)Assembler::sextract(Assembler::ld_instr(insn_addr + 12), 31, 20)) << 20; // Addi.
- target_address += ((int64_t)Assembler::sextract(Assembler::ld_instr(insn_addr + 20), 31, 20)) << 8; // Addi.
- target_address += ((int64_t)Assembler::sextract(Assembler::ld_instr(insn_addr + 28), 31, 20)); // Addi.
- return (address)target_address;
-}
-
address MacroAssembler::get_target_of_li32(address insn_addr) {
assert_cond(insn_addr != nullptr);
intptr_t target_address = (((int64_t)Assembler::sextract(Assembler::ld_instr(insn_addr), 31, 12)) & 0xfffff) << 12; // Lui.
@@ -1864,8 +1912,6 @@ int MacroAssembler::pd_patch_instruction_size(address instruction_address, addre
return patch_addr_in_movptr1(instruction_address, target);
} else if (MacroAssembler::is_movptr2_at(instruction_address)) { // movptr2
return patch_addr_in_movptr2(instruction_address, target);
- } else if (MacroAssembler::is_li64_at(instruction_address)) { // li64
- return patch_imm_in_li64(instruction_address, target);
} else if (MacroAssembler::is_li32_at(instruction_address)) { // li32
int64_t imm = (intptr_t)target;
return patch_imm_in_li32(instruction_address, (int32_t)imm);
@@ -1896,8 +1942,6 @@ address MacroAssembler::target_addr_for_insn(address insn_addr) {
return get_target_of_movptr1(insn_addr);
} else if (MacroAssembler::is_movptr2_at(insn_addr)) { // movptr2
return get_target_of_movptr2(insn_addr);
- } else if (MacroAssembler::is_li64_at(insn_addr)) { // li64
- return get_target_of_li64(insn_addr);
} else if (MacroAssembler::is_li32_at(insn_addr)) { // li32
return get_target_of_li32(insn_addr);
} else {
@@ -1928,9 +1972,9 @@ int MacroAssembler::patch_oop(address insn_addr, address o) {
void MacroAssembler::reinit_heapbase() {
if (UseCompressedOops) {
if (Universe::is_fully_initialized()) {
- mv(xheapbase, CompressedOops::ptrs_base());
+ mv(xheapbase, CompressedOops::base());
} else {
- ExternalAddress target(CompressedOops::ptrs_base_addr());
+ ExternalAddress target(CompressedOops::base_addr());
relocate(target.rspec(), [&] {
int32_t offset;
la(xheapbase, target.target(), offset);
@@ -2043,23 +2087,11 @@ void MacroAssembler::addw(Register Rd, Register Rn, int32_t increment, Register
}
void MacroAssembler::sub(Register Rd, Register Rn, int64_t decrement, Register temp) {
- if (is_simm12(-decrement)) {
- addi(Rd, Rn, -decrement);
- } else {
- assert_different_registers(Rn, temp);
- li(temp, decrement);
- sub(Rd, Rn, temp);
- }
+ add(Rd, Rn, -decrement, temp);
}
void MacroAssembler::subw(Register Rd, Register Rn, int32_t decrement, Register temp) {
- if (is_simm12(-decrement)) {
- addiw(Rd, Rn, -decrement);
- } else {
- assert_different_registers(Rn, temp);
- li(temp, decrement);
- subw(Rd, Rn, temp);
- }
+ addw(Rd, Rn, -decrement, temp);
}
void MacroAssembler::andrw(Register Rd, Register Rs1, Register Rs2) {
@@ -2919,7 +2951,7 @@ int MacroAssembler::corrected_idivq(Register result, Register rs1, Register rs2,
return idivq_offset;
}
-// Look up the method for a megamorpic invkkeinterface call.
+// Look up the method for a megamorphic invokeinterface call.
// The target method is determined by .
// The receiver klass is in recv_klass.
// On success, the result will be in method_result, and execution falls through.
@@ -2934,9 +2966,9 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
assert_different_registers(recv_klass, intf_klass, scan_tmp);
assert_different_registers(method_result, intf_klass, scan_tmp);
assert(recv_klass != method_result || !return_method,
- "recv_klass can be destroyed when mehtid isn't needed");
+ "recv_klass can be destroyed when method isn't needed");
assert(itable_index.is_constant() || itable_index.as_register() == method_result,
- "caller must be same register for non-constant itable index as for method");
+ "caller must use same register for non-constant itable index as for method");
// Compute start of first itableOffsetEntry (which is at the end of the vtable).
int vtable_base = in_bytes(Klass::vtable_start_offset());
@@ -3129,6 +3161,13 @@ void MacroAssembler::membar(uint32_t order_constraint) {
}
}
+void MacroAssembler::cmodx_fence() {
+ BLOCK_COMMENT("cmodx fence");
+ if (VM_Version::supports_fencei_barrier()) {
+ Assembler::fencei();
+ }
+}
+
// Form an address from base + offset in Rd. Rd my or may not
// actually be used: you must use the Address that is returned. It
// is up to you to ensure that the shift provided matches the size
@@ -3605,19 +3644,24 @@ void MacroAssembler::atomic_cas(
void MacroAssembler::far_jump(const Address &entry, Register tmp) {
assert(CodeCache::find_blob(entry.target()) != nullptr,
- "destination of far call not found in code cache");
+ "destination of far jump not found in code cache");
assert(entry.rspec().type() == relocInfo::external_word_type
|| entry.rspec().type() == relocInfo::runtime_call_type
|| entry.rspec().type() == relocInfo::none, "wrong entry relocInfo type");
// Fixed length: see MacroAssembler::far_branch_size()
+ // We can use auipc + jr here because we know that the total size of
+ // the code cache cannot exceed 2Gb.
relocate(entry.rspec(), [&] {
- int32_t offset;
- la(tmp, entry.target(), offset);
+ int64_t distance = entry.target() - pc();
+ int32_t offset = ((int32_t)distance << 20) >> 20;
+ assert(is_valid_32bit_offset(distance), "Far jump using wrong instructions.");
+ auipc(tmp, (int32_t)distance + 0x800);
jr(tmp, offset);
});
}
void MacroAssembler::far_call(const Address &entry, Register tmp) {
+ assert(tmp != x5, "tmp register must not be x5.");
assert(CodeCache::find_blob(entry.target()) != nullptr,
"destination of far call not found in code cache");
assert(entry.rspec().type() == relocInfo::external_word_type
@@ -3627,8 +3671,11 @@ void MacroAssembler::far_call(const Address &entry, Register tmp) {
// We can use auipc + jalr here because we know that the total size of
// the code cache cannot exceed 2Gb.
relocate(entry.rspec(), [&] {
- assert(is_valid_32bit_offset(entry.target() - pc()), "Far call using wrong instructions.");
- call(entry.target(), tmp);
+ int64_t distance = entry.target() - pc();
+ int32_t offset = ((int32_t)distance << 20) >> 20;
+ assert(is_valid_32bit_offset(distance), "Far call using wrong instructions.");
+ auipc(tmp, (int32_t)distance + 0x800);
+ jalr(tmp, offset);
});
}
@@ -3973,8 +4020,8 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl
// Check if bitmap is SECONDARY_SUPERS_BITMAP_FULL
assert(Klass::SECONDARY_SUPERS_BITMAP_FULL == ~uintx(0), "Adjust this code");
- addi(t0, r_bitmap, (u1)1);
- beqz(t0, L_bitmap_full);
+ subw(t0, r_array_length, Klass::SECONDARY_SUPERS_TABLE_SIZE - 2);
+ bgtz(t0, L_bitmap_full);
// NB! Our caller has checked bits 0 and 1 in the bitmap. The
// current slot (at secondary_supers[r_array_index]) has not yet
@@ -4029,7 +4076,7 @@ void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass,
Register tmp1,
Register tmp2,
Register tmp3) {
- assert_different_registers(r_sub_klass, r_super_klass, tmp1, tmp2, tmp3, result, t0);
+ assert_different_registers(r_sub_klass, r_super_klass, tmp1, tmp2, tmp3, result, t0, t1);
const Register
r_array_base = tmp1, // X11
@@ -4096,8 +4143,8 @@ void MacroAssembler::get_thread(Register thread) {
RegSet::range(x28, x31) + ra - thread;
push_reg(saved_regs, sp);
- mv(ra, CAST_FROM_FN_PTR(address, Thread::current));
- jalr(ra);
+ mv(t1, CAST_FROM_FN_PTR(address, Thread::current));
+ jalr(t1);
if (thread != c_rarg0) {
mv(thread, c_rarg0);
}
@@ -4130,29 +4177,24 @@ void MacroAssembler::remove_frame(int framesize) {
}
void MacroAssembler::reserved_stack_check() {
- // testing if reserved zone needs to be enabled
- Label no_reserved_zone_enabling;
+ // testing if reserved zone needs to be enabled
+ Label no_reserved_zone_enabling;
- ld(t0, Address(xthread, JavaThread::reserved_stack_activation_offset()));
- bltu(sp, t0, no_reserved_zone_enabling);
+ ld(t0, Address(xthread, JavaThread::reserved_stack_activation_offset()));
+ bltu(sp, t0, no_reserved_zone_enabling);
- enter(); // RA and FP are live.
- mv(c_rarg0, xthread);
- rt_call(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone));
- leave();
+ enter(); // RA and FP are live.
+ mv(c_rarg0, xthread);
+ rt_call(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone));
+ leave();
- // We have already removed our own frame.
- // throw_delayed_StackOverflowError will think that it's been
- // called by our caller.
- RuntimeAddress target(StubRoutines::throw_delayed_StackOverflowError_entry());
- relocate(target.rspec(), [&] {
- int32_t offset;
- movptr(t0, target.target(), offset);
- jr(t0, offset);
- });
- should_not_reach_here();
+ // We have already removed our own frame.
+ // throw_delayed_StackOverflowError will think that it's been
+ // called by our caller.
+ j(RuntimeAddress(SharedRuntime::throw_delayed_StackOverflowError_entry()));
+ should_not_reach_here();
- bind(no_reserved_zone_enabling);
+ bind(no_reserved_zone_enabling);
}
// Move the address of the polling page into dest.
@@ -4260,7 +4302,7 @@ address MacroAssembler::load_and_call(Address entry) {
}
#endif
relocate(entry.rspec(), [&] {
- load_link_jump(target);
+ load_link_jump(target, t1);
});
postcond(pc() != badAddress);
@@ -4270,7 +4312,7 @@ address MacroAssembler::load_and_call(Address entry) {
address MacroAssembler::ic_call(address entry, jint method_index) {
RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index);
IncompressibleRegion ir(this); // relocations
- movptr(t1, (address)Universe::non_oop_word(), t0);
+ movptr(t0, (address)Universe::non_oop_word(), t1);
assert_cond(entry != nullptr);
return reloc_call(Address(entry, rh));
}
@@ -4284,9 +4326,9 @@ int MacroAssembler::ic_check_size() {
int MacroAssembler::ic_check(int end_alignment) {
IncompressibleRegion ir(this);
Register receiver = j_rarg0;
- Register data = t1;
+ Register data = t0;
- Register tmp1 = t0; // t0 always scratch
+ Register tmp1 = t1; // scratch
// t2 is saved on call, thus should have been saved before this check.
// Hence we can clobber it.
Register tmp2 = t2;
@@ -4384,8 +4426,8 @@ address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset,
// - load the call
// - call
Label target;
- ld(t0, target); // auipc + ld
- jr(t0); // jalr
+ ld(t1, target); // auipc + ld
+ jr(t1); // jalr
bind(target);
assert(offset() - stub_start_offset == MacroAssembler::NativeShortCall::trampoline_data_offset,
"should be");
@@ -5109,11 +5151,11 @@ const int MacroAssembler::zero_words_block_size = 8;
// ptr: Address of a buffer to be zeroed.
// cnt: Count in HeapWords.
//
-// ptr, cnt, and t0 are clobbered.
+// ptr, cnt, t1, and t0 are clobbered.
address MacroAssembler::zero_words(Register ptr, Register cnt) {
assert(is_power_of_2(zero_words_block_size), "adjust this");
assert(ptr == x28 && cnt == x29, "mismatch in register usage");
- assert_different_registers(cnt, t0);
+ assert_different_registers(cnt, t0, t1);
BLOCK_COMMENT("zero_words {");
@@ -5131,6 +5173,7 @@ address MacroAssembler::zero_words(Register ptr, Register cnt) {
return nullptr;
}
} else {
+ // Clobbers t1
rt_call(zero_blocks.target());
}
}
@@ -5598,15 +5641,21 @@ static int reg2offset_out(VMReg r) {
return (r->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size;
}
-// On 64 bit we will store integer like items to the stack as
-// 64 bits items (riscv64 abi) even though java would only store
-// 32bits for a parameter. On 32bit it will simply be 32 bits
-// So this routine will do 32->32 on 32bit and 32->64 on 64bit
+// The C ABI specifies:
+// "integer scalars narrower than XLEN bits are widened according to the sign
+// of their type up to 32 bits, then sign-extended to XLEN bits."
+// Applies for both passed in register and stack.
+//
+// Java uses 32-bit stack slots; jint, jshort, jchar, jbyte uses one slot.
+// Native uses 64-bit stack slots for all integer scalar types.
+//
+// lw loads the Java stack slot, sign-extends and
+// sd store this widened integer into a 64 bit native stack slot.
void MacroAssembler::move32_64(VMRegPair src, VMRegPair dst, Register tmp) {
if (src.first()->is_stack()) {
if (dst.first()->is_stack()) {
// stack to stack
- ld(tmp, Address(fp, reg2offset_in(src.first())));
+ lw(tmp, Address(fp, reg2offset_in(src.first())));
sd(tmp, Address(sp, reg2offset_out(dst.first())));
} else {
// stack to reg
@@ -5796,9 +5845,9 @@ void MacroAssembler::test_bit(Register Rd, Register Rs, uint32_t bit_pos) {
// - obj: the object to be locked
// - tmp1, tmp2, tmp3: temporary registers, will be destroyed
// - slow: branched to if locking fails
-void MacroAssembler::lightweight_lock(Register obj, Register tmp1, Register tmp2, Register tmp3, Label& slow) {
+void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Register tmp1, Register tmp2, Register tmp3, Label& slow) {
assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking");
- assert_different_registers(obj, tmp1, tmp2, tmp3, t0);
+ assert_different_registers(basic_lock, obj, tmp1, tmp2, tmp3, t0);
Label push;
const Register top = tmp1;
@@ -5809,6 +5858,11 @@ void MacroAssembler::lightweight_lock(Register obj, Register tmp1, Register tmp2
// instruction emitted as it is part of C1's null check semantics.
ld(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
+ if (UseObjectMonitorTable) {
+ // Clear cache in case fast locking succeeds.
+ sd(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))));
+ }
+
// Check if the lock-stack is full.
lwu(top, Address(xthread, JavaThread::lock_stack_top_offset()));
mv(t, (unsigned)LockStack::end_offset());
diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
index 3c1add90367..fda3badf350 100644
--- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
@@ -431,6 +431,8 @@ class MacroAssembler: public Assembler {
}
}
+ void cmodx_fence();
+
void pause() {
Assembler::fence(w, 0);
}
@@ -625,7 +627,7 @@ class MacroAssembler: public Assembler {
void bgtz(Register Rs, const address dest);
private:
- void load_link_jump(const address source, Register temp = t0);
+ void load_link_jump(const address source, Register temp);
void jump_link(const address dest, Register temp);
public:
// We try to follow risc-v asm menomics.
@@ -633,18 +635,42 @@ class MacroAssembler: public Assembler {
// we often need to resort to movptr, li <48imm>.
// https://github.com/riscv-non-isa/riscv-asm-manual/blob/master/riscv-asm.md
+ // Hotspot only use the standard calling convention using x1/ra.
+ // The alternative calling convection using x5/t0 is not used.
+ // Using x5 as a temp causes the CPU to mispredict returns.
+
+ // JALR, return address stack updates:
+ // | rd is x1/x5 | rs1 is x1/x5 | rd=rs1 | RAS action
+ // | ----------- | ------------ | ------ |-------------
+ // | No | No | — | None
+ // | No | Yes | — | Pop
+ // | Yes | No | — | Push
+ // | Yes | Yes | No | Pop, then push
+ // | Yes | Yes | Yes | Push
+ //
+ // JAL, return address stack updates:
+ // | rd is x1/x5 | RAS action
+ // | ----------- | ----------
+ // | Yes | Push
+ // | No | None
+ //
+ // JUMPs uses Rd = x0/zero and Rs = x6/t1 or imm
+ // CALLS uses Rd = x1/ra and Rs = x6/t1 or imm (or x1/ra*)
+ // RETURNS uses Rd = x0/zero and Rs = x1/ra
+ // *use of x1/ra should not normally be used, special case only.
+
// jump: jal x0, offset
// For long reach uses temp register for:
// la + jr
- void j(const address dest, Register temp = t0);
- void j(const Address &adr, Register temp = t0);
- void j(Label &l, Register temp = t0);
+ void j(const address dest, Register temp = t1);
+ void j(const Address &dest, Register temp = t1);
+ void j(Label &l, Register temp = noreg);
// jump register: jalr x0, offset(rs)
void jr(Register Rd, int32_t offset = 0);
// call: la + jalr x1
- void call(const address dest, Register temp = t0);
+ void call(const address dest, Register temp = t1);
// jalr: jalr x1, offset(rs)
void jalr(Register Rs, int32_t offset = 0);
@@ -652,7 +678,8 @@ class MacroAssembler: public Assembler {
// Emit a runtime call. Only invalidates the tmp register which
// is used to keep the entry address for jalr/movptr.
// Uses call() for intra code cache, else movptr + jalr.
- void rt_call(address dest, Register tmp = t0);
+ // Clobebrs t1
+ void rt_call(address dest, Register tmp = t1);
// ret: jalr x0, 0(x1)
inline void ret() {
@@ -813,7 +840,6 @@ class MacroAssembler: public Assembler {
void li16u(Register Rd, uint16_t imm);
void li32(Register Rd, int32_t imm);
- void li64(Register Rd, int64_t imm);
void li (Register Rd, int64_t imm); // optimized load immediate
// mv
@@ -1164,8 +1190,9 @@ class MacroAssembler: public Assembler {
// - relocInfo::external_word_type
// - relocInfo::runtime_call_type
// - relocInfo::none
- void far_call(const Address &entry, Register tmp = t0);
- void far_jump(const Address &entry, Register tmp = t0);
+ // Clobbers t1 default.
+ void far_call(const Address &entry, Register tmp = t1);
+ void far_jump(const Address &entry, Register tmp = t1);
static int far_branch_size() {
return 2 * 4; // auipc + jalr, see far_call() & far_jump()
@@ -1322,6 +1349,10 @@ class MacroAssembler: public Assembler {
void update_byte_crc32(Register crc, Register val, Register table);
#ifdef COMPILER2
+ void vector_update_crc32(Register crc, Register buf, Register len,
+ Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5,
+ Register table0, Register table3);
+
void mul_add(Register out, Register in, Register offset,
Register len, Register k, Register tmp);
void wide_mul(Register prod_lo, Register prod_hi, Register n, Register m);
@@ -1351,7 +1382,7 @@ class MacroAssembler: public Assembler {
Register tmp1, Register tmp2, Register tmp3, Register tmp4,
Register tmp5, Register tmp6, Register product_hi);
-#endif
+#endif // COMPILER2
void inflate_lo32(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2 = t1);
void inflate_hi32(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2 = t1);
@@ -1602,7 +1633,7 @@ class MacroAssembler: public Assembler {
void store_conditional(Register dst, Register new_val, Register addr, enum operand_size size, Assembler::Aqrl release);
public:
- void lightweight_lock(Register obj, Register tmp1, Register tmp2, Register tmp3, Label& slow);
+ void lightweight_lock(Register basic_lock, Register obj, Register tmp1, Register tmp2, Register tmp3, Label& slow);
void lightweight_unlock(Register obj, Register tmp1, Register tmp2, Register tmp3, Label& slow);
public:
@@ -1706,40 +1737,6 @@ class MacroAssembler: public Assembler {
extract_rs1(last_instr) == extract_rd(add);
}
- // the instruction sequence of li64 is as below:
- // lui
- // addi
- // slli
- // addi
- // slli
- // addi
- // slli
- // addi
- static bool check_li64_data_dependency(address instr) {
- address lui = instr;
- address addi1 = lui + instruction_size;
- address slli1 = addi1 + instruction_size;
- address addi2 = slli1 + instruction_size;
- address slli2 = addi2 + instruction_size;
- address addi3 = slli2 + instruction_size;
- address slli3 = addi3 + instruction_size;
- address addi4 = slli3 + instruction_size;
- return extract_rs1(addi1) == extract_rd(lui) &&
- extract_rs1(addi1) == extract_rd(addi1) &&
- extract_rs1(slli1) == extract_rd(addi1) &&
- extract_rs1(slli1) == extract_rd(slli1) &&
- extract_rs1(addi2) == extract_rd(slli1) &&
- extract_rs1(addi2) == extract_rd(addi2) &&
- extract_rs1(slli2) == extract_rd(addi2) &&
- extract_rs1(slli2) == extract_rd(slli2) &&
- extract_rs1(addi3) == extract_rd(slli2) &&
- extract_rs1(addi3) == extract_rd(addi3) &&
- extract_rs1(slli3) == extract_rd(addi3) &&
- extract_rs1(slli3) == extract_rd(slli3) &&
- extract_rs1(addi4) == extract_rd(slli3) &&
- extract_rs1(addi4) == extract_rd(addi4);
- }
-
// the instruction sequence of li16u is as below:
// lui
// srli
@@ -1784,7 +1781,6 @@ class MacroAssembler: public Assembler {
}
static bool is_li32_at(address instr);
- static bool is_li64_at(address instr);
static bool is_pc_relative_at(address branch);
static bool is_membar(address addr) {
diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp
index fbb5b914038..8ed4b93ad4d 100644
--- a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp
+++ b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -28,6 +28,7 @@
#include "asm/macroAssembler.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/vmClasses.hpp"
+#include "compiler/disassembler.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "memory/allocation.inline.hpp"
@@ -37,7 +38,7 @@
#include "runtime/frame.inline.hpp"
#include "runtime/stubRoutines.hpp"
-#define __ _masm->
+#define __ Disassembler::hook(__FILE__, __LINE__, _masm)->
#ifdef PRODUCT
#define BLOCK_COMMENT(str) /* nothing */
@@ -108,19 +109,19 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth
// compiled code in threads for which the event is enabled. Check here for
// interp_only_mode if these events CAN be enabled.
- __ lwu(t0, Address(xthread, JavaThread::interp_only_mode_offset()));
- __ beqz(t0, run_compiled_code);
- __ ld(t0, Address(method, Method::interpreter_entry_offset()));
- __ jr(t0);
+ __ lwu(t1, Address(xthread, JavaThread::interp_only_mode_offset()));
+ __ beqz(t1, run_compiled_code);
+ __ ld(t1, Address(method, Method::interpreter_entry_offset()));
+ __ jr(t1);
__ BIND(run_compiled_code);
}
const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() :
Method::from_interpreted_offset();
- __ ld(t0,Address(method, entry_offset));
- __ jr(t0);
+ __ ld(t1, Address(method, entry_offset));
+ __ jr(t1);
__ bind(L_no_such_method);
- __ far_jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry()));
+ __ far_jump(RuntimeAddress(SharedRuntime::throw_AbstractMethodError_entry()));
}
void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm,
@@ -441,10 +442,9 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
jump_from_method_handle(_masm, xmethod, temp1, for_compiler_entry);
if (iid == vmIntrinsics::_linkToInterface) {
__ bind(L_incompatible_class_change_error);
- __ far_jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
+ __ far_jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry()));
}
}
-
}
#ifndef PRODUCT
diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
index f0357f1cd30..988a5b79332 100644
--- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
+++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
@@ -91,10 +91,10 @@ bool NativeShortCallTrampolineStub::is_at(address addr) {
if (MacroAssembler::is_auipc_at(addr) &&
MacroAssembler::is_ld_at(addr + instr_size) &&
MacroAssembler::is_jalr_at(addr + 2 * instr_size) &&
- (MacroAssembler::extract_rd(addr) == x5) &&
- (MacroAssembler::extract_rd(addr + instr_size) == x5) &&
- (MacroAssembler::extract_rs1(addr + instr_size) == x5) &&
- (MacroAssembler::extract_rs1(addr + 2 * instr_size) == x5) &&
+ (MacroAssembler::extract_rd(addr) == x6) &&
+ (MacroAssembler::extract_rd(addr + instr_size) == x6) &&
+ (MacroAssembler::extract_rs1(addr + instr_size) == x6) &&
+ (MacroAssembler::extract_rs1(addr + 2 * instr_size) == x6) &&
(Assembler::extract(Assembler::ld_instr(addr + 4), 31, 20) == trampoline_data_offset)) {
return true;
}
@@ -215,10 +215,10 @@ void NativeShortCall::print() {
// Used in the runtime linkage of calls; see class CompiledIC.
//
// Add parameter assert_lock to switch off assertion
-// during code generation, where no patching lock is needed.
+// during code generation, where no lock is needed.
bool NativeShortCall::set_destination_mt_safe(address dest, bool assert_lock) {
assert(!assert_lock ||
- (Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
+ (CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
CompiledICLocker::is_safe(instruction_address()),
"concurrent code patching");
@@ -386,7 +386,7 @@ void NativeFarCall::print() {
bool NativeFarCall::set_destination_mt_safe(address dest, bool assert_lock) {
assert(NativeFarCall::is_at(addr_at(0)), "unexpected code at call site");
assert(!assert_lock ||
- (Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
+ (CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
CompiledICLocker::is_safe(addr_at(0)),
"concurrent code patching");
@@ -460,10 +460,10 @@ bool NativeFarCall::is_at(address addr) {
if (MacroAssembler::is_auipc_at(addr) &&
MacroAssembler::is_ld_at(addr + instr_size) &&
MacroAssembler::is_jalr_at(addr + 2 * instr_size) &&
- (MacroAssembler::extract_rd(addr) == x5) &&
- (MacroAssembler::extract_rd(addr + instr_size) == x5) &&
- (MacroAssembler::extract_rs1(addr + instr_size) == x5) &&
- (MacroAssembler::extract_rs1(addr + 2 * instr_size) == x5) &&
+ (MacroAssembler::extract_rd(addr) == x6) &&
+ (MacroAssembler::extract_rd(addr + instr_size) == x6) &&
+ (MacroAssembler::extract_rs1(addr + instr_size) == x6) &&
+ (MacroAssembler::extract_rs1(addr + 2 * instr_size) == x6) &&
(MacroAssembler::extract_rd(addr + 2 * instr_size) == x1)) {
return true;
}
@@ -685,7 +685,7 @@ address NativeJump::jump_destination() const {
// load
// return -1 if jump to self or to 0
- if ((dest == (address) this) || dest == 0) {
+ if ((dest == (address) this) || dest == nullptr) {
dest = (address) -1;
}
@@ -714,7 +714,7 @@ address NativeGeneralJump::jump_destination() const {
// a general jump
// return -1 if jump to self or to 0
- if ((dest == (address) this) || dest == 0) {
+ if ((dest == (address) this) || dest == nullptr) {
dest = (address) -1;
}
@@ -789,8 +789,8 @@ void NativeGeneralJump::insert_unconditional(address code_pos, address entry) {
Assembler::IncompressibleRegion ir(&a); // Fixed length: see NativeGeneralJump::get_instruction_size()
int32_t offset = 0;
- a.movptr(t0, entry, offset, t1); // lui, lui, slli, add
- a.jr(t0, offset); // jalr
+ a.movptr(t1, entry, offset, t0); // lui, lui, slli, add
+ a.jr(t1, offset); // jalr
ICache::invalidate_range(code_pos, instruction_size);
}
diff --git a/src/hotspot/cpu/riscv/relocInfo_riscv.cpp b/src/hotspot/cpu/riscv/relocInfo_riscv.cpp
index d0903c96e22..18b4302c7e6 100644
--- a/src/hotspot/cpu/riscv/relocInfo_riscv.cpp
+++ b/src/hotspot/cpu/riscv/relocInfo_riscv.cpp
@@ -55,7 +55,21 @@ void Relocation::pd_set_data_value(address x, bool verify_only) {
bytes = MacroAssembler::pd_patch_instruction_size(addr(), x);
break;
}
- ICache::invalidate_range(addr(), bytes);
+
+ // If we are using UseCtxFencei no ICache invalidation is needed here.
+ // Instead every hart will preform an fence.i either by a Java thread
+ // (due to patching epoch will take it to slow path),
+ // or by the kernel when a Java thread is moved to a hart.
+ // The instruction streams changes must only happen before the disarm of
+ // the nmethod barrier. Where the disarm have a leading full two way fence.
+ // If this is performed during a safepoint, all Java threads will emit a fence.i
+ // before transitioning to 'Java', e.g. leaving native or the safepoint wait barrier.
+ if (!UseCtxFencei) {
+ // ICache invalidation is a serialization point.
+ // The above patching of instructions happens before the invalidation.
+ // Hence it have a leading full two way fence (wr, wr).
+ ICache::invalidate_range(addr(), bytes);
+ }
}
address Relocation::pd_call_destination(address orig_addr) {
diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad
index b176c6e9cb7..5710d6496a1 100644
--- a/src/hotspot/cpu/riscv/riscv.ad
+++ b/src/hotspot/cpu/riscv/riscv.ad
@@ -84,8 +84,8 @@ reg_def R0 ( NS, NS, Op_RegI, 0, x0->as_VMReg() ); // zr
reg_def R0_H ( NS, NS, Op_RegI, 0, x0->as_VMReg()->next() );
reg_def R1 ( NS, SOC, Op_RegI, 1, x1->as_VMReg() ); // ra
reg_def R1_H ( NS, SOC, Op_RegI, 1, x1->as_VMReg()->next() );
-reg_def R2 ( NS, SOE, Op_RegI, 2, x2->as_VMReg() ); // sp
-reg_def R2_H ( NS, SOE, Op_RegI, 2, x2->as_VMReg()->next() );
+reg_def R2 ( NS, NS, Op_RegI, 2, x2->as_VMReg() ); // sp
+reg_def R2_H ( NS, NS, Op_RegI, 2, x2->as_VMReg()->next() );
reg_def R3 ( NS, NS, Op_RegI, 3, x3->as_VMReg() ); // gp
reg_def R3_H ( NS, NS, Op_RegI, 3, x3->as_VMReg()->next() );
reg_def R4 ( NS, NS, Op_RegI, 4, x4->as_VMReg() ); // tp
@@ -1261,11 +1261,11 @@ int MachCallRuntimeNode::ret_addr_offset() {
// jal(trampoline_stub)
// for real runtime callouts it will be 11 instructions
// see riscv_enc_java_to_runtime
- // la(t1, retaddr) -> auipc + addi
- // la(t0, RuntimeAddress(addr)) -> lui + addi + slli + addi + slli + addi
+ // la(t0, retaddr) -> auipc + addi
+ // la(t1, RuntimeAddress(addr)) -> lui + addi + slli + addi + slli + addi
// addi(sp, sp, -2 * wordSize) -> addi
// sd(t1, Address(sp, wordSize)) -> sd
- // jalr(t0) -> jalr
+ // jalr(t1) -> jalr
CodeBlob *cb = CodeCache::find_blob(_entry_point);
if (cb != nullptr) {
if (UseTrampolines) {
@@ -1822,13 +1822,13 @@ void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const
assert_cond(st != nullptr);
st->print_cr("# MachUEPNode");
if (UseCompressedClassPointers) {
- st->print_cr("\tlwu t0, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass");
- st->print_cr("\tlwu t2, [t1 + CompiledICData::speculated_klass_offset()]\t# compressed klass");
+ st->print_cr("\tlwu t1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass");
+ st->print_cr("\tlwu t2, [t0 + CompiledICData::speculated_klass_offset()]\t# compressed klass");
} else {
- st->print_cr("\tld t0, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass");
- st->print_cr("\tld t2, [t1 + CompiledICData::speculated_klass_offset()]\t# compressed klass");
+ st->print_cr("\tld t1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass");
+ st->print_cr("\tld t2, [t0 + CompiledICData::speculated_klass_offset()]\t# compressed klass");
}
- st->print_cr("\tbeq t0, t2, ic_hit");
+ st->print_cr("\tbeq t1, t2, ic_hit");
st->print_cr("\tj, SharedRuntime::_ic_miss_stub\t # Inline cache check");
st->print_cr("\tic_hit:");
}
@@ -1857,8 +1857,8 @@ uint MachUEPNode::size(PhaseRegAlloc* ra_) const
// Emit exception handler code.
int HandlerImpl::emit_exception_handler(C2_MacroAssembler* masm)
{
- // auipc t0, #exception_blob_entry_point
- // jr (offset)t0
+ // auipc t1, #exception_blob_entry_point
+ // jr (offset)t1
// Note that the code buffer's insts_mark is always relative to insts.
// That's why we must use the macroassembler to generate a handler.
address base = __ start_a_stub(size_exception_handler());
@@ -1920,6 +1920,18 @@ bool Matcher::match_rule_supported(int opcode) {
case Op_EncodeISOArray:
return UseRVV;
+ // Current test shows that, it brings performance gain when MaxVectorSize >= 32, but brings
+ // regression when MaxVectorSize == 16. So only enable the intrinsic when MaxVectorSize >= 32.
+ case Op_RoundVF:
+ return UseRVV && MaxVectorSize >= 32;
+
+ // For double, current test shows that even with MaxVectorSize == 32, there is still some regression.
+ // Although there is no hardware to verify it for now, from the trend of performance data on hardwares
+ // (with vlenb == 16 and 32 respectively), it's promising to bring better performance rather than
+ // regression for double when MaxVectorSize == 64+. So only enable the intrinsic when MaxVectorSize >= 64.
+ case Op_RoundVD:
+ return UseRVV && MaxVectorSize >= 64;
+
case Op_PopCountI:
case Op_PopCountL:
return UsePopCountInstruction;
@@ -1954,18 +1966,18 @@ const RegMask* Matcher::predicate_reg_mask(void) {
return &_VMASK_REG_mask;
}
-const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) {
- return new TypeVectMask(elemTy, length);
-}
-
// Vector calling convention not yet implemented.
bool Matcher::supports_vector_calling_convention(void) {
- return false;
+ return EnableVectorSupport && UseVectorStubs;
}
OptoRegPair Matcher::vector_return_value(uint ideal_reg) {
- Unimplemented();
- return OptoRegPair(0, 0);
+ assert(EnableVectorSupport && UseVectorStubs, "sanity");
+ assert(ideal_reg == Op_VecA, "sanity");
+ // check more info at https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc
+ int lo = V8_num;
+ int hi = V8_K_num;
+ return OptoRegPair(hi, lo);
}
// Is this branch offset short enough that a short branch can be used?
@@ -2212,7 +2224,8 @@ bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) {
assert_cond(m != nullptr);
if (is_vshift_con_pattern(n, m) || // ShiftV src (ShiftCntV con)
is_vector_bitwise_not_pattern(n, m) ||
- is_vector_scalar_bitwise_pattern(n, m)) {
+ is_vector_scalar_bitwise_pattern(n, m) ||
+ is_encode_and_store_pattern(n, m)) {
mstack.push(m, Visit);
return true;
}
@@ -2491,12 +2504,12 @@ encode %{
__ post_call_nop();
} else {
Label retaddr;
- __ la(t1, retaddr);
- __ la(t0, RuntimeAddress(entry));
+ __ la(t0, retaddr);
+ __ la(t1, RuntimeAddress(entry));
// Leave a breadcrumb for JavaFrameAnchor::capture_last_Java_pc()
__ addi(sp, sp, -2 * wordSize);
- __ sd(t1, Address(sp, wordSize));
- __ jalr(t0);
+ __ sd(t0, Address(sp, wordSize));
+ __ jalr(t1);
__ bind(retaddr);
__ post_call_nop();
__ addi(sp, sp, 2 * wordSize);
@@ -4773,6 +4786,7 @@ instruct loadP(iRegPNoSp dst, memory mem)
// Load Compressed Pointer
instruct loadN(iRegNNoSp dst, memory mem)
%{
+ predicate(n->as_Load()->barrier_data() == 0);
match(Set dst (LoadN mem));
ins_cost(LOAD_COST);
@@ -5021,41 +5035,6 @@ instruct loadConD0(fRegD dst, immD0 con) %{
ins_pipe(fp_load_constant_d);
%}
-// Store Instructions
-// Store CMS card-mark Immediate
-instruct storeimmCM0(immI0 zero, memory mem)
-%{
- match(Set mem (StoreCM mem zero));
-
- ins_cost(STORE_COST);
- format %{ "storestore (elided)\n\t"
- "sb zr, $mem\t# byte, #@storeimmCM0" %}
-
- ins_encode %{
- __ sb(zr, Address(as_Register($mem$$base), $mem$$disp));
- %}
-
- ins_pipe(istore_mem);
-%}
-
-// Store CMS card-mark Immediate with intervening StoreStore
-// needed when using CMS with no conditional card marking
-instruct storeimmCM0_ordered(immI0 zero, memory mem)
-%{
- match(Set mem (StoreCM mem zero));
-
- ins_cost(ALU_COST + STORE_COST);
- format %{ "membar(StoreStore)\n\t"
- "sb zr, $mem\t# byte, #@storeimmCM0_ordered" %}
-
- ins_encode %{
- __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore);
- __ sb(zr, Address(as_Register($mem$$base), $mem$$disp));
- %}
-
- ins_pipe(istore_mem);
-%}
-
// Store Byte
instruct storeB(iRegIorL2I src, memory mem)
%{
@@ -5208,6 +5187,7 @@ instruct storeimmP0(immP0 zero, memory mem)
// Store Compressed Pointer
instruct storeN(iRegN src, memory mem)
%{
+ predicate(n->as_Store()->barrier_data() == 0);
match(Set mem (StoreN mem src));
ins_cost(STORE_COST);
@@ -5222,6 +5202,7 @@ instruct storeN(iRegN src, memory mem)
instruct storeImmN0(immN0 zero, memory mem)
%{
+ predicate(n->as_Store()->barrier_data() == 0);
match(Set mem (StoreN mem zero));
ins_cost(STORE_COST);
@@ -5412,6 +5393,7 @@ instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval
instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval)
%{
+ predicate(n->as_LoadStore()->barrier_data() == 0);
match(Set res (CompareAndSwapN mem (Binary oldval newval)));
ins_cost(LOAD_COST + STORE_COST + ALU_COST * 8 + BRANCH_COST * 4);
@@ -5533,7 +5515,7 @@ instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP new
instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval)
%{
- predicate(needs_acquiring_load_reserved(n));
+ predicate(needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == 0);
match(Set res (CompareAndSwapN mem (Binary oldval newval)));
@@ -5641,6 +5623,7 @@ instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL ne
instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval)
%{
+ predicate(n->as_LoadStore()->barrier_data() == 0);
match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST * 3);
@@ -5774,7 +5757,7 @@ instruct compareAndExchangeLAcq(iRegLNoSp res, indirect mem, iRegL oldval, iRegL
instruct compareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval)
%{
- predicate(needs_acquiring_load_reserved(n));
+ predicate(needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == 0);
match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
@@ -5902,6 +5885,7 @@ instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL ne
instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval)
%{
+ predicate(n->as_LoadStore()->barrier_data() == 0);
match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 4);
@@ -6033,7 +6017,7 @@ instruct weakCompareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL
instruct weakCompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval)
%{
- predicate(needs_acquiring_load_reserved(n));
+ predicate(needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == 0);
match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
@@ -6105,6 +6089,8 @@ instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev)
instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev)
%{
+ predicate(n->as_LoadStore()->barrier_data() == 0);
+
match(Set prev (GetAndSetN mem newv));
ins_cost(ALU_COST);
@@ -6170,7 +6156,7 @@ instruct get_and_setLAcq(indirect mem, iRegL newv, iRegLNoSp prev)
instruct get_and_setNAcq(indirect mem, iRegN newv, iRegINoSp prev)
%{
- predicate(needs_acquiring_load_reserved(n));
+ predicate(needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == 0);
match(Set prev (GetAndSetN mem newv));
@@ -10003,11 +9989,11 @@ instruct CallStaticJavaDirect(method meth)
// Call Java Dynamic Instruction
// Note: If this code changes, the corresponding ret_addr_offset() and
// compute_padding() functions will have to be adjusted.
-instruct CallDynamicJavaDirect(method meth, rFlagsReg cr)
+instruct CallDynamicJavaDirect(method meth)
%{
match(CallDynamicJava);
- effect(USE meth, KILL cr);
+ effect(USE meth);
ins_cost(BRANCH_COST + ALU_COST * 5);
@@ -10022,11 +10008,11 @@ instruct CallDynamicJavaDirect(method meth, rFlagsReg cr)
// Call Runtime Instruction
-instruct CallRuntimeDirect(method meth, rFlagsReg cr)
+instruct CallRuntimeDirect(method meth)
%{
match(CallRuntime);
- effect(USE meth, KILL cr);
+ effect(USE meth);
ins_cost(BRANCH_COST);
@@ -10039,11 +10025,11 @@ instruct CallRuntimeDirect(method meth, rFlagsReg cr)
// Call Runtime Instruction
-instruct CallLeafDirect(method meth, rFlagsReg cr)
+instruct CallLeafDirect(method meth)
%{
match(CallLeaf);
- effect(USE meth, KILL cr);
+ effect(USE meth);
ins_cost(BRANCH_COST);
@@ -10054,13 +10040,30 @@ instruct CallLeafDirect(method meth, rFlagsReg cr)
ins_pipe(pipe_class_call);
%}
+// Call Runtime Instruction without safepoint and with vector arguments
+
+instruct CallLeafDirectVector(method meth)
+%{
+ match(CallLeafVector);
+
+ effect(USE meth);
+
+ ins_cost(BRANCH_COST);
+
+ format %{ "CALL, runtime leaf vector $meth" %}
+
+ ins_encode(riscv_enc_java_to_runtime(meth));
+
+ ins_pipe(pipe_class_call);
+%}
+
// Call Runtime Instruction
-instruct CallLeafNoFPDirect(method meth, rFlagsReg cr)
+instruct CallLeafNoFPDirect(method meth)
%{
match(CallLeafNoFP);
- effect(USE meth, KILL cr);
+ effect(USE meth);
ins_cost(BRANCH_COST);
@@ -10095,11 +10098,11 @@ instruct partialSubtypeCheck(iRegP_R15 result, iRegP_R14 sub, iRegP_R10 super, i
%}
instruct partialSubtypeCheckConstSuper(iRegP_R14 sub, iRegP_R10 super_reg, immP super_con, iRegP_R15 result,
- iRegP_R11 tmpR11, iRegP_R12 tmpR12, iRegP_R13 tmpR13, iRegP_R16 tmpR16)
+ iRegP_R11 tmpR11, iRegP_R12 tmpR12, iRegP_R13 tmpR13, iRegP_R16 tmpR16, rFlagsReg cr)
%{
predicate(UseSecondarySupersTable);
match(Set result (PartialSubtypeCheck sub (Binary super_reg super_con)));
- effect(TEMP tmpR11, TEMP tmpR12, TEMP tmpR13, TEMP tmpR16);
+ effect(TEMP tmpR11, TEMP tmpR12, TEMP tmpR13, TEMP tmpR16, KILL cr);
ins_cost(7 * DEFAULT_COST); // needs to be less than competing nodes
format %{ "partialSubtypeCheck $result, $sub, $super_reg, $super_con" %}
@@ -10376,12 +10379,12 @@ instruct stringL_indexof_char(iRegP_R11 str1, iRegI_R12 cnt1, iRegI_R13 ch,
// clearing of an array
instruct clearArray_reg_reg(iRegL_R29 cnt, iRegP_R28 base, iRegP_R30 tmp1,
- iRegP_R31 tmp2, Universe dummy)
+ iRegP_R31 tmp2, rFlagsReg cr, Universe dummy)
%{
// temp registers must match the one used in StubGenerator::generate_zero_blocks()
predicate(UseBlockZeroing || !UseRVV);
match(Set dummy (ClearArray cnt base));
- effect(USE_KILL cnt, USE_KILL base, TEMP tmp1, TEMP tmp2);
+ effect(USE_KILL cnt, USE_KILL base, TEMP tmp1, TEMP tmp2, KILL cr);
ins_cost(4 * DEFAULT_COST);
format %{ "ClearArray $cnt, $base\t#@clearArray_reg_reg" %}
@@ -10553,33 +10556,33 @@ instruct cmpFastUnlock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp1, iR
ins_pipe(pipe_serial);
%}
-instruct cmpFastLockLightweight(rFlagsReg cr, iRegP object, iRegP_R10 box, iRegPNoSp tmp1, iRegPNoSp tmp2)
+instruct cmpFastLockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3)
%{
predicate(LockingMode == LM_LIGHTWEIGHT);
match(Set cr (FastLock object box));
- effect(TEMP tmp1, TEMP tmp2, USE_KILL box);
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3);
ins_cost(10 * DEFAULT_COST);
- format %{ "fastlock $object,$box\t! kills $box,$tmp1,$tmp2 #@cmpFastLockLightweight" %}
+ format %{ "fastlock $object,$box\t! kills $tmp1,$tmp2,$tmp3 #@cmpFastLockLightweight" %}
ins_encode %{
- __ fast_lock_lightweight($object$$Register, $box$$Register, $tmp1$$Register, $tmp2$$Register);
+ __ fast_lock_lightweight($object$$Register, $box$$Register, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register);
%}
ins_pipe(pipe_serial);
%}
-instruct cmpFastUnlockLightweight(rFlagsReg cr, iRegP object, iRegP_R10 box, iRegPNoSp tmp1, iRegPNoSp tmp2)
+instruct cmpFastUnlockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3)
%{
predicate(LockingMode == LM_LIGHTWEIGHT);
match(Set cr (FastUnlock object box));
- effect(TEMP tmp1, TEMP tmp2, USE_KILL box);
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3);
ins_cost(10 * DEFAULT_COST);
- format %{ "fastunlock $object,$box\t! kills $box,$tmp1,$tmp2, #@cmpFastUnlockLightweight" %}
+ format %{ "fastunlock $object,$box\t! kills $tmp1,$tmp2,$tmp3 #@cmpFastUnlockLightweight" %}
ins_encode %{
- __ fast_unlock_lightweight($object$$Register, $box$$Register, $tmp1$$Register, $tmp2$$Register);
+ __ fast_unlock_lightweight($object$$Register, $box$$Register, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register);
%}
ins_pipe(pipe_serial);
@@ -10617,6 +10620,22 @@ instruct TailjmpInd(iRegPNoSpNoFp jump_target, iRegP_R10 ex_oop)
ins_pipe(pipe_class_call);
%}
+// Forward exception.
+instruct ForwardExceptionjmp()
+%{
+ match(ForwardException);
+
+ ins_cost(BRANCH_COST);
+
+ format %{ "j forward_exception_stub\t#@ForwardException" %}
+
+ ins_encode %{
+ __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
+ %}
+
+ ins_pipe(pipe_class_call);
+%}
+
// Create exception oop: created by stack-crawling runtime code.
// Created exception is now available to this handler, and is setup
// just prior to jumping to this handler. No code emitted.
diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad
index 1a51d7583c9..510c0ff5d46 100644
--- a/src/hotspot/cpu/riscv/riscv_v.ad
+++ b/src/hotspot/cpu/riscv/riscv_v.ad
@@ -4715,6 +4715,34 @@ instruct vsignum_reg(vReg dst, vReg zero, vReg one, vRegMask_V0 v0) %{
ins_pipe(pipe_slow);
%}
+// ---------------- Round float/double Vector Operations ----------------
+
+instruct vround_f(vReg dst, vReg src, fRegF tmp, vRegMask_V0 v0) %{
+ match(Set dst (RoundVF src));
+ effect(TEMP_DEF dst, TEMP tmp, TEMP v0);
+ format %{ "java_round_float_v $dst, $src\t" %}
+ ins_encode %{
+ BasicType bt = Matcher::vector_element_basic_type(this);
+ uint vector_length = Matcher::vector_length(this);
+ __ java_round_float_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg),
+ as_FloatRegister($tmp$$reg), bt, vector_length);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+instruct vround_d(vReg dst, vReg src, fRegD tmp, vRegMask_V0 v0) %{
+ match(Set dst (RoundVD src));
+ effect(TEMP_DEF dst, TEMP tmp, TEMP v0);
+ format %{ "java_round_double_v $dst, $src\t" %}
+ ins_encode %{
+ BasicType bt = Matcher::vector_element_basic_type(this);
+ uint vector_length = Matcher::vector_length(this);
+ __ java_round_double_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg),
+ as_FloatRegister($tmp$$reg), bt, vector_length);
+ %}
+ ins_pipe(pipe_slow);
+%}
+
// -------------------------------- Reverse Bytes Vector Operations ------------------------
instruct vreverse_bytes_masked(vReg dst_src, vRegMask_V0 v0) %{
@@ -4867,11 +4895,10 @@ instruct gather_loadS(vReg dst, indirect mem, vReg idx) %{
effect(TEMP_DEF dst);
format %{ "gather_loadS $dst, $mem, $idx" %}
ins_encode %{
- __ vmv1r_v(as_VectorRegister($dst$$reg), as_VectorRegister($idx$$reg));
BasicType bt = Matcher::vector_element_basic_type(this);
Assembler::SEW sew = Assembler::elemtype_to_sew(bt);
__ vsetvli_helper(bt, Matcher::vector_length(this));
- __ vsll_vi(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), (int)sew);
+ __ vsll_vi(as_VectorRegister($dst$$reg), as_VectorRegister($idx$$reg), (int)sew);
__ vluxei32_v(as_VectorRegister($dst$$reg), as_Register($mem$$base),
as_VectorRegister($dst$$reg));
%}
@@ -4901,11 +4928,10 @@ instruct gather_loadS_masked(vReg dst, indirect mem, vReg idx, vRegMask_V0 v0, v
effect(TEMP_DEF dst, TEMP tmp);
format %{ "gather_loadS_masked $dst, $mem, $idx, $v0\t# KILL $tmp" %}
ins_encode %{
- __ vmv1r_v(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg));
BasicType bt = Matcher::vector_element_basic_type(this);
Assembler::SEW sew = Assembler::elemtype_to_sew(bt);
__ vsetvli_helper(bt, Matcher::vector_length(this));
- __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), (int)sew);
+ __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg), (int)sew);
__ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg),
as_VectorRegister($dst$$reg));
__ vluxei32_v(as_VectorRegister($dst$$reg), as_Register($mem$$base),
@@ -4941,11 +4967,10 @@ instruct scatter_storeS(indirect mem, vReg src, vReg idx, vReg tmp) %{
effect(TEMP tmp);
format %{ "scatter_storeS $mem, $idx, $src\t# KILL $tmp" %}
ins_encode %{
- __ vmv1r_v(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg));
BasicType bt = Matcher::vector_element_basic_type(this, $src);
Assembler::SEW sew = Assembler::elemtype_to_sew(bt);
__ vsetvli_helper(bt, Matcher::vector_length(this, $src));
- __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), (int)sew);
+ __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg), (int)sew);
__ vsuxei32_v(as_VectorRegister($src$$reg), as_Register($mem$$base),
as_VectorRegister($tmp$$reg));
%}
@@ -4975,11 +5000,10 @@ instruct scatter_storeS_masked(indirect mem, vReg src, vReg idx, vRegMask_V0 v0,
effect(TEMP tmp);
format %{ "scatter_storeS_masked $mem, $idx, $src, $v0\t# KILL $tmp" %}
ins_encode %{
- __ vmv1r_v(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg));
BasicType bt = Matcher::vector_element_basic_type(this, $src);
Assembler::SEW sew = Assembler::elemtype_to_sew(bt);
__ vsetvli_helper(bt, Matcher::vector_length(this, $src));
- __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), (int)sew);
+ __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg), (int)sew);
__ vsuxei32_v(as_VectorRegister($src$$reg), as_Register($mem$$base),
as_VectorRegister($tmp$$reg), Assembler::v0_t);
%}
diff --git a/src/hotspot/cpu/riscv/runtime_riscv.cpp b/src/hotspot/cpu/riscv/runtime_riscv.cpp
new file mode 100644
index 00000000000..2f879b07e26
--- /dev/null
+++ b/src/hotspot/cpu/riscv/runtime_riscv.cpp
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, Red Hat Inc. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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"
+#ifdef COMPILER2
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
+#include "code/vmreg.hpp"
+#include "interpreter/interpreter.hpp"
+#include "opto/runtime.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/vframeArray.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "vmreg_riscv.inline.hpp"
+
+class SimpleRuntimeFrame {
+public:
+
+ // Most of the runtime stubs have this simple frame layout.
+ // This class exists to make the layout shared in one place.
+ // Offsets are for compiler stack slots, which are jints.
+ enum layout {
+ // The frame sender code expects that fp will be in the "natural" place and
+ // will override any oopMap setting for it. We must therefore force the layout
+ // so that it agrees with the frame sender code.
+ // we don't expect any arg reg save area so riscv asserts that
+ // frame::arg_reg_save_area_bytes == 0
+ fp_off = 0, fp_off2,
+ return_off, return_off2,
+ framesize
+ };
+};
+
+#define __ masm->
+
+//------------------------------generate_uncommon_trap_blob--------------------
+void OptoRuntime::generate_uncommon_trap_blob() {
+ // Allocate space for the code
+ ResourceMark rm;
+ // Setup code generation tools
+ CodeBuffer buffer("uncommon_trap_blob", 2048, 1024);
+ MacroAssembler* masm = new MacroAssembler(&buffer);
+ assert_cond(masm != nullptr);
+
+ assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
+
+ address start = __ pc();
+
+ // Push self-frame. We get here with a return address in RA
+ // and sp should be 16 byte aligned
+ // push fp and retaddr by hand
+ __ addi(sp, sp, -2 * wordSize);
+ __ sd(ra, Address(sp, wordSize));
+ __ sd(fp, Address(sp, 0));
+ // we don't expect an arg reg save area
+#ifndef PRODUCT
+ assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area");
+#endif
+ // compiler left unloaded_class_index in j_rarg0 move to where the
+ // runtime expects it.
+ __ sign_extend(c_rarg1, j_rarg0, 32);
+
+ // we need to set the past SP to the stack pointer of the stub frame
+ // and the pc to the address where this runtime call will return
+ // although actually any pc in this code blob will do).
+ Label retaddr;
+ __ set_last_Java_frame(sp, noreg, retaddr, t0);
+
+ // Call C code. Need thread but NOT official VM entry
+ // crud. We cannot block on this call, no GC can happen. Call should
+ // capture callee-saved registers as well as return values.
+ //
+ // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index, jint exec_mode)
+ //
+ // n.b. 3 gp args, 0 fp args, integral return type
+
+ __ mv(c_rarg0, xthread);
+ __ mv(c_rarg2, Deoptimization::Unpack_uncommon_trap);
+ __ rt_call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap));
+ __ bind(retaddr);
+
+ // Set an oopmap for the call site
+ OopMapSet* oop_maps = new OopMapSet();
+ OopMap* map = new OopMap(SimpleRuntimeFrame::framesize, 0);
+ assert_cond(oop_maps != nullptr && map != nullptr);
+
+ // location of fp is known implicitly by the frame sender code
+
+ oop_maps->add_gc_map(__ pc() - start, map);
+
+ __ reset_last_Java_frame(false);
+
+ // move UnrollBlock* into x14
+ __ mv(x14, x10);
+
+#ifdef ASSERT
+ { Label L;
+ __ lwu(t0, Address(x14, Deoptimization::UnrollBlock::unpack_kind_offset()));
+ __ mv(t1, Deoptimization::Unpack_uncommon_trap);
+ __ beq(t0, t1, L);
+ __ stop("OptoRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap");
+ __ bind(L);
+ }
+#endif
+
+ // Pop all the frames we must move/replace.
+ //
+ // Frame picture (youngest to oldest)
+ // 1: self-frame (no frame link)
+ // 2: deopting frame (no frame link)
+ // 3: caller of deopting frame (could be compiled/interpreted).
+
+ __ add(sp, sp, (SimpleRuntimeFrame::framesize) << LogBytesPerInt); // Epilog!
+
+ // Pop deoptimized frame (int)
+ __ lwu(x12, Address(x14,
+ Deoptimization::UnrollBlock::
+ size_of_deoptimized_frame_offset()));
+ __ sub(x12, x12, 2 * wordSize);
+ __ add(sp, sp, x12);
+ __ ld(fp, Address(sp, 0));
+ __ ld(ra, Address(sp, wordSize));
+ __ addi(sp, sp, 2 * wordSize);
+ // RA should now be the return address to the caller (3) frame
+
+#ifdef ASSERT
+ // Compilers generate code that bang the stack by as much as the
+ // interpreter would need. So this stack banging should never
+ // trigger a fault. Verify that it does not on non product builds.
+ __ lwu(x11, Address(x14,
+ Deoptimization::UnrollBlock::
+ total_frame_sizes_offset()));
+ __ bang_stack_size(x11, x12);
+#endif
+
+ // Load address of array of frame pcs into x12 (address*)
+ __ ld(x12, Address(x14,
+ Deoptimization::UnrollBlock::frame_pcs_offset()));
+
+ // Load address of array of frame sizes into x15 (intptr_t*)
+ __ ld(x15, Address(x14,
+ Deoptimization::UnrollBlock::
+ frame_sizes_offset()));
+
+ // Counter
+ __ lwu(x13, Address(x14,
+ Deoptimization::UnrollBlock::
+ number_of_frames_offset())); // (int)
+
+ // Now adjust the caller's stack to make up for the extra locals but
+ // record the original sp so that we can save it in the skeletal
+ // interpreter frame and the stack walking of interpreter_sender
+ // will get the unextended sp value and not the "real" sp value.
+
+ const Register sender_sp = t1; // temporary register
+
+ __ lwu(x11, Address(x14,
+ Deoptimization::UnrollBlock::
+ caller_adjustment_offset())); // (int)
+ __ mv(sender_sp, sp);
+ __ sub(sp, sp, x11);
+
+ // Push interpreter frames in a loop
+ Label loop;
+ __ bind(loop);
+ __ ld(x11, Address(x15, 0)); // Load frame size
+ __ sub(x11, x11, 2 * wordSize); // We'll push pc and fp by hand
+ __ ld(ra, Address(x12, 0)); // Save return address
+ __ enter(); // and old fp & set new fp
+ __ sub(sp, sp, x11); // Prolog
+ __ sd(sender_sp, Address(fp, frame::interpreter_frame_sender_sp_offset * wordSize)); // Make it walkable
+ // This value is corrected by layout_activation_impl
+ __ sd(zr, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize));
+ __ mv(sender_sp, sp); // Pass sender_sp to next frame
+ __ add(x15, x15, wordSize); // Bump array pointer (sizes)
+ __ add(x12, x12, wordSize); // Bump array pointer (pcs)
+ __ subw(x13, x13, 1); // Decrement counter
+ __ bgtz(x13, loop);
+ __ ld(ra, Address(x12, 0)); // save final return address
+ // Re-push self-frame
+ __ enter(); // & old fp & set new fp
+
+ // Use fp because the frames look interpreted now
+ // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP.
+ // Don't need the precise return PC here, just precise enough to point into this code blob.
+ address the_pc = __ pc();
+ __ set_last_Java_frame(sp, fp, the_pc, t0);
+
+ // Call C code. Need thread but NOT official VM entry
+ // crud. We cannot block on this call, no GC can happen. Call should
+ // restore return values to their stack-slots with the new SP.
+ //
+ // BasicType unpack_frames(JavaThread* thread, int exec_mode)
+ //
+
+ // n.b. 2 gp args, 0 fp args, integral return type
+
+ // sp should already be aligned
+ __ mv(c_rarg0, xthread);
+ __ mv(c_rarg1, Deoptimization::Unpack_uncommon_trap);
+ __ rt_call(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames));
+
+ // Set an oopmap for the call site
+ // Use the same PC we used for the last java frame
+ oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0));
+
+ // Clear fp AND pc
+ __ reset_last_Java_frame(true);
+
+ // Pop self-frame.
+ __ leave(); // Epilog
+
+ // Jump to interpreter
+ __ ret();
+
+ // Make sure all code is generated
+ masm->flush();
+
+ _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps,
+ SimpleRuntimeFrame::framesize >> 1);
+}
+
+//------------------------------generate_exception_blob---------------------------
+// creates exception blob at the end
+// Using exception blob, this code is jumped from a compiled method.
+// (see emit_exception_handler in riscv.ad file)
+//
+// Given an exception pc at a call we call into the runtime for the
+// handler in this method. This handler might merely restore state
+// (i.e. callee save registers) unwind the frame and jump to the
+// exception handler for the nmethod if there is no Java level handler
+// for the nmethod.
+//
+// This code is entered with a jmp.
+//
+// Arguments:
+// x10: exception oop
+// x13: exception pc
+//
+// Results:
+// x10: exception oop
+// x13: exception pc in caller
+// destination: exception handler of caller
+//
+// Note: the exception pc MUST be at a call (precise debug information)
+// Registers x10, x13, x12, x14, x15, t0 are not callee saved.
+//
+
+void OptoRuntime::generate_exception_blob() {
+ assert(!OptoRuntime::is_callee_saved_register(R13_num), "");
+ assert(!OptoRuntime::is_callee_saved_register(R10_num), "");
+ assert(!OptoRuntime::is_callee_saved_register(R12_num), "");
+
+ assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
+
+ // Allocate space for the code
+ ResourceMark rm;
+ // Setup code generation tools
+ CodeBuffer buffer("exception_blob", 2048, 1024);
+ MacroAssembler* masm = new MacroAssembler(&buffer);
+ assert_cond(masm != nullptr);
+
+ // TODO check various assumptions made here
+ //
+ // make sure we do so before running this
+
+ address start = __ pc();
+
+ // push fp and retaddr by hand
+ // Exception pc is 'return address' for stack walker
+ __ addi(sp, sp, -2 * wordSize);
+ __ sd(ra, Address(sp, wordSize));
+ __ sd(fp, Address(sp));
+ // there are no callee save registers and we don't expect an
+ // arg reg save area
+#ifndef PRODUCT
+ assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area");
+#endif
+ // Store exception in Thread object. We cannot pass any arguments to the
+ // handle_exception call, since we do not want to make any assumption
+ // about the size of the frame where the exception happened in.
+ __ sd(x10, Address(xthread, JavaThread::exception_oop_offset()));
+ __ sd(x13, Address(xthread, JavaThread::exception_pc_offset()));
+
+ // This call does all the hard work. It checks if an exception handler
+ // exists in the method.
+ // If so, it returns the handler address.
+ // If not, it prepares for stack-unwinding, restoring the callee-save
+ // registers of the frame being removed.
+ //
+ // address OptoRuntime::handle_exception_C(JavaThread* thread)
+ //
+ // n.b. 1 gp arg, 0 fp args, integral return type
+
+ // the stack should always be aligned
+ address the_pc = __ pc();
+ __ set_last_Java_frame(sp, noreg, the_pc, t0);
+ __ mv(c_rarg0, xthread);
+ __ rt_call(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C));
+
+ // handle_exception_C is a special VM call which does not require an explicit
+ // instruction sync afterwards.
+
+ // Set an oopmap for the call site. This oopmap will only be used if we
+ // are unwinding the stack. Hence, all locations will be dead.
+ // Callee-saved registers will be the same as the frame above (i.e.,
+ // handle_exception_stub), since they were restored when we got the
+ // exception.
+
+ OopMapSet* oop_maps = new OopMapSet();
+ assert_cond(oop_maps != nullptr);
+
+ oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0));
+
+ __ reset_last_Java_frame(false);
+
+ // Restore callee-saved registers
+
+ // fp is an implicitly saved callee saved register (i.e. the calling
+ // convention will save restore it in prolog/epilog) Other than that
+ // there are no callee save registers now that adapter frames are gone.
+ // and we dont' expect an arg reg save area
+ __ ld(fp, Address(sp));
+ __ ld(x13, Address(sp, wordSize));
+ __ addi(sp, sp , 2 * wordSize);
+
+ // x10: exception handler
+
+ // We have a handler in x10 (could be deopt blob).
+ __ mv(t1, x10);
+
+ // Get the exception oop
+ __ ld(x10, Address(xthread, JavaThread::exception_oop_offset()));
+ // Get the exception pc in case we are deoptimized
+ __ ld(x14, Address(xthread, JavaThread::exception_pc_offset()));
+#ifdef ASSERT
+ __ sd(zr, Address(xthread, JavaThread::exception_handler_pc_offset()));
+ __ sd(zr, Address(xthread, JavaThread::exception_pc_offset()));
+#endif
+ // Clear the exception oop so GC no longer processes it as a root.
+ __ sd(zr, Address(xthread, JavaThread::exception_oop_offset()));
+
+ // x10: exception oop
+ // t1: exception handler
+ // x14: exception pc
+ // Jump to handler
+
+ __ jr(t1);
+
+ // Make sure all code is generated
+ masm->flush();
+
+ // Set exception blob
+ _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1);
+}
+#endif // COMPILER2
+
+
diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp
index 01ab3d5c274..cec6a5f9760 100644
--- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp
+++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp
@@ -48,6 +48,7 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/signature.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/timerTrace.hpp"
#include "runtime/vframeArray.hpp"
#include "utilities/align.hpp"
#include "utilities/formatBuffer.hpp"
@@ -65,25 +66,13 @@
#define __ masm->
-const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size;
-
-class SimpleRuntimeFrame {
-public:
+#ifdef PRODUCT
+#define BLOCK_COMMENT(str) /* nothing */
+#else
+#define BLOCK_COMMENT(str) __ block_comment(str)
+#endif
- // Most of the runtime stubs have this simple frame layout.
- // This class exists to make the layout shared in one place.
- // Offsets are for compiler stack slots, which are jints.
- enum layout {
- // The frame sender code expects that fp will be in the "natural" place and
- // will override any oopMap setting for it. We must therefore force the layout
- // so that it agrees with the frame sender code.
- // we don't expect any arg reg save area so riscv asserts that
- // frame::arg_reg_save_area_bytes == 0
- fp_off = 0, fp_off2,
- return_off, return_off2,
- framesize
- };
-};
+const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size;
class RegisterSaver {
const bool _save_vectors;
@@ -479,8 +468,8 @@ static void gen_c2i_adapter(MacroAssembler *masm,
__ mv(esp, sp); // Interp expects args on caller's expression stack
- __ ld(t0, Address(xmethod, in_bytes(Method::interpreter_entry_offset())));
- __ jr(t0);
+ __ ld(t1, Address(xmethod, in_bytes(Method::interpreter_entry_offset())));
+ __ jr(t1);
}
void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
@@ -621,8 +610,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
Label skip_fixup;
const Register receiver = j_rarg0;
- const Register data = t1;
- const Register tmp = t2; // A call-clobbered register not used for arg passing
+ const Register data = t0;
// -------------------------------------------------------------------------
// Generate a C2I adapter. On entry we know xmethod holds the Method* during calls
@@ -677,7 +665,20 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
int SharedRuntime::vector_calling_convention(VMRegPair *regs,
uint num_bits,
uint total_args_passed) {
- Unimplemented();
+ assert(total_args_passed <= Argument::n_vector_register_parameters_c, "unsupported");
+ assert(num_bits >= 64 && num_bits <= 2048 && is_power_of_2(num_bits), "unsupported");
+
+ // check more info at https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc
+ static const VectorRegister VEC_ArgReg[Argument::n_vector_register_parameters_c] = {
+ v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23
+ };
+
+ const int next_reg_val = 3;
+ for (uint i = 0; i < total_args_passed; i++) {
+ VMReg vmreg = VEC_ArgReg[i]->as_VMReg();
+ regs[i].set_pair(vmreg->next(next_reg_val), vmreg);
+ }
return 0;
}
@@ -1138,8 +1139,7 @@ static void gen_continuation_yield(MacroAssembler* masm,
Label ok;
__ beqz(t0, ok);
__ leave();
- __ la(t0, RuntimeAddress(StubRoutines::forward_exception_entry()));
- __ jr(t0);
+ __ j(RuntimeAddress(StubRoutines::forward_exception_entry()));
__ bind(ok);
__ leave();
@@ -1450,8 +1450,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
// restoring them except fp. fp is the only callee save register
// as far as the interpreter and the compiler(s) are concerned.
-
- const Register ic_reg = t1;
const Register receiver = j_rarg0;
__ verify_oop(receiver);
@@ -1713,7 +1711,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
__ bnez(swap_reg, slow_path_lock);
} else {
assert(LockingMode == LM_LIGHTWEIGHT, "must be");
- __ lightweight_lock(obj_reg, swap_reg, tmp, lock_tmp, slow_path_lock);
+ __ lightweight_lock(lock_reg, obj_reg, swap_reg, tmp, lock_tmp, slow_path_lock);
}
__ bind(count);
@@ -1735,6 +1733,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
__ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore);
__ sw(t0, Address(t1));
+ // Clobbers t1
__ rt_call(native_func);
__ bind(native_return);
@@ -2068,7 +2067,8 @@ void SharedRuntime::generate_deopt_blob() {
pad += 512; // Increase the buffer size when compiling for JVMCI
}
#endif
- CodeBuffer buffer("deopt_blob", 2048 + pad, 1024);
+ const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id);
+ CodeBuffer buffer(name, 2048 + pad, 1024);
MacroAssembler* masm = new MacroAssembler(&buffer);
int frame_size_in_words = -1;
OopMap* map = nullptr;
@@ -2120,7 +2120,7 @@ void SharedRuntime::generate_deopt_blob() {
int reexecute_offset = __ pc() - start;
#if INCLUDE_JVMCI && !defined(COMPILER1)
- if (EnableJVMCI && UseJVMCICompiler) {
+ if (UseJVMCICompiler) {
// JVMCI does not use this kind of deoptimization
__ should_not_reach_here();
}
@@ -2441,216 +2441,30 @@ uint SharedRuntime::out_preserve_stack_slots() {
return 0;
}
-#ifdef COMPILER2
-//------------------------------generate_uncommon_trap_blob--------------------
-void SharedRuntime::generate_uncommon_trap_blob() {
- // Allocate space for the code
- ResourceMark rm;
- // Setup code generation tools
- CodeBuffer buffer("uncommon_trap_blob", 2048, 1024);
- MacroAssembler* masm = new MacroAssembler(&buffer);
- assert_cond(masm != nullptr);
-
- assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
-
- address start = __ pc();
-
- // Push self-frame. We get here with a return address in RA
- // and sp should be 16 byte aligned
- // push fp and retaddr by hand
- __ addi(sp, sp, -2 * wordSize);
- __ sd(ra, Address(sp, wordSize));
- __ sd(fp, Address(sp, 0));
- // we don't expect an arg reg save area
-#ifndef PRODUCT
- assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area");
-#endif
- // compiler left unloaded_class_index in j_rarg0 move to where the
- // runtime expects it.
- __ sign_extend(c_rarg1, j_rarg0, 32);
-
- // we need to set the past SP to the stack pointer of the stub frame
- // and the pc to the address where this runtime call will return
- // although actually any pc in this code blob will do).
- Label retaddr;
- __ set_last_Java_frame(sp, noreg, retaddr, t0);
-
- // Call C code. Need thread but NOT official VM entry
- // crud. We cannot block on this call, no GC can happen. Call should
- // capture callee-saved registers as well as return values.
- //
- // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index, jint exec_mode)
- //
- // n.b. 3 gp args, 0 fp args, integral return type
-
- __ mv(c_rarg0, xthread);
- __ mv(c_rarg2, Deoptimization::Unpack_uncommon_trap);
- __ rt_call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap));
- __ bind(retaddr);
-
- // Set an oopmap for the call site
- OopMapSet* oop_maps = new OopMapSet();
- OopMap* map = new OopMap(SimpleRuntimeFrame::framesize, 0);
- assert_cond(oop_maps != nullptr && map != nullptr);
-
- // location of fp is known implicitly by the frame sender code
-
- oop_maps->add_gc_map(__ pc() - start, map);
-
- __ reset_last_Java_frame(false);
-
- // move UnrollBlock* into x14
- __ mv(x14, x10);
-
-#ifdef ASSERT
- { Label L;
- __ lwu(t0, Address(x14, Deoptimization::UnrollBlock::unpack_kind_offset()));
- __ mv(t1, Deoptimization::Unpack_uncommon_trap);
- __ beq(t0, t1, L);
- __ stop("SharedRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap");
- __ bind(L);
- }
-#endif
-
- // Pop all the frames we must move/replace.
- //
- // Frame picture (youngest to oldest)
- // 1: self-frame (no frame link)
- // 2: deopting frame (no frame link)
- // 3: caller of deopting frame (could be compiled/interpreted).
-
- __ add(sp, sp, (SimpleRuntimeFrame::framesize) << LogBytesPerInt); // Epilog!
-
- // Pop deoptimized frame (int)
- __ lwu(x12, Address(x14,
- Deoptimization::UnrollBlock::
- size_of_deoptimized_frame_offset()));
- __ sub(x12, x12, 2 * wordSize);
- __ add(sp, sp, x12);
- __ ld(fp, Address(sp, 0));
- __ ld(ra, Address(sp, wordSize));
- __ addi(sp, sp, 2 * wordSize);
- // RA should now be the return address to the caller (3) frame
-
-#ifdef ASSERT
- // Compilers generate code that bang the stack by as much as the
- // interpreter would need. So this stack banging should never
- // trigger a fault. Verify that it does not on non product builds.
- __ lwu(x11, Address(x14,
- Deoptimization::UnrollBlock::
- total_frame_sizes_offset()));
- __ bang_stack_size(x11, x12);
-#endif
-
- // Load address of array of frame pcs into x12 (address*)
- __ ld(x12, Address(x14,
- Deoptimization::UnrollBlock::frame_pcs_offset()));
-
- // Load address of array of frame sizes into x15 (intptr_t*)
- __ ld(x15, Address(x14,
- Deoptimization::UnrollBlock::
- frame_sizes_offset()));
-
- // Counter
- __ lwu(x13, Address(x14,
- Deoptimization::UnrollBlock::
- number_of_frames_offset())); // (int)
-
- // Now adjust the caller's stack to make up for the extra locals but
- // record the original sp so that we can save it in the skeletal
- // interpreter frame and the stack walking of interpreter_sender
- // will get the unextended sp value and not the "real" sp value.
-
- const Register sender_sp = t1; // temporary register
-
- __ lwu(x11, Address(x14,
- Deoptimization::UnrollBlock::
- caller_adjustment_offset())); // (int)
- __ mv(sender_sp, sp);
- __ sub(sp, sp, x11);
-
- // Push interpreter frames in a loop
- Label loop;
- __ bind(loop);
- __ ld(x11, Address(x15, 0)); // Load frame size
- __ sub(x11, x11, 2 * wordSize); // We'll push pc and fp by hand
- __ ld(ra, Address(x12, 0)); // Save return address
- __ enter(); // and old fp & set new fp
- __ sub(sp, sp, x11); // Prolog
- __ sd(sender_sp, Address(fp, frame::interpreter_frame_sender_sp_offset * wordSize)); // Make it walkable
- // This value is corrected by layout_activation_impl
- __ sd(zr, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize));
- __ mv(sender_sp, sp); // Pass sender_sp to next frame
- __ add(x15, x15, wordSize); // Bump array pointer (sizes)
- __ add(x12, x12, wordSize); // Bump array pointer (pcs)
- __ subw(x13, x13, 1); // Decrement counter
- __ bgtz(x13, loop);
- __ ld(ra, Address(x12, 0)); // save final return address
- // Re-push self-frame
- __ enter(); // & old fp & set new fp
-
- // Use fp because the frames look interpreted now
- // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP.
- // Don't need the precise return PC here, just precise enough to point into this code blob.
- address the_pc = __ pc();
- __ set_last_Java_frame(sp, fp, the_pc, t0);
-
- // Call C code. Need thread but NOT official VM entry
- // crud. We cannot block on this call, no GC can happen. Call should
- // restore return values to their stack-slots with the new SP.
- //
- // BasicType unpack_frames(JavaThread* thread, int exec_mode)
- //
-
- // n.b. 2 gp args, 0 fp args, integral return type
-
- // sp should already be aligned
- __ mv(c_rarg0, xthread);
- __ mv(c_rarg1, Deoptimization::Unpack_uncommon_trap);
- __ rt_call(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames));
-
- // Set an oopmap for the call site
- // Use the same PC we used for the last java frame
- oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0));
-
- // Clear fp AND pc
- __ reset_last_Java_frame(true);
-
- // Pop self-frame.
- __ leave(); // Epilog
-
- // Jump to interpreter
- __ ret();
-
- // Make sure all code is generated
- masm->flush();
-
- _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps,
- SimpleRuntimeFrame::framesize >> 1);
-}
-#endif // COMPILER2
-
//------------------------------generate_handler_blob------
//
// Generate a special Compile2Runtime blob that saves all registers,
// and setup oopmap.
//
-SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) {
+SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) {
+ assert(is_polling_page_id(id), "expected a polling page stub id");
+
ResourceMark rm;
OopMapSet *oop_maps = new OopMapSet();
assert_cond(oop_maps != nullptr);
OopMap* map = nullptr;
// Allocate space for the code. Setup code generation tools.
- CodeBuffer buffer("handler_blob", 2048, 1024);
+ const char* name = SharedRuntime::stub_name(id);
+ CodeBuffer buffer(name, 2048, 1024);
MacroAssembler* masm = new MacroAssembler(&buffer);
assert_cond(masm != nullptr);
address start = __ pc();
address call_pc = nullptr;
int frame_size_in_words = -1;
- bool cause_return = (poll_type == POLL_AT_RETURN);
- RegisterSaver reg_saver(poll_type == POLL_AT_VECTOR_LOOP /* save_vectors */);
+ bool cause_return = (id == SharedStubId::polling_page_return_handler_id);
+ RegisterSaver reg_saver(id == SharedStubId::polling_page_vectors_safepoint_handler_id /* save_vectors */);
// Save Integer and Float registers.
map = reg_saver.save_live_registers(masm, 0, &frame_size_in_words);
@@ -2756,12 +2570,14 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
// but since this is generic code we don't know what they are and the caller
// must do any gc of the args.
//
-RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) {
+RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) {
assert(StubRoutines::forward_exception_entry() != nullptr, "must be generated before");
+ assert(is_resolve_id(id), "expected a resolve stub id");
// allocate space for the code
ResourceMark rm;
+ const char* name = SharedRuntime::stub_name(id);
CodeBuffer buffer(name, 1000, 512);
MacroAssembler* masm = new MacroAssembler(&buffer);
assert_cond(masm != nullptr);
@@ -2812,8 +2628,8 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha
reg_saver.restore_live_registers(masm);
// We are back to the original state on entry and ready to go.
-
- __ jr(t0);
+ __ mv(t1, t0);
+ __ jr(t1);
// Pending exception after the safepoint
@@ -2836,138 +2652,196 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha
return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true);
}
-#ifdef COMPILER2
-//------------------------------generate_exception_blob---------------------------
-// creates exception blob at the end
-// Using exception blob, this code is jumped from a compiled method.
-// (see emit_exception_handler in riscv.ad file)
-//
-// Given an exception pc at a call we call into the runtime for the
-// handler in this method. This handler might merely restore state
-// (i.e. callee save registers) unwind the frame and jump to the
-// exception handler for the nmethod if there is no Java level handler
-// for the nmethod.
-//
-// This code is entered with a jmp.
-//
-// Arguments:
-// x10: exception oop
-// x13: exception pc
-//
-// Results:
-// x10: exception oop
-// x13: exception pc in caller
-// destination: exception handler of caller
-//
-// Note: the exception pc MUST be at a call (precise debug information)
-// Registers x10, x13, x12, x14, x15, t0 are not callee saved.
-//
-
-void OptoRuntime::generate_exception_blob() {
- assert(!OptoRuntime::is_callee_saved_register(R13_num), "");
- assert(!OptoRuntime::is_callee_saved_register(R10_num), "");
- assert(!OptoRuntime::is_callee_saved_register(R12_num), "");
+// Continuation point for throwing of implicit exceptions that are
+// not handled in the current activation. Fabricates an exception
+// oop and initiates normal exception dispatching in this
+// frame. Since we need to preserve callee-saved values (currently
+// only for C2, but done for C1 as well) we need a callee-saved oop
+// map and therefore have to make these stubs into RuntimeStubs
+// rather than BufferBlobs. If the compiler needs all registers to
+// be preserved between the fault point and the exception handler
+// then it must assume responsibility for that in
+// AbstractCompiler::continuation_for_implicit_null_exception or
+// continuation_for_implicit_division_by_zero_exception. All other
+// implicit exceptions (e.g., NullPointerException or
+// AbstractMethodError on entry) are either at call sites or
+// otherwise assume that stack unwinding will be initiated, so
+// caller saved registers were assumed volatile in the compiler.
+
+RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) {
+ assert(is_throw_id(id), "expected a throw stub id");
+
+ const char* name = SharedRuntime::stub_name(id);
+
+ // Information about frame layout at time of blocking runtime call.
+ // Note that we only have to preserve callee-saved registers since
+ // the compilers are responsible for supplying a continuation point
+ // if they expect all registers to be preserved.
+ // n.b. riscv asserts that frame::arg_reg_save_area_bytes == 0
+ assert_cond(runtime_entry != nullptr);
+ enum layout {
+ fp_off = 0,
+ fp_off2,
+ return_off,
+ return_off2,
+ framesize // inclusive of return address
+ };
- assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
+ const int insts_size = 1024;
+ const int locs_size = 64;
- // Allocate space for the code
ResourceMark rm;
- // Setup code generation tools
- CodeBuffer buffer("exception_blob", 2048, 1024);
- MacroAssembler* masm = new MacroAssembler(&buffer);
- assert_cond(masm != nullptr);
+ const char* timer_msg = "SharedRuntime generate_throw_exception";
+ TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime));
- // TODO check various assumptions made here
- //
- // make sure we do so before running this
+ CodeBuffer code(name, insts_size, locs_size);
+ OopMapSet* oop_maps = new OopMapSet();
+ MacroAssembler* masm = new MacroAssembler(&code);
+ assert_cond(oop_maps != nullptr && masm != nullptr);
address start = __ pc();
- // push fp and retaddr by hand
- // Exception pc is 'return address' for stack walker
- __ addi(sp, sp, -2 * wordSize);
- __ sd(ra, Address(sp, wordSize));
- __ sd(fp, Address(sp));
- // there are no callee save registers and we don't expect an
- // arg reg save area
-#ifndef PRODUCT
- assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area");
-#endif
- // Store exception in Thread object. We cannot pass any arguments to the
- // handle_exception call, since we do not want to make any assumption
- // about the size of the frame where the exception happened in.
- __ sd(x10, Address(xthread, JavaThread::exception_oop_offset()));
- __ sd(x13, Address(xthread, JavaThread::exception_pc_offset()));
+ // This is an inlined and slightly modified version of call_VM
+ // which has the ability to fetch the return PC out of
+ // thread-local storage and also sets up last_Java_sp slightly
+ // differently than the real call_VM
- // This call does all the hard work. It checks if an exception handler
- // exists in the method.
- // If so, it returns the handler address.
- // If not, it prepares for stack-unwinding, restoring the callee-save
- // registers of the frame being removed.
- //
- // address OptoRuntime::handle_exception_C(JavaThread* thread)
- //
- // n.b. 1 gp arg, 0 fp args, integral return type
+ __ enter(); // Save FP and RA before call
+
+ assert(is_even(framesize / 2), "sp not 16-byte aligned");
+
+ // ra and fp are already in place
+ __ addi(sp, fp, 0 - ((unsigned)framesize << LogBytesPerInt)); // prolog
- // the stack should always be aligned
+ int frame_complete = __ pc() - start;
+
+ // Set up last_Java_sp and last_Java_fp
address the_pc = __ pc();
- __ set_last_Java_frame(sp, noreg, the_pc, t0);
+ __ set_last_Java_frame(sp, fp, the_pc, t0);
+
+ // Call runtime
__ mv(c_rarg0, xthread);
- __ rt_call(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C));
+ BLOCK_COMMENT("call runtime_entry");
+ __ rt_call(runtime_entry);
- // handle_exception_C is a special VM call which does not require an explicit
- // instruction sync afterwards.
+ // Generate oop map
+ OopMap* map = new OopMap(framesize, 0);
+ assert_cond(map != nullptr);
- // Set an oopmap for the call site. This oopmap will only be used if we
- // are unwinding the stack. Hence, all locations will be dead.
- // Callee-saved registers will be the same as the frame above (i.e.,
- // handle_exception_stub), since they were restored when we got the
- // exception.
+ oop_maps->add_gc_map(the_pc - start, map);
- OopMapSet* oop_maps = new OopMapSet();
- assert_cond(oop_maps != nullptr);
+ __ reset_last_Java_frame(true);
- oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0));
+ __ leave();
- __ reset_last_Java_frame(false);
+ // check for pending exceptions
+#ifdef ASSERT
+ Label L;
+ __ ld(t0, Address(xthread, Thread::pending_exception_offset()));
+ __ bnez(t0, L);
+ __ should_not_reach_here();
+ __ bind(L);
+#endif // ASSERT
+ __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
- // Restore callee-saved registers
+ // codeBlob framesize is in words (not VMRegImpl::slot_size)
+ RuntimeStub* stub =
+ RuntimeStub::new_runtime_stub(name,
+ &code,
+ frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps, false);
+ assert(stub != nullptr, "create runtime stub fail!");
+ return stub;
+}
- // fp is an implicitly saved callee saved register (i.e. the calling
- // convention will save restore it in prolog/epilog) Other than that
- // there are no callee save registers now that adapter frames are gone.
- // and we dont' expect an arg reg save area
- __ ld(fp, Address(sp));
- __ ld(x13, Address(sp, wordSize));
- __ addi(sp, sp , 2 * wordSize);
+#if INCLUDE_JFR
- // x10: exception handler
+static void jfr_prologue(address the_pc, MacroAssembler* masm, Register thread) {
+ __ set_last_Java_frame(sp, fp, the_pc, t0);
+ __ mv(c_rarg0, thread);
+}
- // We have a handler in x10 (could be deopt blob).
- __ mv(t0, x10);
+static void jfr_epilogue(MacroAssembler* masm) {
+ __ reset_last_Java_frame(true);
+}
+// For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
+// It returns a jobject handle to the event writer.
+// The handle is dereferenced and the return value is the event writer oop.
+RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() {
+ enum layout {
+ fp_off,
+ fp_off2,
+ return_off,
+ return_off2,
+ framesize // inclusive of return address
+ };
- // Get the exception oop
- __ ld(x10, Address(xthread, JavaThread::exception_oop_offset()));
- // Get the exception pc in case we are deoptimized
- __ ld(x14, Address(xthread, JavaThread::exception_pc_offset()));
-#ifdef ASSERT
- __ sd(zr, Address(xthread, JavaThread::exception_handler_pc_offset()));
- __ sd(zr, Address(xthread, JavaThread::exception_pc_offset()));
-#endif
- // Clear the exception oop so GC no longer processes it as a root.
- __ sd(zr, Address(xthread, JavaThread::exception_oop_offset()));
+ int insts_size = 1024;
+ int locs_size = 64;
+ const char* name = SharedRuntime::stub_name(SharedStubId::jfr_write_checkpoint_id);
+ CodeBuffer code(name, insts_size, locs_size);
+ OopMapSet* oop_maps = new OopMapSet();
+ MacroAssembler* masm = new MacroAssembler(&code);
+
+ address start = __ pc();
+ __ enter();
+ int frame_complete = __ pc() - start;
+ address the_pc = __ pc();
+ jfr_prologue(the_pc, masm, xthread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1);
+
+ jfr_epilogue(masm);
+ __ resolve_global_jobject(x10, t0, t1);
+ __ leave();
+ __ ret();
- // x10: exception oop
- // t0: exception handler
- // x14: exception pc
- // Jump to handler
+ OopMap* map = new OopMap(framesize, 1);
+ oop_maps->add_gc_map(the_pc - start, map);
- __ jr(t0);
+ RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
+ RuntimeStub::new_runtime_stub(name, &code, frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps, false);
+ return stub;
+}
- // Make sure all code is generated
- masm->flush();
+// For c2: call to return a leased buffer.
+RuntimeStub* SharedRuntime::generate_jfr_return_lease() {
+ enum layout {
+ fp_off,
+ fp_off2,
+ return_off,
+ return_off2,
+ framesize // inclusive of return address
+ };
- // Set exception blob
- _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1);
+ int insts_size = 1024;
+ int locs_size = 64;
+ const char* name = SharedRuntime::stub_name(SharedStubId::jfr_return_lease_id);
+ CodeBuffer code(name, insts_size, locs_size);
+ OopMapSet* oop_maps = new OopMapSet();
+ MacroAssembler* masm = new MacroAssembler(&code);
+
+ address start = __ pc();
+ __ enter();
+ int frame_complete = __ pc() - start;
+ address the_pc = __ pc();
+ jfr_prologue(the_pc, masm, xthread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1);
+
+ jfr_epilogue(masm);
+ __ leave();
+ __ ret();
+
+ OopMap* map = new OopMap(framesize, 1);
+ oop_maps->add_gc_map(the_pc - start, map);
+
+ RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
+ RuntimeStub::new_runtime_stub(name, &code, frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps, false);
+ return stub;
}
-#endif // COMPILER2
+
+#endif // INCLUDE_JFR
diff --git a/src/hotspot/cpu/riscv/smallRegisterMap_riscv.inline.hpp b/src/hotspot/cpu/riscv/smallRegisterMap_riscv.inline.hpp
index 93adaadcef6..9fc4f1d7b0a 100644
--- a/src/hotspot/cpu/riscv/smallRegisterMap_riscv.inline.hpp
+++ b/src/hotspot/cpu/riscv/smallRegisterMap_riscv.inline.hpp
@@ -30,8 +30,15 @@
// Java frames don't have callee saved registers (except for fp), so we can use a smaller RegisterMap
class SmallRegisterMap {
+ constexpr SmallRegisterMap() = default;
+ ~SmallRegisterMap() = default;
+ NONCOPYABLE(SmallRegisterMap);
+
public:
- static constexpr SmallRegisterMap* instance = nullptr;
+ static const SmallRegisterMap* instance() {
+ static constexpr SmallRegisterMap the_instance{};
+ return &the_instance;
+ }
private:
static void assert_is_fp(VMReg r) NOT_DEBUG_RETURN
DEBUG_ONLY({ assert (r == fp->as_VMReg() || r == fp->as_VMReg()->next(), "Reg: %s", r->name()); })
@@ -48,17 +55,6 @@ class SmallRegisterMap {
return map;
}
- SmallRegisterMap() {}
-
- SmallRegisterMap(const RegisterMap* map) {
- #ifdef ASSERT
- for(int i = 0; i < RegisterMap::reg_count; i++) {
- VMReg r = VMRegImpl::as_VMReg(i);
- if (map->location(r, (intptr_t*)nullptr) != nullptr) assert_is_fp(r);
- }
- #endif
- }
-
inline address location(VMReg reg, intptr_t* sp) const {
assert_is_fp(reg);
return (address)(sp - 2);
diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
index 2a9faee7e2f..a4744dfc05c 100644
--- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
+++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
@@ -508,7 +508,7 @@ class StubGenerator: public StubCodeGenerator {
// complete return to VM
assert(StubRoutines::_call_stub_return_address != nullptr,
"_call_stub_return_address must have been generated before");
- __ j(StubRoutines::_call_stub_return_address);
+ __ j(RuntimeAddress(StubRoutines::_call_stub_return_address));
return start;
}
@@ -2428,6 +2428,14 @@ class StubGenerator: public StubCodeGenerator {
__ la(t1, ExternalAddress(bs_asm->patching_epoch_addr()));
__ lwu(t1, t1);
__ sw(t1, thread_epoch_addr);
+ // There are two ways this can work:
+ // - The writer did system icache shootdown after the instruction stream update.
+ // Hence do nothing.
+ // - The writer trust us to make sure our icache is in sync before entering.
+ // Hence use cmodx fence (fence.i, may change).
+ if (UseCtxFencei) {
+ __ cmodx_fence();
+ }
__ membar(__ LoadLoad);
}
@@ -3774,8 +3782,7 @@ class StubGenerator: public StubCodeGenerator {
Label thaw_success;
// t1 contains the size of the frames to thaw, 0 if overflow or no more frames
__ bnez(t1, thaw_success);
- __ la(t0, ExternalAddress(StubRoutines::throw_StackOverflowError_entry()));
- __ jr(t0);
+ __ j(RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry()));
__ bind(thaw_success);
// make room for the thawed frames
@@ -4474,7 +4481,7 @@ class StubGenerator: public StubCodeGenerator {
RegSet reg_cache_saved_regs = RegSet::of(x24, x25, x26, x27); // s8, s9, s10, s11
RegSet reg_cache_regs;
reg_cache_regs += reg_cache_saved_regs;
- reg_cache_regs += RegSet::of(x28, x29, x30, x31); // t3, t4, t5, t6
+ reg_cache_regs += RegSet::of(t3, t4, t5, t6);
BufRegCache reg_cache(_masm, reg_cache_regs);
RegSet saved_regs;
@@ -5103,6 +5110,502 @@ class StubGenerator: public StubCodeGenerator {
return (address) start;
}
+ /**
+ * vector registers:
+ * input VectorRegister's: intputV1-V3, for m2 they could be v2, v4, v6, for m1 they could be v1, v2, v3
+ * index VectorRegister's: idxV1-V4, for m2 they could be v8, v10, v12, v14, for m1 they could be v4, v5, v6, v7
+ * output VectorRegister's: outputV1-V4, for m2 they could be v16, v18, v20, v22, for m1 they could be v8, v9, v10, v11
+ *
+ * NOTE: each field will occupy a vector register group
+ */
+ void base64_vector_encode_round(Register src, Register dst, Register codec,
+ Register size, Register stepSrc, Register stepDst,
+ VectorRegister inputV1, VectorRegister inputV2, VectorRegister inputV3,
+ VectorRegister idxV1, VectorRegister idxV2, VectorRegister idxV3, VectorRegister idxV4,
+ VectorRegister outputV1, VectorRegister outputV2, VectorRegister outputV3, VectorRegister outputV4,
+ Assembler::LMUL lmul) {
+ // set vector register type/len
+ __ vsetvli(x0, size, Assembler::e8, lmul);
+
+ // segmented load src into v registers: mem(src) => vr(3)
+ __ vlseg3e8_v(inputV1, src);
+
+ // src = src + register_group_len_bytes * 3
+ __ add(src, src, stepSrc);
+
+ // encoding
+ // 1. compute index into lookup table: vr(3) => vr(4)
+ __ vsrl_vi(idxV1, inputV1, 2);
+
+ __ vsrl_vi(idxV2, inputV2, 2);
+ __ vsll_vi(inputV1, inputV1, 6);
+ __ vor_vv(idxV2, idxV2, inputV1);
+ __ vsrl_vi(idxV2, idxV2, 2);
+
+ __ vsrl_vi(idxV3, inputV3, 4);
+ __ vsll_vi(inputV2, inputV2, 4);
+ __ vor_vv(idxV3, inputV2, idxV3);
+ __ vsrl_vi(idxV3, idxV3, 2);
+
+ __ vsll_vi(idxV4, inputV3, 2);
+ __ vsrl_vi(idxV4, idxV4, 2);
+
+ // 2. indexed load: vr(4) => vr(4)
+ __ vluxei8_v(outputV1, codec, idxV1);
+ __ vluxei8_v(outputV2, codec, idxV2);
+ __ vluxei8_v(outputV3, codec, idxV3);
+ __ vluxei8_v(outputV4, codec, idxV4);
+
+ // segmented store encoded data in v registers back to dst: vr(4) => mem(dst)
+ __ vsseg4e8_v(outputV1, dst);
+
+ // dst = dst + register_group_len_bytes * 4
+ __ add(dst, dst, stepDst);
+ }
+
+ /**
+ * void j.u.Base64.Encoder.encodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp, boolean isURL)
+ *
+ * Input arguments:
+ * c_rarg0 - src, source array
+ * c_rarg1 - sp, src start offset
+ * c_rarg2 - sl, src end offset
+ * c_rarg3 - dst, dest array
+ * c_rarg4 - dp, dst start offset
+ * c_rarg5 - isURL, Base64 or URL character set
+ */
+ address generate_base64_encodeBlock() {
+ alignas(64) static const char toBase64[64] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+ };
+
+ alignas(64) static const char toBase64URL[64] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
+ };
+
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "encodeBlock");
+ address start = __ pc();
+ __ enter();
+
+ Register src = c_rarg0;
+ Register soff = c_rarg1;
+ Register send = c_rarg2;
+ Register dst = c_rarg3;
+ Register doff = c_rarg4;
+ Register isURL = c_rarg5;
+
+ Register codec = c_rarg6;
+ Register length = c_rarg7; // total length of src data in bytes
+
+ Label ProcessData, Exit;
+
+ // length should be multiple of 3
+ __ sub(length, send, soff);
+ // real src/dst to process data
+ __ add(src, src, soff);
+ __ add(dst, dst, doff);
+
+ // load the codec base address
+ __ la(codec, ExternalAddress((address) toBase64));
+ __ beqz(isURL, ProcessData);
+ __ la(codec, ExternalAddress((address) toBase64URL));
+ __ BIND(ProcessData);
+
+ // vector version
+ if (UseRVV) {
+ Label ProcessM2, ProcessM1, ProcessScalar;
+
+ Register size = soff;
+ Register stepSrcM1 = send;
+ Register stepSrcM2 = doff;
+ Register stepDst = isURL;
+
+ __ mv(size, MaxVectorSize * 2);
+ __ mv(stepSrcM1, MaxVectorSize * 3);
+ __ slli(stepSrcM2, stepSrcM1, 1);
+ __ mv(stepDst, MaxVectorSize * 2 * 4);
+
+ __ blt(length, stepSrcM2, ProcessM1);
+
+ __ BIND(ProcessM2);
+ base64_vector_encode_round(src, dst, codec,
+ size, stepSrcM2, stepDst,
+ v2, v4, v6, // inputs
+ v8, v10, v12, v14, // indexes
+ v16, v18, v20, v22, // outputs
+ Assembler::m2);
+
+ __ sub(length, length, stepSrcM2);
+ __ bge(length, stepSrcM2, ProcessM2);
+
+ __ BIND(ProcessM1);
+ __ blt(length, stepSrcM1, ProcessScalar);
+
+ __ srli(size, size, 1);
+ __ srli(stepDst, stepDst, 1);
+ base64_vector_encode_round(src, dst, codec,
+ size, stepSrcM1, stepDst,
+ v1, v2, v3, // inputs
+ v4, v5, v6, v7, // indexes
+ v8, v9, v10, v11, // outputs
+ Assembler::m1);
+ __ sub(length, length, stepSrcM1);
+
+ __ BIND(ProcessScalar);
+ }
+
+ // scalar version
+ {
+ Register byte1 = soff, byte0 = send, byte2 = doff;
+ Register combined24Bits = isURL;
+
+ __ beqz(length, Exit);
+
+ Label ScalarLoop;
+ __ BIND(ScalarLoop);
+ {
+ // plain: [byte0[7:0] : byte1[7:0] : byte2[7:0]] =>
+ // encoded: [byte0[7:2] : byte0[1:0]+byte1[7:4] : byte1[3:0]+byte2[7:6] : byte2[5:0]]
+
+ // load 3 bytes src data
+ __ lbu(byte0, Address(src, 0));
+ __ lbu(byte1, Address(src, 1));
+ __ lbu(byte2, Address(src, 2));
+ __ addi(src, src, 3);
+
+ // construct 24 bits from 3 bytes
+ __ slliw(byte0, byte0, 16);
+ __ slliw(byte1, byte1, 8);
+ __ orr(combined24Bits, byte0, byte1);
+ __ orr(combined24Bits, combined24Bits, byte2);
+
+ // get codec index and encode(ie. load from codec by index)
+ __ slliw(byte0, combined24Bits, 8);
+ __ srliw(byte0, byte0, 26);
+ __ add(byte0, codec, byte0);
+ __ lbu(byte0, byte0);
+
+ __ slliw(byte1, combined24Bits, 14);
+ __ srliw(byte1, byte1, 26);
+ __ add(byte1, codec, byte1);
+ __ lbu(byte1, byte1);
+
+ __ slliw(byte2, combined24Bits, 20);
+ __ srliw(byte2, byte2, 26);
+ __ add(byte2, codec, byte2);
+ __ lbu(byte2, byte2);
+
+ __ andi(combined24Bits, combined24Bits, 0x3f);
+ __ add(combined24Bits, codec, combined24Bits);
+ __ lbu(combined24Bits, combined24Bits);
+
+ // store 4 bytes encoded data
+ __ sb(byte0, Address(dst, 0));
+ __ sb(byte1, Address(dst, 1));
+ __ sb(byte2, Address(dst, 2));
+ __ sb(combined24Bits, Address(dst, 3));
+
+ __ sub(length, length, 3);
+ __ addi(dst, dst, 4);
+ // loop back
+ __ bnez(length, ScalarLoop);
+ }
+ }
+
+ __ BIND(Exit);
+
+ __ leave();
+ __ ret();
+
+ return (address) start;
+ }
+
+ /**
+ * vector registers:
+ * input VectorRegister's: intputV1-V4, for m2 they could be v2, v4, v6, for m1 they could be v2, v4, v6, v8
+ * index VectorRegister's: idxV1-V3, for m2 they could be v8, v10, v12, v14, for m1 they could be v10, v12, v14, v16
+ * output VectorRegister's: outputV1-V4, for m2 they could be v16, v18, v20, v22, for m1 they could be v18, v20, v22
+ *
+ * NOTE: each field will occupy a single vector register group
+ */
+ void base64_vector_decode_round(Register src, Register dst, Register codec,
+ Register size, Register stepSrc, Register stepDst, Register failedIdx,
+ VectorRegister inputV1, VectorRegister inputV2, VectorRegister inputV3, VectorRegister inputV4,
+ VectorRegister idxV1, VectorRegister idxV2, VectorRegister idxV3, VectorRegister idxV4,
+ VectorRegister outputV1, VectorRegister outputV2, VectorRegister outputV3,
+ Assembler::LMUL lmul) {
+ // set vector register type/len
+ __ vsetvli(x0, size, Assembler::e8, lmul, Assembler::ma, Assembler::ta);
+
+ // segmented load src into v registers: mem(src) => vr(4)
+ __ vlseg4e8_v(inputV1, src);
+
+ // src = src + register_group_len_bytes * 4
+ __ add(src, src, stepSrc);
+
+ // decoding
+ // 1. indexed load: vr(4) => vr(4)
+ __ vluxei8_v(idxV1, codec, inputV1);
+ __ vluxei8_v(idxV2, codec, inputV2);
+ __ vluxei8_v(idxV3, codec, inputV3);
+ __ vluxei8_v(idxV4, codec, inputV4);
+
+ // 2. check wrong data
+ __ vor_vv(outputV1, idxV1, idxV2);
+ __ vor_vv(outputV2, idxV3, idxV4);
+ __ vor_vv(outputV1, outputV1, outputV2);
+ __ vmseq_vi(v0, outputV1, -1);
+ __ vfirst_m(failedIdx, v0);
+ Label NoFailure, FailureAtIdx0;
+ // valid value can only be -1 when < 0
+ __ bltz(failedIdx, NoFailure);
+ // when the first data (at index 0) fails, no need to process data anymore
+ __ beqz(failedIdx, FailureAtIdx0);
+ __ vsetvli(x0, failedIdx, Assembler::e8, lmul, Assembler::mu, Assembler::tu);
+ __ slli(stepDst, failedIdx, 1);
+ __ add(stepDst, failedIdx, stepDst);
+ __ BIND(NoFailure);
+
+ // 3. compute the decoded data: vr(4) => vr(3)
+ __ vsll_vi(idxV1, idxV1, 2);
+ __ vsrl_vi(outputV1, idxV2, 4);
+ __ vor_vv(outputV1, outputV1, idxV1);
+
+ __ vsll_vi(idxV2, idxV2, 4);
+ __ vsrl_vi(outputV2, idxV3, 2);
+ __ vor_vv(outputV2, outputV2, idxV2);
+
+ __ vsll_vi(idxV3, idxV3, 6);
+ __ vor_vv(outputV3, idxV4, idxV3);
+
+ // segmented store encoded data in v registers back to dst: vr(3) => mem(dst)
+ __ vsseg3e8_v(outputV1, dst);
+
+ // dst = dst + register_group_len_bytes * 3
+ __ add(dst, dst, stepDst);
+ __ BIND(FailureAtIdx0);
+ }
+
+ /**
+ * int j.u.Base64.Decoder.decodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp, boolean isURL, boolean isMIME)
+ *
+ * Input arguments:
+ * c_rarg0 - src, source array
+ * c_rarg1 - sp, src start offset
+ * c_rarg2 - sl, src end offset
+ * c_rarg3 - dst, dest array
+ * c_rarg4 - dp, dst start offset
+ * c_rarg5 - isURL, Base64 or URL character set
+ * c_rarg6 - isMIME, Decoding MIME block
+ */
+ address generate_base64_decodeBlock() {
+
+ static const uint8_t fromBase64[256] = {
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 62u, 255u, 255u, 255u, 63u,
+ 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u,
+ 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u,
+ 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ };
+
+ static const uint8_t fromBase64URL[256] = {
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 62u, 255u, 255u,
+ 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u,
+ 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 255u, 255u, 255u, 255u, 63u,
+ 255u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u,
+ 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ };
+
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "decodeBlock");
+ address start = __ pc();
+ __ enter();
+
+ Register src = c_rarg0;
+ Register soff = c_rarg1;
+ Register send = c_rarg2;
+ Register dst = c_rarg3;
+ Register doff = c_rarg4;
+ Register isURL = c_rarg5;
+ Register isMIME = c_rarg6;
+
+ Register codec = c_rarg7;
+ Register dstBackup = t6;
+ Register length = t3; // total length of src data in bytes
+
+ Label ProcessData, Exit;
+ Label ProcessScalar, ScalarLoop;
+
+ // passed in length (send - soff) is guaranteed to be > 4,
+ // and in this intrinsic we only process data of length in multiple of 4,
+ // it's not guaranteed to be multiple of 4 by java level, so do it explicitly
+ __ sub(length, send, soff);
+ __ andi(length, length, -4);
+ // real src/dst to process data
+ __ add(src, src, soff);
+ __ add(dst, dst, doff);
+ // backup of dst, used to calculate the return value at exit
+ __ mv(dstBackup, dst);
+
+ // load the codec base address
+ __ la(codec, ExternalAddress((address) fromBase64));
+ __ beqz(isURL, ProcessData);
+ __ la(codec, ExternalAddress((address) fromBase64URL));
+ __ BIND(ProcessData);
+
+ // vector version
+ if (UseRVV) {
+ // for MIME case, it has a default length limit of 76 which could be
+ // different(smaller) from (send - soff), so in MIME case, we go through
+ // the scalar code path directly.
+ __ bnez(isMIME, ScalarLoop);
+
+ Label ProcessM1, ProcessM2;
+
+ Register failedIdx = soff;
+ Register stepSrcM1 = send;
+ Register stepSrcM2 = doff;
+ Register stepDst = isURL;
+ Register size = t4;
+
+ __ mv(size, MaxVectorSize * 2);
+ __ mv(stepSrcM1, MaxVectorSize * 4);
+ __ slli(stepSrcM2, stepSrcM1, 1);
+ __ mv(stepDst, MaxVectorSize * 2 * 3);
+
+ __ blt(length, stepSrcM2, ProcessM1);
+
+
+ // Assembler::m2
+ __ BIND(ProcessM2);
+ base64_vector_decode_round(src, dst, codec,
+ size, stepSrcM2, stepDst, failedIdx,
+ v2, v4, v6, v8, // inputs
+ v10, v12, v14, v16, // indexes
+ v18, v20, v22, // outputs
+ Assembler::m2);
+ __ sub(length, length, stepSrcM2);
+
+ // error check
+ // valid value of failedIdx can only be -1 when < 0
+ __ bgez(failedIdx, Exit);
+
+ __ bge(length, stepSrcM2, ProcessM2);
+
+
+ // Assembler::m1
+ __ BIND(ProcessM1);
+ __ blt(length, stepSrcM1, ProcessScalar);
+
+ __ srli(size, size, 1);
+ __ srli(stepDst, stepDst, 1);
+ base64_vector_decode_round(src, dst, codec,
+ size, stepSrcM1, stepDst, failedIdx,
+ v1, v2, v3, v4, // inputs
+ v5, v6, v7, v8, // indexes
+ v9, v10, v11, // outputs
+ Assembler::m1);
+ __ sub(length, length, stepSrcM1);
+
+ // error check
+ // valid value of failedIdx can only be -1 when < 0
+ __ bgez(failedIdx, Exit);
+
+ __ BIND(ProcessScalar);
+ __ beqz(length, Exit);
+ }
+
+ // scalar version
+ {
+ Register byte0 = soff, byte1 = send, byte2 = doff, byte3 = isURL;
+ Register combined32Bits = t4;
+
+ // encoded: [byte0[5:0] : byte1[5:0] : byte2[5:0]] : byte3[5:0]] =>
+ // plain: [byte0[5:0]+byte1[5:4] : byte1[3:0]+byte2[5:2] : byte2[1:0]+byte3[5:0]]
+ __ BIND(ScalarLoop);
+
+ // load 4 bytes encoded src data
+ __ lbu(byte0, Address(src, 0));
+ __ lbu(byte1, Address(src, 1));
+ __ lbu(byte2, Address(src, 2));
+ __ lbu(byte3, Address(src, 3));
+ __ addi(src, src, 4);
+
+ // get codec index and decode (ie. load from codec by index)
+ __ add(byte0, codec, byte0);
+ __ add(byte1, codec, byte1);
+ __ lb(byte0, Address(byte0, 0));
+ __ lb(byte1, Address(byte1, 0));
+ __ add(byte2, codec, byte2);
+ __ add(byte3, codec, byte3);
+ __ lb(byte2, Address(byte2, 0));
+ __ lb(byte3, Address(byte3, 0));
+ __ slliw(byte0, byte0, 18);
+ __ slliw(byte1, byte1, 12);
+ __ orr(byte0, byte0, byte1);
+ __ orr(byte0, byte0, byte3);
+ __ slliw(byte2, byte2, 6);
+ // For performance consideration, `combined32Bits` is constructed for 2 purposes at the same time,
+ // 1. error check below
+ // 2. decode below
+ __ orr(combined32Bits, byte0, byte2);
+
+ // error check
+ __ bltz(combined32Bits, Exit);
+
+ // store 3 bytes decoded data
+ __ sraiw(byte0, combined32Bits, 16);
+ __ sraiw(byte1, combined32Bits, 8);
+ __ sb(byte0, Address(dst, 0));
+ __ sb(byte1, Address(dst, 1));
+ __ sb(combined32Bits, Address(dst, 2));
+
+ __ sub(length, length, 4);
+ __ addi(dst, dst, 3);
+ // loop back
+ __ bnez(length, ScalarLoop);
+ }
+
+ __ BIND(Exit);
+ __ sub(c_rarg0, dst, dstBackup);
+
+ __ leave();
+ __ ret();
+
+ return (address) start;
+ }
+
void adler32_process_bytes(Register buff, Register s1, Register s2, VectorRegister vtable,
VectorRegister vzero, VectorRegister vbytes, VectorRegister vs1acc, VectorRegister vs2acc,
Register temp0, Register temp1, Register temp2, Register temp3,
@@ -5204,10 +5707,10 @@ class StubGenerator: public StubCodeGenerator {
Register nmax = c_rarg4;
Register base = c_rarg5;
Register count = c_rarg6;
- Register temp0 = x28; // t3
- Register temp1 = x29; // t4
- Register temp2 = x30; // t5
- Register temp3 = x31; // t6
+ Register temp0 = t3;
+ Register temp1 = t4;
+ Register temp2 = t5;
+ Register temp3 = t6;
VectorRegister vzero = v31;
VectorRegister vbytes = v8; // group: v8, v9, v10, v11
@@ -5567,6 +6070,58 @@ static const int64_t right_3_bits = right_n_bits(3);
return start;
}
+ void generate_vector_math_stubs() {
+ if (!UseRVV) {
+ log_info(library)("vector is not supported, skip loading vector math (sleef) library!");
+ return;
+ }
+
+ // Get native vector math stub routine addresses
+ void* libsleef = nullptr;
+ char ebuf[1024];
+ char dll_name[JVM_MAXPATHLEN];
+ if (os::dll_locate_lib(dll_name, sizeof(dll_name), Arguments::get_dll_dir(), "sleef")) {
+ libsleef = os::dll_load(dll_name, ebuf, sizeof ebuf);
+ }
+ if (libsleef == nullptr) {
+ log_info(library)("Failed to load native vector math (sleef) library, %s!", ebuf);
+ return;
+ }
+
+ // Method naming convention
+ // All the methods are named as _
+ //
+ // Where:
+ // is the operation name, e.g. sin, cos
+ // is to indicate float/double
+ // "fx/dx" for vector float/double operation
+ // is the precision level
+ // "u10/u05" represents 1.0/0.5 ULP error bounds
+ // We use "u10" for all operations by default
+ // But for those functions do not have u10 support, we use "u05" instead
+ // rvv, indicates riscv vector extension
+ //
+ // e.g. sinfx_u10rvv is the method for computing vector float sin using rvv instructions
+ //
+ log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "sleef" JNI_LIB_SUFFIX, p2i(libsleef));
+
+ for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) {
+ int vop = VectorSupport::VECTOR_OP_MATH_START + op;
+ if (vop == VectorSupport::VECTOR_OP_TANH) { // skip tanh because of performance regression
+ continue;
+ }
+
+ // The native library does not support u10 level of "hypot".
+ const char* ulf = (vop == VectorSupport::VECTOR_OP_HYPOT) ? "u05" : "u10";
+
+ snprintf(ebuf, sizeof(ebuf), "%sfx_%srvv", VectorSupport::mathname[op], ulf);
+ StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf);
+
+ snprintf(ebuf, sizeof(ebuf), "%sdx_%srvv", VectorSupport::mathname[op], ulf);
+ StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf);
+ }
+ }
+
#endif // COMPILER2
/**
@@ -5588,26 +6143,17 @@ static const int64_t right_3_bits = right_n_bits(3);
address start = __ pc();
+ // input parameters
const Register crc = c_rarg0; // crc
const Register buf = c_rarg1; // source java byte array address
const Register len = c_rarg2; // length
- const Register table0 = c_rarg3; // crc_table address
- const Register table1 = c_rarg4;
- const Register table2 = c_rarg5;
- const Register table3 = c_rarg6;
-
- const Register tmp1 = c_rarg7;
- const Register tmp2 = t2;
- const Register tmp3 = x28; // t3
- const Register tmp4 = x29; // t4
- const Register tmp5 = x30; // t5
- const Register tmp6 = x31; // t6
BLOCK_COMMENT("Entry:");
__ enter(); // required for proper stackwalking of RuntimeStub frame
- __ kernel_crc32(crc, buf, len, table0, table1, table2,
- table3, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6);
+ __ kernel_crc32(crc, buf, len,
+ c_rarg3, c_rarg4, c_rarg5, c_rarg6, // tmp's for tables
+ c_rarg7, t2, t3, t4, t5, t6); // misc tmps
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret();
@@ -5615,97 +6161,6 @@ static const int64_t right_3_bits = right_n_bits(3);
return start;
}
-#if INCLUDE_JFR
-
- static void jfr_prologue(address the_pc, MacroAssembler* _masm, Register thread) {
- __ set_last_Java_frame(sp, fp, the_pc, t0);
- __ mv(c_rarg0, thread);
- }
-
- static void jfr_epilogue(MacroAssembler* _masm) {
- __ reset_last_Java_frame(true);
- }
- // For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
- // It returns a jobject handle to the event writer.
- // The handle is dereferenced and the return value is the event writer oop.
- static RuntimeStub* generate_jfr_write_checkpoint() {
- enum layout {
- fp_off,
- fp_off2,
- return_off,
- return_off2,
- framesize // inclusive of return address
- };
-
- int insts_size = 1024;
- int locs_size = 64;
- CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size);
- OopMapSet* oop_maps = new OopMapSet();
- MacroAssembler* masm = new MacroAssembler(&code);
- MacroAssembler* _masm = masm;
-
- address start = __ pc();
- __ enter();
- int frame_complete = __ pc() - start;
- address the_pc = __ pc();
- jfr_prologue(the_pc, _masm, xthread);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1);
-
- jfr_epilogue(_masm);
- __ resolve_global_jobject(x10, t0, t1);
- __ leave();
- __ ret();
-
- OopMap* map = new OopMap(framesize, 1);
- oop_maps->add_gc_map(the_pc - start, map);
-
- RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
- RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps, false);
- return stub;
- }
-
- // For c2: call to return a leased buffer.
- static RuntimeStub* generate_jfr_return_lease() {
- enum layout {
- fp_off,
- fp_off2,
- return_off,
- return_off2,
- framesize // inclusive of return address
- };
-
- int insts_size = 1024;
- int locs_size = 64;
- CodeBuffer code("jfr_return_lease", insts_size, locs_size);
- OopMapSet* oop_maps = new OopMapSet();
- MacroAssembler* masm = new MacroAssembler(&code);
- MacroAssembler* _masm = masm;
-
- address start = __ pc();
- __ enter();
- int frame_complete = __ pc() - start;
- address the_pc = __ pc();
- jfr_prologue(the_pc, _masm, xthread);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1);
-
- jfr_epilogue(_masm);
- __ leave();
- __ ret();
-
- OopMap* map = new OopMap(framesize, 1);
- oop_maps->add_gc_map(the_pc - start, map);
-
- RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
- RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps, false);
- return stub;
- }
-
-#endif // INCLUDE_JFR
-
// exception handler for upcall stubs
address generate_upcall_stub_exception_handler() {
StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler");
@@ -5720,112 +6175,27 @@ static const int64_t right_3_bits = right_n_bits(3);
return start;
}
- // Continuation point for throwing of implicit exceptions that are
- // not handled in the current activation. Fabricates an exception
- // oop and initiates normal exception dispatching in this
- // frame. Since we need to preserve callee-saved values (currently
- // only for C2, but done for C1 as well) we need a callee-saved oop
- // map and therefore have to make these stubs into RuntimeStubs
- // rather than BufferBlobs. If the compiler needs all registers to
- // be preserved between the fault point and the exception handler
- // then it must assume responsibility for that in
- // AbstractCompiler::continuation_for_implicit_null_exception or
- // continuation_for_implicit_division_by_zero_exception. All other
- // implicit exceptions (e.g., NullPointerException or
- // AbstractMethodError on entry) are either at call sites or
- // otherwise assume that stack unwinding will be initiated, so
- // caller saved registers were assumed volatile in the compiler.
-
-#undef __
-#define __ masm->
-
- address generate_throw_exception(const char* name,
- address runtime_entry,
- Register arg1 = noreg,
- Register arg2 = noreg) {
- // Information about frame layout at time of blocking runtime call.
- // Note that we only have to preserve callee-saved registers since
- // the compilers are responsible for supplying a continuation point
- // if they expect all registers to be preserved.
- // n.b. riscv asserts that frame::arg_reg_save_area_bytes == 0
- assert_cond(runtime_entry != nullptr);
- enum layout {
- fp_off = 0,
- fp_off2,
- return_off,
- return_off2,
- framesize // inclusive of return address
- };
-
- const int insts_size = 1024;
- const int locs_size = 64;
-
- CodeBuffer code(name, insts_size, locs_size);
- OopMapSet* oop_maps = new OopMapSet();
- MacroAssembler* masm = new MacroAssembler(&code);
- assert_cond(oop_maps != nullptr && masm != nullptr);
+ // load Method* target of MethodHandle
+ // j_rarg0 = jobject receiver
+ // xmethod = Method* result
+ address generate_upcall_stub_load_target() {
+ StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target");
address start = __ pc();
- // This is an inlined and slightly modified version of call_VM
- // which has the ability to fetch the return PC out of
- // thread-local storage and also sets up last_Java_sp slightly
- // differently than the real call_VM
-
- __ enter(); // Save FP and RA before call
+ __ resolve_global_jobject(j_rarg0, t0, t1);
+ // Load target method from receiver
+ __ load_heap_oop(xmethod, Address(j_rarg0, java_lang_invoke_MethodHandle::form_offset()), t0, t1);
+ __ load_heap_oop(xmethod, Address(xmethod, java_lang_invoke_LambdaForm::vmentry_offset()), t0, t1);
+ __ load_heap_oop(xmethod, Address(xmethod, java_lang_invoke_MemberName::method_offset()), t0, t1);
+ __ access_load_at(T_ADDRESS, IN_HEAP, xmethod,
+ Address(xmethod, java_lang_invoke_ResolvedMethodName::vmtarget_offset()),
+ noreg, noreg);
+ __ sd(xmethod, Address(xthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized
- assert(is_even(framesize / 2), "sp not 16-byte aligned");
-
- // ra and fp are already in place
- __ addi(sp, fp, 0 - ((unsigned)framesize << LogBytesPerInt)); // prolog
-
- int frame_complete = __ pc() - start;
-
- // Set up last_Java_sp and last_Java_fp
- address the_pc = __ pc();
- __ set_last_Java_frame(sp, fp, the_pc, t0);
-
- // Call runtime
- if (arg1 != noreg) {
- assert(arg2 != c_rarg1, "clobbered");
- __ mv(c_rarg1, arg1);
- }
- if (arg2 != noreg) {
- __ mv(c_rarg2, arg2);
- }
- __ mv(c_rarg0, xthread);
- BLOCK_COMMENT("call runtime_entry");
- __ rt_call(runtime_entry);
-
- // Generate oop map
- OopMap* map = new OopMap(framesize, 0);
- assert_cond(map != nullptr);
-
- oop_maps->add_gc_map(the_pc - start, map);
-
- __ reset_last_Java_frame(true);
-
- __ leave();
+ __ ret();
- // check for pending exceptions
-#ifdef ASSERT
- Label L;
- __ ld(t0, Address(xthread, Thread::pending_exception_offset()));
- __ bnez(t0, L);
- __ should_not_reach_here();
- __ bind(L);
-#endif // ASSERT
- __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
-
- // codeBlob framesize is in words (not VMRegImpl::slot_size)
- RuntimeStub* stub =
- RuntimeStub::new_runtime_stub(name,
- &code,
- frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps, false);
- assert(stub != nullptr, "create runtime stub fail!");
- return stub->entry_point();
+ return start;
}
#undef __
@@ -5852,16 +6222,6 @@ static const int64_t right_3_bits = right_n_bits(3);
// is referenced by megamorphic call
StubRoutines::_catch_exception_entry = generate_catch_exception();
- // Build this early so it's available for the interpreter.
- StubRoutines::_throw_StackOverflowError_entry =
- generate_throw_exception("StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::throw_StackOverflowError));
- StubRoutines::_throw_delayed_StackOverflowError_entry =
- generate_throw_exception("delayed StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::throw_delayed_StackOverflowError));
-
if (UseCRC32Intrinsics) {
// set table address before stub generation which use it
StubRoutines::_crc_table_adr = (address)StubRoutines::riscv::_crc_table;
@@ -5874,42 +6234,14 @@ static const int64_t right_3_bits = right_n_bits(3);
StubRoutines::_cont_thaw = generate_cont_thaw();
StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier();
StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception();
-
- JFR_ONLY(generate_jfr_stubs();)
}
-#if INCLUDE_JFR
- void generate_jfr_stubs() {
- StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint();
- StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point();
- StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease();
- StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point();
- }
-#endif // INCLUDE_JFR
-
void generate_final_stubs() {
// support for verify_oop (must happen after universe_init)
if (VerifyOops) {
StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop();
}
- StubRoutines::_throw_AbstractMethodError_entry =
- generate_throw_exception("AbstractMethodError throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::
- throw_AbstractMethodError));
-
- StubRoutines::_throw_IncompatibleClassChangeError_entry =
- generate_throw_exception("IncompatibleClassChangeError throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::
- throw_IncompatibleClassChangeError));
-
- StubRoutines::_throw_NullPointerException_at_call_entry =
- generate_throw_exception("NullPointerException at call throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::
- throw_NullPointerException_at_call));
// arraycopy stubs used by compilers
generate_arraycopy_stubs();
@@ -5931,12 +6263,12 @@ static const int64_t right_3_bits = right_n_bits(3);
#endif // COMPILER2
StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler();
+ StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target();
StubRoutines::riscv::set_completed();
}
void generate_compiler_stubs() {
-#if COMPILER2_OR_JVMCI
#ifdef COMPILER2
if (UseMulAddIntrinsic) {
StubRoutines::_mulAdd = generate_mulAdd();
@@ -5970,7 +6302,6 @@ static const int64_t right_3_bits = right_n_bits(3);
StubRoutines::_bigIntegerLeftShiftWorker = generate_bigIntegerLeftShift();
StubRoutines::_bigIntegerRightShiftWorker = generate_bigIntegerRightShift();
}
-#endif // COMPILER2
if (UseSHA256Intrinsics) {
Sha2Generator sha2(_masm, this);
@@ -5984,10 +6315,6 @@ static const int64_t right_3_bits = right_n_bits(3);
StubRoutines::_sha512_implCompressMB = sha2.generate_sha512_implCompress(true);
}
- 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");
@@ -6002,11 +6329,22 @@ static const int64_t right_3_bits = right_n_bits(3);
StubRoutines::_sha1_implCompressMB = generate_sha1_implCompress(true, "sha1_implCompressMB");
}
+ if (UseBASE64Intrinsics) {
+ StubRoutines::_base64_encodeBlock = generate_base64_encodeBlock();
+ StubRoutines::_base64_decodeBlock = generate_base64_decodeBlock();
+ }
+
if (UseAdler32Intrinsics) {
StubRoutines::_updateBytesAdler32 = generate_updateBytesAdler32();
}
-#endif // COMPILER2_OR_JVMCI
+ generate_compare_long_strings();
+
+ generate_string_indexof_stubs();
+
+ generate_vector_math_stubs();
+
+#endif // COMPILER2
}
public:
diff --git a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp
index 05bdeaf7570..6d5492b86b3 100644
--- a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp
+++ b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp
@@ -276,4 +276,219 @@ ATTRIBUTE_ALIGNED(4096) juint StubRoutines::riscv::_crc_table[] =
0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
0xde0506f1UL,
+
+ // Tables for vector version
+ // This improvement (vectorization) is based on java.base/share/native/libzip/zlib/zcrc32.c.
+ // To make it, following steps are taken:
+ // 1. in zcrc32.c, modify N to 16 and related code,
+ // 2. re-generate the tables needed, we use tables of (N == 16, W == 4)
+ // 3. finally vectorize the code (original implementation in zcrc32.c is just scalar code).
+ 0x00000000, 0x8f352d95, 0xc51b5d6b, 0x4a2e70fe, 0x5147bc97,
+ 0xde729102, 0x945ce1fc, 0x1b69cc69, 0xa28f792e, 0x2dba54bb,
+ 0x67942445, 0xe8a109d0, 0xf3c8c5b9, 0x7cfde82c, 0x36d398d2,
+ 0xb9e6b547, 0x9e6ff41d, 0x115ad988, 0x5b74a976, 0xd44184e3,
+ 0xcf28488a, 0x401d651f, 0x0a3315e1, 0x85063874, 0x3ce08d33,
+ 0xb3d5a0a6, 0xf9fbd058, 0x76cefdcd, 0x6da731a4, 0xe2921c31,
+ 0xa8bc6ccf, 0x2789415a, 0xe7aeee7b, 0x689bc3ee, 0x22b5b310,
+ 0xad809e85, 0xb6e952ec, 0x39dc7f79, 0x73f20f87, 0xfcc72212,
+ 0x45219755, 0xca14bac0, 0x803aca3e, 0x0f0fe7ab, 0x14662bc2,
+ 0x9b530657, 0xd17d76a9, 0x5e485b3c, 0x79c11a66, 0xf6f437f3,
+ 0xbcda470d, 0x33ef6a98, 0x2886a6f1, 0xa7b38b64, 0xed9dfb9a,
+ 0x62a8d60f, 0xdb4e6348, 0x547b4edd, 0x1e553e23, 0x916013b6,
+ 0x8a09dfdf, 0x053cf24a, 0x4f1282b4, 0xc027af21, 0x142cdab7,
+ 0x9b19f722, 0xd13787dc, 0x5e02aa49, 0x456b6620, 0xca5e4bb5,
+ 0x80703b4b, 0x0f4516de, 0xb6a3a399, 0x39968e0c, 0x73b8fef2,
+ 0xfc8dd367, 0xe7e41f0e, 0x68d1329b, 0x22ff4265, 0xadca6ff0,
+ 0x8a432eaa, 0x0576033f, 0x4f5873c1, 0xc06d5e54, 0xdb04923d,
+ 0x5431bfa8, 0x1e1fcf56, 0x912ae2c3, 0x28cc5784, 0xa7f97a11,
+ 0xedd70aef, 0x62e2277a, 0x798beb13, 0xf6bec686, 0xbc90b678,
+ 0x33a59bed, 0xf38234cc, 0x7cb71959, 0x369969a7, 0xb9ac4432,
+ 0xa2c5885b, 0x2df0a5ce, 0x67ded530, 0xe8ebf8a5, 0x510d4de2,
+ 0xde386077, 0x94161089, 0x1b233d1c, 0x004af175, 0x8f7fdce0,
+ 0xc551ac1e, 0x4a64818b, 0x6dedc0d1, 0xe2d8ed44, 0xa8f69dba,
+ 0x27c3b02f, 0x3caa7c46, 0xb39f51d3, 0xf9b1212d, 0x76840cb8,
+ 0xcf62b9ff, 0x4057946a, 0x0a79e494, 0x854cc901, 0x9e250568,
+ 0x111028fd, 0x5b3e5803, 0xd40b7596, 0x2859b56e, 0xa76c98fb,
+ 0xed42e805, 0x6277c590, 0x791e09f9, 0xf62b246c, 0xbc055492,
+ 0x33307907, 0x8ad6cc40, 0x05e3e1d5, 0x4fcd912b, 0xc0f8bcbe,
+ 0xdb9170d7, 0x54a45d42, 0x1e8a2dbc, 0x91bf0029, 0xb6364173,
+ 0x39036ce6, 0x732d1c18, 0xfc18318d, 0xe771fde4, 0x6844d071,
+ 0x226aa08f, 0xad5f8d1a, 0x14b9385d, 0x9b8c15c8, 0xd1a26536,
+ 0x5e9748a3, 0x45fe84ca, 0xcacba95f, 0x80e5d9a1, 0x0fd0f434,
+ 0xcff75b15, 0x40c27680, 0x0aec067e, 0x85d92beb, 0x9eb0e782,
+ 0x1185ca17, 0x5babbae9, 0xd49e977c, 0x6d78223b, 0xe24d0fae,
+ 0xa8637f50, 0x275652c5, 0x3c3f9eac, 0xb30ab339, 0xf924c3c7,
+ 0x7611ee52, 0x5198af08, 0xdead829d, 0x9483f263, 0x1bb6dff6,
+ 0x00df139f, 0x8fea3e0a, 0xc5c44ef4, 0x4af16361, 0xf317d626,
+ 0x7c22fbb3, 0x360c8b4d, 0xb939a6d8, 0xa2506ab1, 0x2d654724,
+ 0x674b37da, 0xe87e1a4f, 0x3c756fd9, 0xb340424c, 0xf96e32b2,
+ 0x765b1f27, 0x6d32d34e, 0xe207fedb, 0xa8298e25, 0x271ca3b0,
+ 0x9efa16f7, 0x11cf3b62, 0x5be14b9c, 0xd4d46609, 0xcfbdaa60,
+ 0x408887f5, 0x0aa6f70b, 0x8593da9e, 0xa21a9bc4, 0x2d2fb651,
+ 0x6701c6af, 0xe834eb3a, 0xf35d2753, 0x7c680ac6, 0x36467a38,
+ 0xb97357ad, 0x0095e2ea, 0x8fa0cf7f, 0xc58ebf81, 0x4abb9214,
+ 0x51d25e7d, 0xdee773e8, 0x94c90316, 0x1bfc2e83, 0xdbdb81a2,
+ 0x54eeac37, 0x1ec0dcc9, 0x91f5f15c, 0x8a9c3d35, 0x05a910a0,
+ 0x4f87605e, 0xc0b24dcb, 0x7954f88c, 0xf661d519, 0xbc4fa5e7,
+ 0x337a8872, 0x2813441b, 0xa726698e, 0xed081970, 0x623d34e5,
+ 0x45b475bf, 0xca81582a, 0x80af28d4, 0x0f9a0541, 0x14f3c928,
+ 0x9bc6e4bd, 0xd1e89443, 0x5eddb9d6, 0xe73b0c91, 0x680e2104,
+ 0x222051fa, 0xad157c6f, 0xb67cb006, 0x39499d93, 0x7367ed6d,
+ 0xfc52c0f8,
+ 0x00000000, 0x50b36adc, 0xa166d5b8, 0xf1d5bf64, 0x99bcad31,
+ 0xc90fc7ed, 0x38da7889, 0x68691255, 0xe8085c23, 0xb8bb36ff,
+ 0x496e899b, 0x19dde347, 0x71b4f112, 0x21079bce, 0xd0d224aa,
+ 0x80614e76, 0x0b61be07, 0x5bd2d4db, 0xaa076bbf, 0xfab40163,
+ 0x92dd1336, 0xc26e79ea, 0x33bbc68e, 0x6308ac52, 0xe369e224,
+ 0xb3da88f8, 0x420f379c, 0x12bc5d40, 0x7ad54f15, 0x2a6625c9,
+ 0xdbb39aad, 0x8b00f071, 0x16c37c0e, 0x467016d2, 0xb7a5a9b6,
+ 0xe716c36a, 0x8f7fd13f, 0xdfccbbe3, 0x2e190487, 0x7eaa6e5b,
+ 0xfecb202d, 0xae784af1, 0x5fadf595, 0x0f1e9f49, 0x67778d1c,
+ 0x37c4e7c0, 0xc61158a4, 0x96a23278, 0x1da2c209, 0x4d11a8d5,
+ 0xbcc417b1, 0xec777d6d, 0x841e6f38, 0xd4ad05e4, 0x2578ba80,
+ 0x75cbd05c, 0xf5aa9e2a, 0xa519f4f6, 0x54cc4b92, 0x047f214e,
+ 0x6c16331b, 0x3ca559c7, 0xcd70e6a3, 0x9dc38c7f, 0x2d86f81c,
+ 0x7d3592c0, 0x8ce02da4, 0xdc534778, 0xb43a552d, 0xe4893ff1,
+ 0x155c8095, 0x45efea49, 0xc58ea43f, 0x953dcee3, 0x64e87187,
+ 0x345b1b5b, 0x5c32090e, 0x0c8163d2, 0xfd54dcb6, 0xade7b66a,
+ 0x26e7461b, 0x76542cc7, 0x878193a3, 0xd732f97f, 0xbf5beb2a,
+ 0xefe881f6, 0x1e3d3e92, 0x4e8e544e, 0xceef1a38, 0x9e5c70e4,
+ 0x6f89cf80, 0x3f3aa55c, 0x5753b709, 0x07e0ddd5, 0xf63562b1,
+ 0xa686086d, 0x3b458412, 0x6bf6eece, 0x9a2351aa, 0xca903b76,
+ 0xa2f92923, 0xf24a43ff, 0x039ffc9b, 0x532c9647, 0xd34dd831,
+ 0x83feb2ed, 0x722b0d89, 0x22986755, 0x4af17500, 0x1a421fdc,
+ 0xeb97a0b8, 0xbb24ca64, 0x30243a15, 0x609750c9, 0x9142efad,
+ 0xc1f18571, 0xa9989724, 0xf92bfdf8, 0x08fe429c, 0x584d2840,
+ 0xd82c6636, 0x889f0cea, 0x794ab38e, 0x29f9d952, 0x4190cb07,
+ 0x1123a1db, 0xe0f61ebf, 0xb0457463, 0x5b0df038, 0x0bbe9ae4,
+ 0xfa6b2580, 0xaad84f5c, 0xc2b15d09, 0x920237d5, 0x63d788b1,
+ 0x3364e26d, 0xb305ac1b, 0xe3b6c6c7, 0x126379a3, 0x42d0137f,
+ 0x2ab9012a, 0x7a0a6bf6, 0x8bdfd492, 0xdb6cbe4e, 0x506c4e3f,
+ 0x00df24e3, 0xf10a9b87, 0xa1b9f15b, 0xc9d0e30e, 0x996389d2,
+ 0x68b636b6, 0x38055c6a, 0xb864121c, 0xe8d778c0, 0x1902c7a4,
+ 0x49b1ad78, 0x21d8bf2d, 0x716bd5f1, 0x80be6a95, 0xd00d0049,
+ 0x4dce8c36, 0x1d7de6ea, 0xeca8598e, 0xbc1b3352, 0xd4722107,
+ 0x84c14bdb, 0x7514f4bf, 0x25a79e63, 0xa5c6d015, 0xf575bac9,
+ 0x04a005ad, 0x54136f71, 0x3c7a7d24, 0x6cc917f8, 0x9d1ca89c,
+ 0xcdafc240, 0x46af3231, 0x161c58ed, 0xe7c9e789, 0xb77a8d55,
+ 0xdf139f00, 0x8fa0f5dc, 0x7e754ab8, 0x2ec62064, 0xaea76e12,
+ 0xfe1404ce, 0x0fc1bbaa, 0x5f72d176, 0x371bc323, 0x67a8a9ff,
+ 0x967d169b, 0xc6ce7c47, 0x768b0824, 0x263862f8, 0xd7eddd9c,
+ 0x875eb740, 0xef37a515, 0xbf84cfc9, 0x4e5170ad, 0x1ee21a71,
+ 0x9e835407, 0xce303edb, 0x3fe581bf, 0x6f56eb63, 0x073ff936,
+ 0x578c93ea, 0xa6592c8e, 0xf6ea4652, 0x7deab623, 0x2d59dcff,
+ 0xdc8c639b, 0x8c3f0947, 0xe4561b12, 0xb4e571ce, 0x4530ceaa,
+ 0x1583a476, 0x95e2ea00, 0xc55180dc, 0x34843fb8, 0x64375564,
+ 0x0c5e4731, 0x5ced2ded, 0xad389289, 0xfd8bf855, 0x6048742a,
+ 0x30fb1ef6, 0xc12ea192, 0x919dcb4e, 0xf9f4d91b, 0xa947b3c7,
+ 0x58920ca3, 0x0821667f, 0x88402809, 0xd8f342d5, 0x2926fdb1,
+ 0x7995976d, 0x11fc8538, 0x414fefe4, 0xb09a5080, 0xe0293a5c,
+ 0x6b29ca2d, 0x3b9aa0f1, 0xca4f1f95, 0x9afc7549, 0xf295671c,
+ 0xa2260dc0, 0x53f3b2a4, 0x0340d878, 0x8321960e, 0xd392fcd2,
+ 0x224743b6, 0x72f4296a, 0x1a9d3b3f, 0x4a2e51e3, 0xbbfbee87,
+ 0xeb48845b,
+ 0x00000000, 0xb61be070, 0xb746c6a1, 0x015d26d1, 0xb5fc8b03,
+ 0x03e76b73, 0x02ba4da2, 0xb4a1add2, 0xb0881047, 0x0693f037,
+ 0x07ced6e6, 0xb1d53696, 0x05749b44, 0xb36f7b34, 0xb2325de5,
+ 0x0429bd95, 0xba6126cf, 0x0c7ac6bf, 0x0d27e06e, 0xbb3c001e,
+ 0x0f9dadcc, 0xb9864dbc, 0xb8db6b6d, 0x0ec08b1d, 0x0ae93688,
+ 0xbcf2d6f8, 0xbdaff029, 0x0bb41059, 0xbf15bd8b, 0x090e5dfb,
+ 0x08537b2a, 0xbe489b5a, 0xafb34bdf, 0x19a8abaf, 0x18f58d7e,
+ 0xaeee6d0e, 0x1a4fc0dc, 0xac5420ac, 0xad09067d, 0x1b12e60d,
+ 0x1f3b5b98, 0xa920bbe8, 0xa87d9d39, 0x1e667d49, 0xaac7d09b,
+ 0x1cdc30eb, 0x1d81163a, 0xab9af64a, 0x15d26d10, 0xa3c98d60,
+ 0xa294abb1, 0x148f4bc1, 0xa02ee613, 0x16350663, 0x176820b2,
+ 0xa173c0c2, 0xa55a7d57, 0x13419d27, 0x121cbbf6, 0xa4075b86,
+ 0x10a6f654, 0xa6bd1624, 0xa7e030f5, 0x11fbd085, 0x841791ff,
+ 0x320c718f, 0x3351575e, 0x854ab72e, 0x31eb1afc, 0x87f0fa8c,
+ 0x86addc5d, 0x30b63c2d, 0x349f81b8, 0x828461c8, 0x83d94719,
+ 0x35c2a769, 0x81630abb, 0x3778eacb, 0x3625cc1a, 0x803e2c6a,
+ 0x3e76b730, 0x886d5740, 0x89307191, 0x3f2b91e1, 0x8b8a3c33,
+ 0x3d91dc43, 0x3cccfa92, 0x8ad71ae2, 0x8efea777, 0x38e54707,
+ 0x39b861d6, 0x8fa381a6, 0x3b022c74, 0x8d19cc04, 0x8c44ead5,
+ 0x3a5f0aa5, 0x2ba4da20, 0x9dbf3a50, 0x9ce21c81, 0x2af9fcf1,
+ 0x9e585123, 0x2843b153, 0x291e9782, 0x9f0577f2, 0x9b2cca67,
+ 0x2d372a17, 0x2c6a0cc6, 0x9a71ecb6, 0x2ed04164, 0x98cba114,
+ 0x999687c5, 0x2f8d67b5, 0x91c5fcef, 0x27de1c9f, 0x26833a4e,
+ 0x9098da3e, 0x243977ec, 0x9222979c, 0x937fb14d, 0x2564513d,
+ 0x214deca8, 0x97560cd8, 0x960b2a09, 0x2010ca79, 0x94b167ab,
+ 0x22aa87db, 0x23f7a10a, 0x95ec417a, 0xd35e25bf, 0x6545c5cf,
+ 0x6418e31e, 0xd203036e, 0x66a2aebc, 0xd0b94ecc, 0xd1e4681d,
+ 0x67ff886d, 0x63d635f8, 0xd5cdd588, 0xd490f359, 0x628b1329,
+ 0xd62abefb, 0x60315e8b, 0x616c785a, 0xd777982a, 0x693f0370,
+ 0xdf24e300, 0xde79c5d1, 0x686225a1, 0xdcc38873, 0x6ad86803,
+ 0x6b854ed2, 0xdd9eaea2, 0xd9b71337, 0x6facf347, 0x6ef1d596,
+ 0xd8ea35e6, 0x6c4b9834, 0xda507844, 0xdb0d5e95, 0x6d16bee5,
+ 0x7ced6e60, 0xcaf68e10, 0xcbaba8c1, 0x7db048b1, 0xc911e563,
+ 0x7f0a0513, 0x7e5723c2, 0xc84cc3b2, 0xcc657e27, 0x7a7e9e57,
+ 0x7b23b886, 0xcd3858f6, 0x7999f524, 0xcf821554, 0xcedf3385,
+ 0x78c4d3f5, 0xc68c48af, 0x7097a8df, 0x71ca8e0e, 0xc7d16e7e,
+ 0x7370c3ac, 0xc56b23dc, 0xc436050d, 0x722de57d, 0x760458e8,
+ 0xc01fb898, 0xc1429e49, 0x77597e39, 0xc3f8d3eb, 0x75e3339b,
+ 0x74be154a, 0xc2a5f53a, 0x5749b440, 0xe1525430, 0xe00f72e1,
+ 0x56149291, 0xe2b53f43, 0x54aedf33, 0x55f3f9e2, 0xe3e81992,
+ 0xe7c1a407, 0x51da4477, 0x508762a6, 0xe69c82d6, 0x523d2f04,
+ 0xe426cf74, 0xe57be9a5, 0x536009d5, 0xed28928f, 0x5b3372ff,
+ 0x5a6e542e, 0xec75b45e, 0x58d4198c, 0xeecff9fc, 0xef92df2d,
+ 0x59893f5d, 0x5da082c8, 0xebbb62b8, 0xeae64469, 0x5cfda419,
+ 0xe85c09cb, 0x5e47e9bb, 0x5f1acf6a, 0xe9012f1a, 0xf8faff9f,
+ 0x4ee11fef, 0x4fbc393e, 0xf9a7d94e, 0x4d06749c, 0xfb1d94ec,
+ 0xfa40b23d, 0x4c5b524d, 0x4872efd8, 0xfe690fa8, 0xff342979,
+ 0x492fc909, 0xfd8e64db, 0x4b9584ab, 0x4ac8a27a, 0xfcd3420a,
+ 0x429bd950, 0xf4803920, 0xf5dd1ff1, 0x43c6ff81, 0xf7675253,
+ 0x417cb223, 0x402194f2, 0xf63a7482, 0xf213c917, 0x44082967,
+ 0x45550fb6, 0xf34eefc6, 0x47ef4214, 0xf1f4a264, 0xf0a984b5,
+ 0x46b264c5,
+ 0x00000000, 0x7dcd4d3f, 0xfb9a9a7e, 0x8657d741, 0x2c4432bd,
+ 0x51897f82, 0xd7dea8c3, 0xaa13e5fc, 0x5888657a, 0x25452845,
+ 0xa312ff04, 0xdedfb23b, 0x74cc57c7, 0x09011af8, 0x8f56cdb9,
+ 0xf29b8086, 0xb110caf4, 0xccdd87cb, 0x4a8a508a, 0x37471db5,
+ 0x9d54f849, 0xe099b576, 0x66ce6237, 0x1b032f08, 0xe998af8e,
+ 0x9455e2b1, 0x120235f0, 0x6fcf78cf, 0xc5dc9d33, 0xb811d00c,
+ 0x3e46074d, 0x438b4a72, 0xb95093a9, 0xc49dde96, 0x42ca09d7,
+ 0x3f0744e8, 0x9514a114, 0xe8d9ec2b, 0x6e8e3b6a, 0x13437655,
+ 0xe1d8f6d3, 0x9c15bbec, 0x1a426cad, 0x678f2192, 0xcd9cc46e,
+ 0xb0518951, 0x36065e10, 0x4bcb132f, 0x0840595d, 0x758d1462,
+ 0xf3dac323, 0x8e178e1c, 0x24046be0, 0x59c926df, 0xdf9ef19e,
+ 0xa253bca1, 0x50c83c27, 0x2d057118, 0xab52a659, 0xd69feb66,
+ 0x7c8c0e9a, 0x014143a5, 0x871694e4, 0xfadbd9db, 0xa9d02113,
+ 0xd41d6c2c, 0x524abb6d, 0x2f87f652, 0x859413ae, 0xf8595e91,
+ 0x7e0e89d0, 0x03c3c4ef, 0xf1584469, 0x8c950956, 0x0ac2de17,
+ 0x770f9328, 0xdd1c76d4, 0xa0d13beb, 0x2686ecaa, 0x5b4ba195,
+ 0x18c0ebe7, 0x650da6d8, 0xe35a7199, 0x9e973ca6, 0x3484d95a,
+ 0x49499465, 0xcf1e4324, 0xb2d30e1b, 0x40488e9d, 0x3d85c3a2,
+ 0xbbd214e3, 0xc61f59dc, 0x6c0cbc20, 0x11c1f11f, 0x9796265e,
+ 0xea5b6b61, 0x1080b2ba, 0x6d4dff85, 0xeb1a28c4, 0x96d765fb,
+ 0x3cc48007, 0x4109cd38, 0xc75e1a79, 0xba935746, 0x4808d7c0,
+ 0x35c59aff, 0xb3924dbe, 0xce5f0081, 0x644ce57d, 0x1981a842,
+ 0x9fd67f03, 0xe21b323c, 0xa190784e, 0xdc5d3571, 0x5a0ae230,
+ 0x27c7af0f, 0x8dd44af3, 0xf01907cc, 0x764ed08d, 0x0b839db2,
+ 0xf9181d34, 0x84d5500b, 0x0282874a, 0x7f4fca75, 0xd55c2f89,
+ 0xa89162b6, 0x2ec6b5f7, 0x530bf8c8, 0x88d14467, 0xf51c0958,
+ 0x734bde19, 0x0e869326, 0xa49576da, 0xd9583be5, 0x5f0feca4,
+ 0x22c2a19b, 0xd059211d, 0xad946c22, 0x2bc3bb63, 0x560ef65c,
+ 0xfc1d13a0, 0x81d05e9f, 0x078789de, 0x7a4ac4e1, 0x39c18e93,
+ 0x440cc3ac, 0xc25b14ed, 0xbf9659d2, 0x1585bc2e, 0x6848f111,
+ 0xee1f2650, 0x93d26b6f, 0x6149ebe9, 0x1c84a6d6, 0x9ad37197,
+ 0xe71e3ca8, 0x4d0dd954, 0x30c0946b, 0xb697432a, 0xcb5a0e15,
+ 0x3181d7ce, 0x4c4c9af1, 0xca1b4db0, 0xb7d6008f, 0x1dc5e573,
+ 0x6008a84c, 0xe65f7f0d, 0x9b923232, 0x6909b2b4, 0x14c4ff8b,
+ 0x929328ca, 0xef5e65f5, 0x454d8009, 0x3880cd36, 0xbed71a77,
+ 0xc31a5748, 0x80911d3a, 0xfd5c5005, 0x7b0b8744, 0x06c6ca7b,
+ 0xacd52f87, 0xd11862b8, 0x574fb5f9, 0x2a82f8c6, 0xd8197840,
+ 0xa5d4357f, 0x2383e23e, 0x5e4eaf01, 0xf45d4afd, 0x899007c2,
+ 0x0fc7d083, 0x720a9dbc, 0x21016574, 0x5ccc284b, 0xda9bff0a,
+ 0xa756b235, 0x0d4557c9, 0x70881af6, 0xf6dfcdb7, 0x8b128088,
+ 0x7989000e, 0x04444d31, 0x82139a70, 0xffded74f, 0x55cd32b3,
+ 0x28007f8c, 0xae57a8cd, 0xd39ae5f2, 0x9011af80, 0xeddce2bf,
+ 0x6b8b35fe, 0x164678c1, 0xbc559d3d, 0xc198d002, 0x47cf0743,
+ 0x3a024a7c, 0xc899cafa, 0xb55487c5, 0x33035084, 0x4ece1dbb,
+ 0xe4ddf847, 0x9910b578, 0x1f476239, 0x628a2f06, 0x9851f6dd,
+ 0xe59cbbe2, 0x63cb6ca3, 0x1e06219c, 0xb415c460, 0xc9d8895f,
+ 0x4f8f5e1e, 0x32421321, 0xc0d993a7, 0xbd14de98, 0x3b4309d9,
+ 0x468e44e6, 0xec9da11a, 0x9150ec25, 0x17073b64, 0x6aca765b,
+ 0x29413c29, 0x548c7116, 0xd2dba657, 0xaf16eb68, 0x05050e94,
+ 0x78c843ab, 0xfe9f94ea, 0x8352d9d5, 0x71c95953, 0x0c04146c,
+ 0x8a53c32d, 0xf79e8e12, 0x5d8d6bee, 0x204026d1, 0xa617f190,
+ 0xdbdabcaf
};
diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp
index 769e4dc5ccc..0281c66b97d 100644
--- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp
+++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -27,6 +27,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "classfile/javaClasses.hpp"
+#include "compiler/disassembler.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/bytecodeTracer.hpp"
@@ -70,7 +71,7 @@
// Max size with JVMTI
int TemplateInterpreter::InterpreterCodeSize = 256 * 1024;
-#define __ _masm->
+#define __ Disassembler::hook(__FILE__, __LINE__, _masm)->
//-----------------------------------------------------------------------------
@@ -165,7 +166,6 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
address fn = nullptr;
address entry_point = nullptr;
- Register continuation = ra;
switch (kind) {
case Interpreter::java_lang_math_abs:
entry_point = __ pc();
@@ -184,83 +184,82 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
__ fld(f10, Address(esp));
__ mv(sp, x19_sender_sp);
__ mv(x9, ra);
- continuation = x9; // The first callee-saved register
if (StubRoutines::dsin() == nullptr) {
fn = CAST_FROM_FN_PTR(address, SharedRuntime::dsin);
} else {
fn = CAST_FROM_FN_PTR(address, StubRoutines::dsin());
}
__ call(fn);
+ __ mv(ra, x9);
break;
case Interpreter::java_lang_math_cos :
entry_point = __ pc();
__ fld(f10, Address(esp));
__ mv(sp, x19_sender_sp);
__ mv(x9, ra);
- continuation = x9; // The first callee-saved register
if (StubRoutines::dcos() == nullptr) {
fn = CAST_FROM_FN_PTR(address, SharedRuntime::dcos);
} else {
fn = CAST_FROM_FN_PTR(address, StubRoutines::dcos());
}
__ call(fn);
+ __ mv(ra, x9);
break;
case Interpreter::java_lang_math_tan :
entry_point = __ pc();
__ fld(f10, Address(esp));
__ mv(sp, x19_sender_sp);
__ mv(x9, ra);
- continuation = x9; // The first callee-saved register
if (StubRoutines::dtan() == nullptr) {
fn = CAST_FROM_FN_PTR(address, SharedRuntime::dtan);
} else {
fn = CAST_FROM_FN_PTR(address, StubRoutines::dtan());
}
__ call(fn);
+ __ mv(ra, x9);
break;
case Interpreter::java_lang_math_log :
entry_point = __ pc();
__ fld(f10, Address(esp));
__ mv(sp, x19_sender_sp);
__ mv(x9, ra);
- continuation = x9; // The first callee-saved register
if (StubRoutines::dlog() == nullptr) {
fn = CAST_FROM_FN_PTR(address, SharedRuntime::dlog);
} else {
fn = CAST_FROM_FN_PTR(address, StubRoutines::dlog());
}
__ call(fn);
+ __ mv(ra, x9);
break;
case Interpreter::java_lang_math_log10 :
entry_point = __ pc();
__ fld(f10, Address(esp));
__ mv(sp, x19_sender_sp);
__ mv(x9, ra);
- continuation = x9; // The first callee-saved register
if (StubRoutines::dlog10() == nullptr) {
fn = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10);
} else {
fn = CAST_FROM_FN_PTR(address, StubRoutines::dlog10());
}
__ call(fn);
+ __ mv(ra, x9);
break;
case Interpreter::java_lang_math_exp :
entry_point = __ pc();
__ fld(f10, Address(esp));
__ mv(sp, x19_sender_sp);
__ mv(x9, ra);
- continuation = x9; // The first callee-saved register
if (StubRoutines::dexp() == nullptr) {
fn = CAST_FROM_FN_PTR(address, SharedRuntime::dexp);
} else {
fn = CAST_FROM_FN_PTR(address, StubRoutines::dexp());
}
__ call(fn);
+ __ mv(ra, x9);
break;
case Interpreter::java_lang_math_pow :
entry_point = __ pc();
__ mv(x9, ra);
- continuation = x9;
__ fld(f10, Address(esp, 2 * Interpreter::stackElementSize));
__ fld(f11, Address(esp));
__ mv(sp, x19_sender_sp);
@@ -270,6 +269,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
fn = CAST_FROM_FN_PTR(address, StubRoutines::dpow());
}
__ call(fn);
+ __ mv(ra, x9);
break;
case Interpreter::java_lang_math_fmaD :
if (UseFMA) {
@@ -295,7 +295,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
;
}
if (entry_point != nullptr) {
- __ jr(continuation);
+ __ ret();
}
return entry_point;
@@ -421,7 +421,7 @@ address TemplateInterpreterGenerator::generate_exception_handler_common(
c_rarg1, c_rarg2);
}
// throw exception
- __ j(address(Interpreter::throw_exception_entry()));
+ __ j(RuntimeAddress(Interpreter::throw_exception_entry()));
return entry;
}
@@ -658,8 +658,8 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) {
// Note: the restored frame is not necessarily interpreted.
// Use the shared runtime version of the StackOverflowError.
- assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "stub not yet generated");
- __ far_jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry()));
+ assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "stub not yet generated");
+ __ far_jump(RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry()));
// all done with frame size check
__ bind(after_frame_check);
@@ -1111,8 +1111,8 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
{
Label L;
__ ld(x28, Address(xmethod, Method::native_function_offset()));
- address unsatisfied = (SharedRuntime::native_method_throw_unsatisfied_link_error_entry());
- __ mv(t, unsatisfied);
+ ExternalAddress unsatisfied(SharedRuntime::native_method_throw_unsatisfied_link_error_entry());
+ __ la(t, unsatisfied);
__ load_long_misaligned(t1, Address(t, 0), t0, 2); // 2 bytes aligned, but not 4 or 8
__ bne(x28, t1, L);
@@ -1748,13 +1748,21 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t,
address& vep) {
assert(t != nullptr && t->is_valid() && t->tos_in() == vtos, "illegal template");
Label L;
- aep = __ pc(); __ push_ptr(); __ j(L);
- fep = __ pc(); __ push_f(); __ j(L);
- dep = __ pc(); __ push_d(); __ j(L);
- lep = __ pc(); __ push_l(); __ j(L);
- bep = cep = sep =
- iep = __ pc(); __ push_i();
- vep = __ pc();
+ aep = __ pc(); // atos entry point
+ __ push_ptr();
+ __ j(L);
+ fep = __ pc(); // ftos entry point
+ __ push_f();
+ __ j(L);
+ dep = __ pc(); // dtos entry point
+ __ push_d();
+ __ j(L);
+ lep = __ pc(); // ltos entry point
+ __ push_l();
+ __ j(L);
+ bep = cep = sep = iep = __ pc(); // [bcsi]tos entry point
+ __ push_i();
+ vep = __ pc(); // vtos entry point
__ bind(L);
generate_and_dispatch(t);
}
@@ -1815,7 +1823,7 @@ void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
// the tosca in-state for the given template.
assert(Interpreter::trace_code(t->tos_in()) != nullptr, "entry must have been generated");
- __ call(Interpreter::trace_code(t->tos_in()));
+ __ rt_call(Interpreter::trace_code(t->tos_in()));
__ reinit_heapbase();
}
diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp
index fa542343949..0c20f0e3f92 100644
--- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp
+++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -26,6 +26,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
+#include "compiler/disassembler.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/tlab_globals.hpp"
@@ -49,7 +50,7 @@
#include "runtime/synchronizer.hpp"
#include "utilities/powerOfTwo.hpp"
-#define __ _masm->
+#define __ Disassembler::hook(__FILE__, __LINE__, _masm)->
// Address computation: local variables
@@ -178,7 +179,6 @@ void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg,
__ la(temp_reg, Address(temp_reg, in_bytes(ResolvedFieldEntry::put_code_offset())));
}
// Load-acquire the bytecode to match store-release in ResolvedFieldEntry::fill_in()
- __ membar(MacroAssembler::AnyAny);
__ lbu(temp_reg, Address(temp_reg, 0));
__ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
__ mv(bc_reg, bc);
@@ -320,7 +320,6 @@ void TemplateTable::ldc(LdcType type) {
// get type
__ addi(x13, x11, tags_offset);
__ add(x13, x10, x13);
- __ membar(MacroAssembler::AnyAny);
__ lbu(x13, Address(x13, 0));
__ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
@@ -706,7 +705,7 @@ void TemplateTable::wide_aload() {
}
void TemplateTable::index_check(Register array, Register index) {
- // destroys x11, t0
+ // destroys x11, t0, t1
// sign extend index for use by indexed load
// check index
const Register length = t0;
@@ -719,8 +718,8 @@ void TemplateTable::index_check(Register array, Register index) {
__ sign_extend(index, index, 32);
__ bltu(index, length, ok);
__ mv(x13, array);
- __ mv(t0, Interpreter::_throw_ArrayIndexOutOfBoundsException_entry);
- __ jr(t0);
+ __ mv(t1, Interpreter::_throw_ArrayIndexOutOfBoundsException_entry);
+ __ jr(t1);
__ bind(ok);
}
@@ -1086,7 +1085,7 @@ void TemplateTable::aastore() {
// Come here on failure
// object is at TOS
- __ j(Interpreter::_throw_ArrayStoreException_entry);
+ __ j(RuntimeAddress(Interpreter::_throw_ArrayStoreException_entry));
// Come here on success
__ bind(ok_is_subtype);
@@ -1314,8 +1313,8 @@ void TemplateTable::idiv() {
// explicitly check for div0
Label no_div0;
__ bnez(x10, no_div0);
- __ mv(t0, Interpreter::_throw_ArithmeticException_entry);
- __ jr(t0);
+ __ mv(t1, Interpreter::_throw_ArithmeticException_entry);
+ __ jr(t1);
__ bind(no_div0);
__ pop_i(x11);
// x10 <== x11 idiv x10
@@ -1327,8 +1326,8 @@ void TemplateTable::irem() {
// explicitly check for div0
Label no_div0;
__ bnez(x10, no_div0);
- __ mv(t0, Interpreter::_throw_ArithmeticException_entry);
- __ jr(t0);
+ __ mv(t1, Interpreter::_throw_ArithmeticException_entry);
+ __ jr(t1);
__ bind(no_div0);
__ pop_i(x11);
// x10 <== x11 irem x10
@@ -1346,8 +1345,8 @@ void TemplateTable::ldiv() {
// explicitly check for div0
Label no_div0;
__ bnez(x10, no_div0);
- __ mv(t0, Interpreter::_throw_ArithmeticException_entry);
- __ jr(t0);
+ __ mv(t1, Interpreter::_throw_ArithmeticException_entry);
+ __ jr(t1);
__ bind(no_div0);
__ pop_l(x11);
// x10 <== x11 ldiv x10
@@ -1359,8 +1358,8 @@ void TemplateTable::lrem() {
// explicitly check for div0
Label no_div0;
__ bnez(x10, no_div0);
- __ mv(t0, Interpreter::_throw_ArithmeticException_entry);
- __ jr(t0);
+ __ mv(t1, Interpreter::_throw_ArithmeticException_entry);
+ __ jr(t1);
__ bind(no_div0);
__ pop_l(x11);
// x10 <== x11 lrem x10
@@ -1769,8 +1768,8 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) {
__ andi(sp, esp, -16);
// and begin the OSR nmethod
- __ ld(t0, Address(x9, nmethod::osr_entry_point_offset()));
- __ jr(t0);
+ __ ld(t1, Address(x9, nmethod::osr_entry_point_offset()));
+ __ jr(t1);
}
}
@@ -2098,9 +2097,9 @@ void TemplateTable::_return(TosState state) {
__ ld(c_rarg1, aaddress(0));
__ load_klass(x13, c_rarg1);
- __ lwu(x13, Address(x13, Klass::access_flags_offset()));
+ __ lbu(x13, Address(x13, Klass::misc_flags_offset()));
Label skip_register_finalizer;
- __ test_bit(t0, x13, exact_log2(JVM_ACC_HAS_FINALIZER));
+ __ test_bit(t0, x13, exact_log2(KlassFlags::_misc_has_finalizer));
__ beqz(t0, skip_register_finalizer);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), c_rarg1);
@@ -2172,7 +2171,7 @@ void TemplateTable::_return(TosState state) {
void TemplateTable::resolve_cache_and_index_for_method(int byte_no,
Register Rcache,
Register index) {
- const Register temp = x9;
+ const Register temp = x9; // s1
assert_different_registers(Rcache, index, temp);
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
@@ -2189,7 +2188,6 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no,
break;
}
// Load-acquire the bytecode to match store-release in InterpreterRuntime
- __ membar(MacroAssembler::AnyAny);
__ lbu(temp, Address(temp, 0));
__ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
@@ -2241,7 +2239,6 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no,
__ la(temp, Address(Rcache, in_bytes(ResolvedFieldEntry::put_code_offset())));
}
// Load-acquire the bytecode to match store-release in ResolvedFieldEntry::fill_in()
- __ membar(MacroAssembler::AnyAny);
__ lbu(temp, Address(temp, 0));
__ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
__ mv(t0, (int) code); // have we resolved this bytecode?
@@ -2403,7 +2400,6 @@ void TemplateTable::load_invokedynamic_entry(Register method) {
Label resolved;
__ load_resolved_indy_entry(cache, index);
- __ membar(MacroAssembler::AnyAny);
__ ld(method, Address(cache, in_bytes(ResolvedIndyEntry::method_offset())));
__ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
@@ -2418,7 +2414,6 @@ void TemplateTable::load_invokedynamic_entry(Register method) {
__ call_VM(noreg, entry, method);
// Update registers with resolved info
__ load_resolved_indy_entry(cache, index);
- __ membar(MacroAssembler::AnyAny);
__ ld(method, Address(cache, in_bytes(ResolvedIndyEntry::method_offset())));
__ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
@@ -3533,7 +3528,6 @@ void TemplateTable::_new() {
const int tags_offset = Array::base_offset_in_bytes();
__ add(t0, x10, x13);
__ la(t0, Address(t0, tags_offset));
- __ membar(MacroAssembler::AnyAny);
__ lbu(t0, t0);
__ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
__ sub(t1, t0, (u1)JVM_CONSTANT_Class);
@@ -3651,7 +3645,6 @@ void TemplateTable::checkcast() {
// See if bytecode has already been quicked
__ add(t0, x13, Array::base_offset_in_bytes());
__ add(x11, t0, x9);
- __ membar(MacroAssembler::AnyAny);
__ lbu(x11, x11);
__ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
__ sub(t0, x11, (u1)JVM_CONSTANT_Class);
@@ -3679,7 +3672,7 @@ void TemplateTable::checkcast() {
// Come here on failure
__ push_reg(x13);
// object is at TOS
- __ j(Interpreter::_throw_ClassCastException_entry);
+ __ j(RuntimeAddress(Interpreter::_throw_ClassCastException_entry));
// Come here on success
__ bind(ok_is_subtype);
@@ -3707,7 +3700,6 @@ void TemplateTable::instanceof() {
// See if bytecode has already been quicked
__ add(t0, x13, Array::base_offset_in_bytes());
__ add(x11, t0, x9);
- __ membar(MacroAssembler::AnyAny);
__ lbu(x11, x11);
__ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore);
__ sub(t0, x11, (u1)JVM_CONSTANT_Class);
@@ -3787,7 +3779,7 @@ void TemplateTable::_breakpoint() {
void TemplateTable::athrow() {
transition(atos, vtos);
__ null_check(x10);
- __ j(Interpreter::throw_exception_entry());
+ __ j(RuntimeAddress(Interpreter::throw_exception_entry()));
}
//-----------------------------------------------------------------------------
@@ -3970,8 +3962,8 @@ void TemplateTable::wide() {
__ load_unsigned_byte(x9, at_bcp(1));
__ mv(t0, (address)Interpreter::_wentry_point);
__ shadd(t0, x9, t0, t1, 3);
- __ ld(t0, Address(t0));
- __ jr(t0);
+ __ ld(t1, Address(t0));
+ __ jr(t1);
}
// Multi arrays
diff --git a/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp b/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp
index 383f332f8fd..3b4f26b6dc3 100644
--- a/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp
+++ b/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
+#include "classfile/javaClasses.hpp"
#include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
#include "prims/upcallLinker.hpp"
@@ -117,7 +118,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr
static const int upcall_stub_code_base_size = 1024;
static const int upcall_stub_size_per_arg = 16;
-address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
+address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
@@ -223,7 +224,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
__ block_comment("{ on_entry");
__ la(c_rarg0, Address(sp, frame_data_offset));
- __ movptr(c_rarg1, (address) receiver);
__ rt_call(CAST_FROM_FN_PTR(address, UpcallLinker::on_entry));
__ mv(xthread, x10);
__ reinit_heapbase();
@@ -260,17 +260,15 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
arg_shuffle.generate(_masm, as_VMStorage(shuffle_reg), abi._shadow_space_bytes, 0);
__ block_comment("} argument shuffle");
- __ block_comment("{ receiver ");
- __ get_vm_result(j_rarg0, xthread);
- __ block_comment("} receiver ");
-
- __ mov_metadata(xmethod, entry);
- __ sd(xmethod, Address(xthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized
+ __ block_comment("{ load target ");
+ __ movptr(j_rarg0, (address) receiver);
+ __ far_call(RuntimeAddress(StubRoutines::upcall_stub_load_target())); // loads Method* into xmethod
+ __ block_comment("} load target ");
__ push_cont_fastpath(xthread);
- __ ld(t0, Address(xmethod, Method::from_compiled_offset()));
- __ jalr(t0);
+ __ ld(t1, Address(xmethod, Method::from_compiled_offset()));
+ __ jalr(t1);
__ pop_cont_fastpath(xthread);
@@ -338,7 +336,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
#ifndef PRODUCT
stringStream ss;
- ss.print("upcall_stub_%s", entry->signature()->as_C_string());
+ ss.print("upcall_stub_%s", signature->as_C_string());
const char *name = _masm->code_string(ss.as_string());
#else // PRODUCT
const char* name = "upcall_stub";
diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp
index c52c809f935..e9c6226f446 100644
--- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp
+++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp
@@ -58,6 +58,13 @@ void VM_Version::useRVA23U64Profile() {
}
void VM_Version::initialize() {
+ common_initialize();
+#ifdef COMPILER2
+ c2_initialize();
+#endif // COMPILER2
+}
+
+void VM_Version::common_initialize() {
_supports_atomic_getset4 = true;
_supports_atomic_getadd4 = true;
_supports_atomic_getset8 = true;
@@ -152,10 +159,6 @@ void VM_Version::initialize() {
FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false);
}
- if (FLAG_IS_DEFAULT(UseMD5Intrinsics)) {
- FLAG_SET_DEFAULT(UseMD5Intrinsics, true);
- }
-
if (FLAG_IS_DEFAULT(UsePoly1305Intrinsics)) {
FLAG_SET_DEFAULT(UsePoly1305Intrinsics, true);
}
@@ -230,15 +233,110 @@ void VM_Version::initialize() {
_initial_vector_length = cpu_vector_length();
}
}
+}
#ifdef COMPILER2
- c2_initialize();
-#endif // COMPILER2
+void VM_Version::c2_initialize() {
+ if (UseCMoveUnconditionally) {
+ FLAG_SET_DEFAULT(UseCMoveUnconditionally, false);
+ }
+
+ if (ConditionalMoveLimit > 0) {
+ FLAG_SET_DEFAULT(ConditionalMoveLimit, 0);
+ }
- // NOTE: Make sure codes dependent on UseRVV are put after c2_initialize(),
+ if (!UseRVV) {
+ FLAG_SET_DEFAULT(MaxVectorSize, 0);
+ FLAG_SET_DEFAULT(UseRVVForBigIntegerShiftIntrinsics, false);
+ } else {
+ if (!FLAG_IS_DEFAULT(MaxVectorSize) && MaxVectorSize != _initial_vector_length) {
+ warning("Current system does not support RVV vector length for MaxVectorSize %d. Set MaxVectorSize to %d",
+ (int)MaxVectorSize, _initial_vector_length);
+ }
+ MaxVectorSize = _initial_vector_length;
+ if (MaxVectorSize < 16) {
+ warning("RVV does not support vector length less than 16 bytes. Disabling RVV.");
+ UseRVV = false;
+ FLAG_SET_DEFAULT(MaxVectorSize, 0);
+ }
+ }
+
+ // NOTE: Make sure codes dependent on UseRVV are put after MaxVectorSize initialize,
// as there are extra checks inside it which could disable UseRVV
// in some situations.
+ // Base64
+ if (FLAG_IS_DEFAULT(UseBASE64Intrinsics)) {
+ FLAG_SET_DEFAULT(UseBASE64Intrinsics, true);
+ }
+
+ if (FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) {
+ FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, true);
+ }
+
+ if (!UseZicbop) {
+ if (!FLAG_IS_DEFAULT(AllocatePrefetchStyle)) {
+ warning("Zicbop is not available on this CPU");
+ }
+ FLAG_SET_DEFAULT(AllocatePrefetchStyle, 0);
+ } else {
+ // Limit AllocatePrefetchDistance so that it does not exceed the
+ // static constraint of 512 defined in runtime/globals.hpp.
+ if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) {
+ FLAG_SET_DEFAULT(AllocatePrefetchDistance, MIN2(512, 3 * (int)CacheLineSize));
+ }
+ if (FLAG_IS_DEFAULT(AllocatePrefetchStepSize)) {
+ FLAG_SET_DEFAULT(AllocatePrefetchStepSize, (int)CacheLineSize);
+ }
+ if (FLAG_IS_DEFAULT(PrefetchScanIntervalInBytes)) {
+ FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 3 * (int)CacheLineSize);
+ }
+ if (FLAG_IS_DEFAULT(PrefetchCopyIntervalInBytes)) {
+ FLAG_SET_DEFAULT(PrefetchCopyIntervalInBytes, 3 * (int)CacheLineSize);
+ }
+
+ if (PrefetchCopyIntervalInBytes != -1 &&
+ ((PrefetchCopyIntervalInBytes & 7) || (PrefetchCopyIntervalInBytes >= 32768))) {
+ warning("PrefetchCopyIntervalInBytes must be -1, or a multiple of 8 and < 32768");
+ PrefetchCopyIntervalInBytes &= ~7;
+ if (PrefetchCopyIntervalInBytes >= 32768) {
+ PrefetchCopyIntervalInBytes = 32760;
+ }
+ }
+ if (AllocatePrefetchDistance !=-1 && (AllocatePrefetchDistance & 7)) {
+ warning("AllocatePrefetchDistance must be multiple of 8");
+ AllocatePrefetchDistance &= ~7;
+ }
+ if (AllocatePrefetchStepSize & 7) {
+ warning("AllocatePrefetchStepSize must be multiple of 8");
+ AllocatePrefetchStepSize &= ~7;
+ }
+ }
+
+ if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) {
+ FLAG_SET_DEFAULT(UseMulAddIntrinsic, true);
+ }
+
+ if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
+ FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true);
+ }
+
+ if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) {
+ FLAG_SET_DEFAULT(UseSquareToLenIntrinsic, true);
+ }
+
+ if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) {
+ FLAG_SET_DEFAULT(UseMontgomeryMultiplyIntrinsic, true);
+ }
+
+ if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) {
+ FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, true);
+ }
+
+ if (FLAG_IS_DEFAULT(UseMD5Intrinsics)) {
+ FLAG_SET_DEFAULT(UseMD5Intrinsics, true);
+ }
+
// Adler32
if (UseRVV) {
if (FLAG_IS_DEFAULT(UseAdler32Intrinsics)) {
@@ -252,7 +350,9 @@ void VM_Version::initialize() {
}
// ChaCha20
- if (UseRVV) {
+ if (UseRVV && MaxVectorSize >= 32) {
+ // performance tests on hardwares (MaxVectorSize == 16, 32) show that
+ // it brings regression when MaxVectorSize == 16.
if (FLAG_IS_DEFAULT(UseChaCha20Intrinsics)) {
FLAG_SET_DEFAULT(UseChaCha20Intrinsics, true);
}
@@ -330,96 +430,6 @@ void VM_Version::initialize() {
FLAG_SET_DEFAULT(UseSHA, false);
}
}
-
-#ifdef COMPILER2
-void VM_Version::c2_initialize() {
- if (UseCMoveUnconditionally) {
- FLAG_SET_DEFAULT(UseCMoveUnconditionally, false);
- }
-
- if (ConditionalMoveLimit > 0) {
- FLAG_SET_DEFAULT(ConditionalMoveLimit, 0);
- }
-
- if (!UseRVV) {
- FLAG_SET_DEFAULT(MaxVectorSize, 0);
- FLAG_SET_DEFAULT(UseRVVForBigIntegerShiftIntrinsics, false);
- } else {
- if (!FLAG_IS_DEFAULT(MaxVectorSize) && MaxVectorSize != _initial_vector_length) {
- warning("Current system does not support RVV vector length for MaxVectorSize %d. Set MaxVectorSize to %d",
- (int)MaxVectorSize, _initial_vector_length);
- }
- MaxVectorSize = _initial_vector_length;
- if (MaxVectorSize < 16) {
- warning("RVV does not support vector length less than 16 bytes. Disabling RVV.");
- UseRVV = false;
- FLAG_SET_DEFAULT(MaxVectorSize, 0);
- }
- }
-
- if (FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) {
- FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, true);
- }
-
- if (!UseZicbop) {
- if (!FLAG_IS_DEFAULT(AllocatePrefetchStyle)) {
- warning("Zicbop is not available on this CPU");
- }
- FLAG_SET_DEFAULT(AllocatePrefetchStyle, 0);
- } else {
- // Limit AllocatePrefetchDistance so that it does not exceed the
- // static constraint of 512 defined in runtime/globals.hpp.
- if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) {
- FLAG_SET_DEFAULT(AllocatePrefetchDistance, MIN2(512, 3 * (int)CacheLineSize));
- }
- if (FLAG_IS_DEFAULT(AllocatePrefetchStepSize)) {
- FLAG_SET_DEFAULT(AllocatePrefetchStepSize, (int)CacheLineSize);
- }
- if (FLAG_IS_DEFAULT(PrefetchScanIntervalInBytes)) {
- FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 3 * (int)CacheLineSize);
- }
- if (FLAG_IS_DEFAULT(PrefetchCopyIntervalInBytes)) {
- FLAG_SET_DEFAULT(PrefetchCopyIntervalInBytes, 3 * (int)CacheLineSize);
- }
-
- if (PrefetchCopyIntervalInBytes != -1 &&
- ((PrefetchCopyIntervalInBytes & 7) || (PrefetchCopyIntervalInBytes >= 32768))) {
- warning("PrefetchCopyIntervalInBytes must be -1, or a multiple of 8 and < 32768");
- PrefetchCopyIntervalInBytes &= ~7;
- if (PrefetchCopyIntervalInBytes >= 32768) {
- PrefetchCopyIntervalInBytes = 32760;
- }
- }
- if (AllocatePrefetchDistance !=-1 && (AllocatePrefetchDistance & 7)) {
- warning("AllocatePrefetchDistance must be multiple of 8");
- AllocatePrefetchDistance &= ~7;
- }
- if (AllocatePrefetchStepSize & 7) {
- warning("AllocatePrefetchStepSize must be multiple of 8");
- AllocatePrefetchStepSize &= ~7;
- }
- }
-
- if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) {
- FLAG_SET_DEFAULT(UseMulAddIntrinsic, true);
- }
-
- if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
- FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true);
- }
-
- if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) {
- FLAG_SET_DEFAULT(UseSquareToLenIntrinsic, true);
- }
-
- if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) {
- FLAG_SET_DEFAULT(UseMontgomeryMultiplyIntrinsic, true);
- }
-
- if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) {
- FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, true);
- }
-}
#endif // COMPILER2
void VM_Version::initialize_cpu_information(void) {
diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp
index 9556e2dc9ad..8fdde0094f4 100644
--- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp
+++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp
@@ -264,6 +264,8 @@ class VM_Version : public Abstract_VM_Version {
static uint32_t cpu_vector_length();
static uint32_t _initial_vector_length;
+ static void common_initialize();
+
#ifdef COMPILER2
static void c2_initialize();
#endif // COMPILER2
@@ -283,6 +285,7 @@ class VM_Version : public Abstract_VM_Version {
// RISCV64 supports fast class initialization checks
static bool supports_fast_class_init_checks() { return true; }
+ static bool supports_fencei_barrier() { return ext_Zifencei.enabled(); }
};
#endif // CPU_RISCV_VM_VERSION_RISCV_HPP
diff --git a/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp b/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp
index 5d945dbc323..ce6d9c2f38f 100644
--- a/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp
+++ b/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp
@@ -131,8 +131,8 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
// xmethod: Method*
// x12: receiver
address ame_addr = __ pc();
- __ ld(t0, Address(xmethod, Method::from_compiled_offset()));
- __ jr(t0);
+ __ ld(t1, Address(xmethod, Method::from_compiled_offset()));
+ __ jr(t1);
masm->flush();
bookkeeping(masm, tty, s, npe_addr, ame_addr, true, vtable_index, slop_bytes, 0);
@@ -160,6 +160,13 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
MacroAssembler* masm = new MacroAssembler(&cb);
assert_cond(masm != nullptr);
+ // Real entry arguments:
+ // t0: CompiledICData
+ // j_rarg0: Receiver
+ // Make sure the move of CompiledICData from t0 to t1 is the frist thing that happens.
+ // Otherwise we risk clobber t0 as it is used as scratch.
+ __ mv(t1, t0);
+
#if (!defined(PRODUCT) && defined(COMPILER2))
if (CountCompiledCalls) {
__ la(x18, ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr()));
@@ -170,8 +177,8 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
// get receiver (need to skip return address on top of stack)
assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0");
- // Entry arguments:
- // t1: CompiledICData
+ // Arguments from this point:
+ // t1 (moved from t0): CompiledICData
// j_rarg0: Receiver
// This stub is called from compiled code which has no callee-saved registers,
@@ -220,8 +227,8 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
// xmethod: Method*
// j_rarg0: receiver
address ame_addr = __ pc();
- __ ld(t0, Address(xmethod, Method::from_compiled_offset()));
- __ jr(t0);
+ __ ld(t1, Address(xmethod, Method::from_compiled_offset()));
+ __ jr(t1);
__ bind(L_no_such_interface);
// Handle IncompatibleClassChangeError in itable stubs.
diff --git a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp
index b7f1d360568..e01e4458e38 100644
--- a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp
+++ b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp
@@ -48,7 +48,7 @@ void C1SafepointPollStub::emit_code(LIR_Assembler* ce) {
void RangeCheckStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
if (_info->deoptimize_on_exception()) {
- address a = Runtime1::entry_for (Runtime1::predicate_failed_trap_id);
+ address a = Runtime1::entry_for (C1StubId::predicate_failed_trap_id);
ce->emit_call_c(a);
CHECK_BAILOUT();
ce->add_call_info_here(_info);
@@ -64,11 +64,11 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
__ load_const_optimized(Z_R1_scratch, _index->as_jint());
}
- Runtime1::StubID stub_id;
+ C1StubId stub_id;
if (_throw_index_out_of_bounds_exception) {
- stub_id = Runtime1::throw_index_exception_id;
+ stub_id = C1StubId::throw_index_exception_id;
} else {
- stub_id = Runtime1::throw_range_check_failed_id;
+ stub_id = C1StubId::throw_range_check_failed_id;
__ lgr_if_needed(Z_R0_scratch, _array->as_pointer_register());
}
ce->emit_call_c(Runtime1::entry_for (stub_id));
@@ -84,7 +84,7 @@ PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- address a = Runtime1::entry_for (Runtime1::predicate_failed_trap_id);
+ address a = Runtime1::entry_for (C1StubId::predicate_failed_trap_id);
ce->emit_call_c(a);
CHECK_BAILOUT();
ce->add_call_info_here(_info);
@@ -102,7 +102,7 @@ void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
}
ce->store_parameter(/*_method->as_register()*/ Z_R1_scratch, 1);
ce->store_parameter(_bci, 0);
- ce->emit_call_c(Runtime1::entry_for (Runtime1::counter_overflow_id));
+ ce->emit_call_c(Runtime1::entry_for (C1StubId::counter_overflow_id));
CHECK_BAILOUT();
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
@@ -114,7 +114,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) {
ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
}
__ bind(_entry);
- ce->emit_call_c(Runtime1::entry_for (Runtime1::throw_div0_exception_id));
+ ce->emit_call_c(Runtime1::entry_for (C1StubId::throw_div0_exception_id));
CHECK_BAILOUT();
ce->add_call_info_here(_info);
debug_only(__ should_not_reach_here());
@@ -124,9 +124,9 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
address a;
if (_info->deoptimize_on_exception()) {
// Deoptimize, do not throw the exception, because it is probably wrong to do it here.
- a = Runtime1::entry_for (Runtime1::predicate_failed_trap_id);
+ a = Runtime1::entry_for (C1StubId::predicate_failed_trap_id);
} else {
- a = Runtime1::entry_for (Runtime1::throw_null_pointer_exception_id);
+ a = Runtime1::entry_for (C1StubId::throw_null_pointer_exception_id);
}
ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
@@ -151,14 +151,14 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) {
debug_only(__ should_not_reach_here());
}
-NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) {
+NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, C1StubId stub_id) {
_result = result;
_klass = klass;
_klass_reg = klass_reg;
_info = new CodeEmitInfo(info);
- assert(stub_id == Runtime1::new_instance_id ||
- stub_id == Runtime1::fast_new_instance_id ||
- stub_id == Runtime1::fast_new_instance_init_check_id,
+ assert(stub_id == C1StubId::new_instance_id ||
+ stub_id == C1StubId::fast_new_instance_id ||
+ stub_id == C1StubId::fast_new_instance_init_check_id,
"need new_instance id");
_stub_id = stub_id;
}
@@ -186,7 +186,7 @@ void NewTypeArrayStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
assert(_klass_reg->as_register() == Z_R11, "call target expects klass in Z_R11");
__ lgr_if_needed(Z_R13, _length->as_register());
- address a = Runtime1::entry_for (Runtime1::new_type_array_id);
+ address a = Runtime1::entry_for (C1StubId::new_type_array_id);
ce->emit_call_c(a);
CHECK_BAILOUT();
ce->add_call_info_here(_info);
@@ -206,7 +206,7 @@ void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
assert(_klass_reg->as_register() == Z_R11, "call target expects klass in Z_R11");
__ lgr_if_needed(Z_R13, _length->as_register());
- address a = Runtime1::entry_for (Runtime1::new_object_array_id);
+ address a = Runtime1::entry_for (C1StubId::new_object_array_id);
ce->emit_call_c(a);
CHECK_BAILOUT();
ce->add_call_info_here(_info);
@@ -217,11 +217,11 @@ void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- Runtime1::StubID enter_id;
+ C1StubId enter_id;
if (ce->compilation()->has_fpu_code()) {
- enter_id = Runtime1::monitorenter_id;
+ enter_id = C1StubId::monitorenter_id;
} else {
- enter_id = Runtime1::monitorenter_nofpu_id;
+ enter_id = C1StubId::monitorenter_nofpu_id;
}
__ lgr_if_needed(Z_R1_scratch, _obj_reg->as_register());
__ lgr_if_needed(Z_R13, _lock_reg->as_register()); // See LIRGenerator::syncTempOpr().
@@ -242,11 +242,11 @@ void MonitorExitStub::emit_code(LIR_Assembler* ce) {
__ lgr_if_needed(Z_R1_scratch, _lock_reg->as_register());
}
// Note: non-blocking leaf routine => no call info needed.
- Runtime1::StubID exit_id;
+ C1StubId exit_id;
if (ce->compilation()->has_fpu_code()) {
- exit_id = Runtime1::monitorexit_id;
+ exit_id = C1StubId::monitorexit_id;
} else {
- exit_id = Runtime1::monitorexit_nofpu_id;
+ exit_id = C1StubId::monitorexit_nofpu_id;
}
ce->emit_call_c(Runtime1::entry_for (exit_id));
CHECK_BAILOUT();
@@ -378,10 +378,10 @@ void PatchingStub::emit_code(LIR_Assembler* ce) {
address target = nullptr;
relocInfo::relocType reloc_type = relocInfo::none;
switch (_id) {
- case access_field_id: target = Runtime1::entry_for (Runtime1::access_field_patching_id); break;
- case load_klass_id: target = Runtime1::entry_for (Runtime1::load_klass_patching_id); reloc_type = relocInfo::metadata_type; break;
- case load_mirror_id: target = Runtime1::entry_for (Runtime1::load_mirror_patching_id); reloc_type = relocInfo::oop_type; break;
- case load_appendix_id: target = Runtime1::entry_for (Runtime1::load_appendix_patching_id); reloc_type = relocInfo::oop_type; break;
+ case access_field_id: target = Runtime1::entry_for (C1StubId::access_field_patching_id); break;
+ case load_klass_id: target = Runtime1::entry_for (C1StubId::load_klass_patching_id); reloc_type = relocInfo::metadata_type; break;
+ case load_mirror_id: target = Runtime1::entry_for (C1StubId::load_mirror_patching_id); reloc_type = relocInfo::oop_type; break;
+ case load_appendix_id: target = Runtime1::entry_for (C1StubId::load_appendix_patching_id); reloc_type = relocInfo::oop_type; break;
default: ShouldNotReachHere();
}
__ bind(call_patch);
@@ -406,7 +406,7 @@ void PatchingStub::emit_code(LIR_Assembler* ce) {
void DeoptimizeStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
__ load_const_optimized(Z_R1_scratch, _trap_request); // Pass trap request in Z_R1_scratch.
- ce->emit_call_c(Runtime1::entry_for (Runtime1::deoptimize_id));
+ ce->emit_call_c(Runtime1::entry_for (C1StubId::deoptimize_id));
CHECK_BAILOUT();
ce->add_call_info_here(_info);
DEBUG_ONLY(__ should_not_reach_here());
diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp
index a5e62169a93..8bf11816219 100644
--- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp
+++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp
@@ -172,7 +172,7 @@ int LIR_Assembler::emit_exception_handler() {
int offset = code_offset();
- address a = Runtime1::entry_for (Runtime1::handle_exception_from_callee_id);
+ address a = Runtime1::entry_for (C1StubId::handle_exception_from_callee_id);
address call_addr = emit_call_c(a);
CHECK_BAILOUT_(-1);
__ should_not_reach_here();
@@ -212,11 +212,15 @@ int LIR_Assembler::emit_unwind_handler() {
// Perform needed unlocking.
MonitorExitStub* stub = nullptr;
if (method()->is_synchronized()) {
- // Runtime1::monitorexit_id expects lock address in Z_R1_scratch.
+ // C1StubId::monitorexit_id expects lock address in Z_R1_scratch.
LIR_Opr lock = FrameMap::as_opr(Z_R1_scratch);
monitor_address(0, lock);
stub = new MonitorExitStub(lock, true, 0);
- __ unlock_object(Rtmp1, Rtmp2, lock->as_register(), *stub->entry());
+ if (LockingMode == LM_MONITOR) {
+ __ branch_optimized(Assembler::bcondAlways, *stub->entry());
+ } else {
+ __ unlock_object(Rtmp1, Rtmp2, lock->as_register(), *stub->entry());
+ }
__ bind(*stub->continuation());
}
@@ -241,7 +245,7 @@ int LIR_Assembler::emit_unwind_handler() {
// Z_EXC_PC: exception pc
// Dispatch to the unwind logic.
- __ load_const_optimized(Z_R5, Runtime1::entry_for (Runtime1::unwind_exception_id));
+ __ load_const_optimized(Z_R5, Runtime1::entry_for (C1StubId::unwind_exception_id));
__ z_br(Z_R5);
// Emit the slow path assembly.
@@ -1910,8 +1914,8 @@ void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmit
// Reuse the debug info from the safepoint poll for the throw op itself.
__ get_PC(Z_EXC_PC);
add_call_info(__ offset(), info); // for exception handler
- address stub = Runtime1::entry_for (compilation()->has_fpu_code() ? Runtime1::handle_exception_id
- : Runtime1::handle_exception_nofpu_id);
+ address stub = Runtime1::entry_for (compilation()->has_fpu_code() ? C1StubId::handle_exception_id
+ : C1StubId::handle_exception_nofpu_id);
emit_call_c(stub);
}
@@ -2116,7 +2120,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
store_parameter(src_klass, 0); // sub
store_parameter(dst_klass, 1); // super
- emit_call_c(Runtime1::entry_for (Runtime1::slow_subtype_check_id));
+ emit_call_c(Runtime1::entry_for (C1StubId::slow_subtype_check_id));
CHECK_BAILOUT2(cont, slow);
// Sets condition code 0 for match (2 otherwise).
__ branch_optimized(Assembler::bcondEqual, cont);
@@ -2350,6 +2354,7 @@ void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, jint count, LIR_Opr de
void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) {
if (op->init_check()) {
// Make sure klass is initialized & doesn't have finalizer.
+ // init_state needs acquire, but S390 is TSO, and so we are already good.
const int state_offset = in_bytes(InstanceKlass::init_state_offset());
Register iklass = op->klass()->as_register();
add_debug_info_for_null_check_here(op->stub()->info());
@@ -2539,7 +2544,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L
RegisterOrConstant(super_check_offset));
if (need_slow_path) {
// Call out-of-line instance of __ check_klass_subtype_slow_path(...):
- address a = Runtime1::entry_for (Runtime1::slow_subtype_check_id);
+ address a = Runtime1::entry_for (C1StubId::slow_subtype_check_id);
store_parameter(klass_RInfo, 0); // sub
store_parameter(k_RInfo, 1); // super
emit_call_c(a); // Sets condition code 0 for match (2 otherwise).
@@ -2614,7 +2619,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
// Perform the fast part of the checking logic.
__ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, success_target, failure_target, nullptr);
// Call out-of-line instance of __ check_klass_subtype_slow_path(...):
- address a = Runtime1::entry_for (Runtime1::slow_subtype_check_id);
+ address a = Runtime1::entry_for (C1StubId::slow_subtype_check_id);
store_parameter(klass_RInfo, 0); // sub
store_parameter(k_RInfo, 1); // super
emit_call_c(a); // Sets condition code 0 for match (2 otherwise).
diff --git a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp
index 619f0f7174f..f998e86256f 100644
--- a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp
+++ b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp
@@ -885,7 +885,7 @@ void LIRGenerator::do_NewMultiArray(NewMultiArray* x) {
args->append(rank);
args->append(varargs);
LIR_Opr reg = result_register_for (x->type());
- __ call_runtime(Runtime1::entry_for (Runtime1::new_multi_array_id),
+ __ call_runtime(Runtime1::entry_for (C1StubId::new_multi_array_id),
LIR_OprFact::illegalOpr,
reg, args, info);
@@ -916,14 +916,14 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
CodeStub* stub;
if (x->is_incompatible_class_change_check()) {
assert(patching_info == nullptr, "can't patch this");
- stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception);
+ stub = new SimpleExceptionStub(C1StubId::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception);
} else if (x->is_invokespecial_receiver_check()) {
assert(patching_info == nullptr, "can't patch this");
stub = new DeoptimizeStub(info_for_exception,
Deoptimization::Reason_class_check,
Deoptimization::Action_none);
} else {
- stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception);
+ stub = new SimpleExceptionStub(C1StubId::throw_class_cast_exception_id, obj.result(), info_for_exception);
}
LIR_Opr reg = rlock_result(x);
LIR_Opr tmp1 = new_register(objectType);
diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp
index 13b08067821..41c2ae260a6 100644
--- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp
+++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp
@@ -72,14 +72,14 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp, Roop);
- testbit(Address(tmp, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
+ z_tm(Address(tmp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class);
branch_optimized(Assembler::bcondAllOne, slow_case);
}
assert(LockingMode != LM_MONITOR, "LM_MONITOR is already handled, by emit_lock()");
if (LockingMode == LM_LIGHTWEIGHT) {
- lightweight_lock(Roop, Rmark, tmp, slow_case);
+ lightweight_lock(Rbox, Roop, Rmark, tmp, slow_case);
} else if (LockingMode == LM_LEGACY) {
NearLabel done;
@@ -120,6 +120,8 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox
branch_optimized(Assembler::bcondNotZero, slow_case);
// done
bind(done);
+ } else {
+ assert(false, "Unhandled LockingMode:%d", LockingMode);
}
}
@@ -151,6 +153,8 @@ void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rb
// If the object header was not pointing to the displaced header,
// we do unlocking via runtime call.
branch_optimized(Assembler::bcondNotEqual, slow_case);
+ } else {
+ assert(false, "Unhandled LockingMode:%d", LockingMode);
}
// done
bind(done);
@@ -254,7 +258,7 @@ void C1_MacroAssembler::initialize_object(
// Dtrace support is unimplemented.
// if (CURRENT_ENV->dtrace_alloc_probes()) {
// assert(obj == rax, "must be");
- // call(RuntimeAddress(Runtime1::entry_for (Runtime1::dtrace_object_alloc_id)));
+ // call(RuntimeAddress(Runtime1::entry_for (C1StubId::dtrace_object_alloc_id)));
// }
verify_oop(obj, FILE_AND_LINE);
@@ -315,7 +319,7 @@ void C1_MacroAssembler::allocate_array(
// Dtrace support is unimplemented.
// if (CURRENT_ENV->dtrace_alloc_probes()) {
// assert(obj == rax, "must be");
- // call(RuntimeAddress(Runtime1::entry_for (Runtime1::dtrace_object_alloc_id)));
+ // call(RuntimeAddress(Runtime1::entry_for (C1StubId::dtrace_object_alloc_id)));
// }
verify_oop(obj, FILE_AND_LINE);
diff --git a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp
index decb3a1cafc..2f629c108c9 100644
--- a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp
+++ b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2023 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -98,10 +98,10 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre
restore_return_pc();
load_const_optimized(Z_R1, StubRoutines::forward_exception_entry());
z_br(Z_R1);
- } else if (_stub_id == Runtime1::forward_exception_id) {
+ } else if (_stub_id == (int)C1StubId::forward_exception_id) {
should_not_reach_here();
} else {
- load_const_optimized(Z_R1, Runtime1::entry_for (Runtime1::forward_exception_id));
+ load_const_optimized(Z_R1, Runtime1::entry_for (C1StubId::forward_exception_id));
z_br(Z_R1);
}
@@ -305,7 +305,7 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
return oop_maps;
}
-OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
+OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) {
// for better readability
const bool must_gc_arguments = true;
@@ -318,26 +318,26 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
// Stub code and info for the different stubs.
OopMapSet* oop_maps = nullptr;
switch (id) {
- case forward_exception_id:
+ case C1StubId::forward_exception_id:
{
oop_maps = generate_handle_exception(id, sasm);
// will not return
}
break;
- case new_instance_id:
- case fast_new_instance_id:
- case fast_new_instance_init_check_id:
+ case C1StubId::new_instance_id:
+ case C1StubId::fast_new_instance_id:
+ case C1StubId::fast_new_instance_init_check_id:
{
Register klass = Z_R11; // Incoming
Register obj = Z_R2; // Result
- if (id == new_instance_id) {
+ if (id == C1StubId::new_instance_id) {
__ set_info("new_instance", dont_gc_arguments);
- } else if (id == fast_new_instance_id) {
+ } else if (id == C1StubId::fast_new_instance_id) {
__ set_info("fast new_instance", dont_gc_arguments);
} else {
- assert(id == fast_new_instance_init_check_id, "bad StubID");
+ assert(id == C1StubId::fast_new_instance_init_check_id, "bad C1StubId");
__ set_info("fast new_instance init check", dont_gc_arguments);
}
@@ -352,7 +352,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case counter_overflow_id:
+ case C1StubId::counter_overflow_id:
{
// Arguments :
// bci : stack param 0
@@ -371,14 +371,14 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
__ z_br(Z_R14);
}
break;
- case new_type_array_id:
- case new_object_array_id:
+ case C1StubId::new_type_array_id:
+ case C1StubId::new_object_array_id:
{
Register length = Z_R13; // Incoming
Register klass = Z_R11; // Incoming
Register obj = Z_R2; // Result
- if (id == new_type_array_id) {
+ if (id == C1StubId::new_type_array_id) {
__ set_info("new_type_array", dont_gc_arguments);
} else {
__ set_info("new_object_array", dont_gc_arguments);
@@ -391,7 +391,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
Register t0 = obj;
__ mem2reg_opt(t0, Address(klass, Klass::layout_helper_offset()), false);
__ z_sra(t0, Klass::_lh_array_tag_shift);
- int tag = ((id == new_type_array_id)
+ int tag = ((id == C1StubId::new_type_array_id)
? Klass::_lh_array_tag_type_value
: Klass::_lh_array_tag_obj_value);
__ compare32_and_branch(t0, tag, Assembler::bcondEqual, ok);
@@ -403,7 +403,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
OopMap* map = save_live_registers_except_r2(sasm);
int call_offset;
- if (id == new_type_array_id) {
+ if (id == C1StubId::new_type_array_id) {
call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_type_array), klass, length);
} else {
call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length);
@@ -418,7 +418,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case new_multi_array_id:
+ case C1StubId::new_multi_array_id:
{ __ set_info("new_multi_array", dont_gc_arguments);
// Z_R3,: klass
// Z_R4,: rank
@@ -436,14 +436,14 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case register_finalizer_id:
+ case C1StubId::register_finalizer_id:
{
__ set_info("register_finalizer", dont_gc_arguments);
// Load the klass and check the has finalizer flag.
Register klass = Z_ARG2;
__ load_klass(klass, Z_ARG1);
- __ testbit(Address(klass, Klass::access_flags_offset()), exact_log2(JVM_ACC_HAS_FINALIZER));
+ __ z_tm(Address(klass, Klass::misc_flags_offset()), KlassFlags::_misc_has_finalizer);
__ z_bcr(Assembler::bcondAllZero, Z_R14); // Return if bit is not set.
OopMap* oop_map = save_live_registers(sasm);
@@ -459,62 +459,62 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case throw_range_check_failed_id:
+ case C1StubId::throw_range_check_failed_id:
{ __ set_info("range_check_failed", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), true);
}
break;
- case throw_index_exception_id:
+ case C1StubId::throw_index_exception_id:
{ __ set_info("index_range_check_failed", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true);
}
break;
- case throw_div0_exception_id:
+ case C1StubId::throw_div0_exception_id:
{ __ set_info("throw_div0_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false);
}
break;
- case throw_null_pointer_exception_id:
+ case C1StubId::throw_null_pointer_exception_id:
{ __ set_info("throw_null_pointer_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false);
}
break;
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
{ __ set_info("handle_exception", dont_gc_arguments);
oop_maps = generate_handle_exception(id, sasm);
}
break;
- case handle_exception_from_callee_id:
+ case C1StubId::handle_exception_from_callee_id:
{ __ set_info("handle_exception_from_callee", dont_gc_arguments);
oop_maps = generate_handle_exception(id, sasm);
}
break;
- case unwind_exception_id:
+ case C1StubId::unwind_exception_id:
{ __ set_info("unwind_exception", dont_gc_arguments);
// Note: no stubframe since we are about to leave the current
// activation and we are calling a leaf VM function only.
generate_unwind_exception(sasm);
}
break;
- case throw_array_store_exception_id:
+ case C1StubId::throw_array_store_exception_id:
{ __ set_info("throw_array_store_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_array_store_exception), true);
}
break;
- case throw_class_cast_exception_id:
+ case C1StubId::throw_class_cast_exception_id:
{ // Z_R1_scratch: object
__ set_info("throw_class_cast_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true);
}
break;
- case throw_incompatible_class_change_error_id:
+ case C1StubId::throw_incompatible_class_change_error_id:
{ __ set_info("throw_incompatible_class_cast_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false);
}
break;
- case slow_subtype_check_id:
+ case C1StubId::slow_subtype_check_id:
{
// Arguments :
// sub : stack param 0
@@ -580,13 +580,13 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
__ z_br(Z_R14);
}
break;
- case monitorenter_nofpu_id:
- case monitorenter_id:
+ case C1StubId::monitorenter_nofpu_id:
+ case C1StubId::monitorenter_id:
{ // Z_R1_scratch : object
// Z_R13 : lock address (see LIRGenerator::syncTempOpr())
__ set_info("monitorenter", dont_gc_arguments);
- int save_fpu_registers = (id == monitorenter_id);
+ int save_fpu_registers = (id == C1StubId::monitorenter_id);
// Make a frame and preserve the caller's caller-save registers.
OopMap* oop_map = save_live_registers(sasm, save_fpu_registers);
@@ -600,15 +600,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case monitorexit_nofpu_id:
- case monitorexit_id:
+ case C1StubId::monitorexit_nofpu_id:
+ case C1StubId::monitorexit_id:
{ // Z_R1_scratch : lock address
// Note: really a leaf routine but must setup last java sp
// => Use call_RT for now (speed can be improved by
// doing last java sp setup manually).
__ set_info("monitorexit", dont_gc_arguments);
- int save_fpu_registers = (id == monitorexit_id);
+ int save_fpu_registers = (id == C1StubId::monitorexit_id);
// Make a frame and preserve the caller's caller-save registers.
OopMap* oop_map = save_live_registers(sasm, save_fpu_registers);
@@ -622,7 +622,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case deoptimize_id:
+ case C1StubId::deoptimize_id:
{ // Args: Z_R1_scratch: trap request
__ set_info("deoptimize", dont_gc_arguments);
Register trap_request = Z_R1_scratch;
@@ -639,32 +639,32 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case access_field_patching_id:
+ case C1StubId::access_field_patching_id:
{ __ set_info("access_field_patching", dont_gc_arguments);
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching));
}
break;
- case load_klass_patching_id:
+ case C1StubId::load_klass_patching_id:
{ __ set_info("load_klass_patching", dont_gc_arguments);
// We should set up register map.
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching));
}
break;
- case load_mirror_patching_id:
+ case C1StubId::load_mirror_patching_id:
{ __ set_info("load_mirror_patching", dont_gc_arguments);
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_mirror_patching));
}
break;
- case load_appendix_patching_id:
+ case C1StubId::load_appendix_patching_id:
{ __ set_info("load_appendix_patching", dont_gc_arguments);
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching));
}
break;
#if 0
- case dtrace_object_alloc_id:
+ case C1StubId::dtrace_object_alloc_id:
{ // rax,: object
StubFrame f(sasm, "dtrace_object_alloc", dont_gc_arguments);
// We can't gc here so skip the oopmap but make sure that all
@@ -679,7 +679,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case fpu2long_stub_id:
+ case C1StubId::fpu2long_stub_id:
{
// rax, and rdx are destroyed, but should be free since the result is returned there
// preserve rsi,ecx
@@ -754,7 +754,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
break;
#endif // TODO
- case predicate_failed_trap_id:
+ case C1StubId::predicate_failed_trap_id:
{
__ set_info("predicate_failed_trap", dont_gc_arguments);
@@ -775,14 +775,14 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
default:
{
- __ should_not_reach_here(FILE_AND_LINE, id);
+ __ should_not_reach_here(FILE_AND_LINE, (int)id);
}
break;
}
return oop_maps;
}
-OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
+OopMapSet* Runtime1::generate_handle_exception(C1StubId id, StubAssembler *sasm) {
__ block_comment("generate_handle_exception");
// incoming parameters: Z_EXC_OOP, Z_EXC_PC
@@ -793,7 +793,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
Register reg_fp = Z_R1_scratch;
switch (id) {
- case forward_exception_id: {
+ case C1StubId::forward_exception_id: {
// We're handling an exception in the context of a compiled frame.
// The registers have been saved in the standard places. Perform
// an exception lookup in the caller and dispatch to the handler
@@ -820,13 +820,13 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
__ clear_mem(Address(Z_thread, JavaThread::vm_result_2_offset()), sizeof(Metadata*));
break;
}
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
// At this point all registers MAY be live.
DEBUG_ONLY(__ z_lgr(reg_fp, Z_SP);)
- oop_map = save_live_registers(sasm, id != handle_exception_nofpu_id, Z_EXC_PC);
+ oop_map = save_live_registers(sasm, id != C1StubId::handle_exception_nofpu_id, Z_EXC_PC);
break;
- case handle_exception_from_callee_id: {
+ case C1StubId::handle_exception_from_callee_id: {
// At this point all registers except Z_EXC_OOP and Z_EXC_PC are dead.
DEBUG_ONLY(__ z_lgr(reg_fp, Z_SP);)
__ save_return_pc(Z_EXC_PC);
@@ -875,15 +875,15 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
__ invalidate_registers(Z_R2);
switch(id) {
- case forward_exception_id:
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::forward_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
// Restore the registers that were saved at the beginning.
__ z_lgr(Z_R1_scratch, Z_R2); // Restoring live registers kills Z_R2.
- restore_live_registers(sasm, id != handle_exception_nofpu_id); // Pops as well the frame.
+ restore_live_registers(sasm, id != C1StubId::handle_exception_nofpu_id); // Pops as well the frame.
__ z_br(Z_R1_scratch);
break;
- case handle_exception_from_callee_id: {
+ case C1StubId::handle_exception_from_callee_id: {
__ pop_frame();
__ z_br(Z_R2); // Jump to exception handler.
}
diff --git a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp
index 3641d82dabe..025ef4c8915 100644
--- a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp
+++ b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp
@@ -34,12 +34,12 @@
#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Register temp1, Register temp2) {
- compiler_fast_lock_lightweight_object(obj, temp1, temp2);
+ compiler_fast_lock_lightweight_object(obj, box, temp1, temp2);
}
void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, Register temp1, Register temp2) {
- compiler_fast_unlock_lightweight_object(obj, temp1, temp2);
+ compiler_fast_unlock_lightweight_object(obj, box, temp1, temp2);
}
//------------------------------------------------------
diff --git a/src/hotspot/cpu/s390/downcallLinker_s390.cpp b/src/hotspot/cpu/s390/downcallLinker_s390.cpp
index 383a3244874..85ddc5bf185 100644
--- a/src/hotspot/cpu/s390/downcallLinker_s390.cpp
+++ b/src/hotspot/cpu/s390/downcallLinker_s390.cpp
@@ -36,8 +36,8 @@
#define __ _masm->
-static const int native_invoker_code_base_size = 512;
-static const int native_invoker_size_per_args = 8;
+static const int native_invoker_code_base_size = 384;
+static const int native_invoker_size_per_args = 12;
RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature,
int num_args,
diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp
index 37631298920..544c82d34a7 100644
--- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp
+++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018, 2023 SAP SE. All rights reserved.
+ * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -42,11 +42,47 @@
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "gc/g1/c1/g1BarrierSetC1.hpp"
-#endif
+#endif // COMPILER1
+#ifdef COMPILER2
+#include "gc/g1/c2/g1BarrierSetC2.hpp"
+#endif // COMPILER2
#define __ masm->
-#define BLOCK_COMMENT(str) if (PrintAssembly) __ block_comment(str)
+#define BLOCK_COMMENT(str) __ block_comment(str)
+
+static void generate_pre_barrier_fast_path(MacroAssembler* masm,
+ const Register thread,
+ const Register tmp1) {
+ Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
+ // Is marking active?
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ load_and_test_int(tmp1, in_progress);
+ } else {
+ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ load_and_test_byte(tmp1, in_progress);
+ }
+}
+
+static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime,
+ const Register Z_thread, const Register value, const Register temp) {
+ BLOCK_COMMENT("generate_queue_test_and_insertion {");
+
+ assert_different_registers(temp, value);
+ // Can we store a value in the given thread's buffer?
+ // (The index field is typed as size_t.)
+
+ __ load_and_test_long(temp, Address(Z_thread, in_bytes(index_offset))); // temp := *(index address)
+ __ branch_optimized(Assembler::bcondEqual, runtime); // jump to runtime if index == 0 (full buffer)
+
+ // The buffer is not full, store value into it.
+ __ add2reg(temp, -wordSize); // temp := next index
+ __ z_stg(temp, in_bytes(index_offset), Z_thread); // *(index address) := next index
+
+ __ z_ag(temp, Address(Z_thread, in_bytes(buffer_offset))); // temp := buffer address + next index
+ __ z_stg(value, 0, temp); // *(buffer address + next index) := value
+ BLOCK_COMMENT("} generate_queue_test_and_insertion");
+}
void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register addr, Register count) {
@@ -59,13 +95,8 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm
assert_different_registers(addr, Z_R0_scratch); // would be destroyed by push_frame()
assert_different_registers(count, Z_R0_scratch); // would be destroyed by push_frame()
Register Rtmp1 = Z_R0_scratch;
- const int active_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- __ load_and_test_int(Rtmp1, Address(Z_thread, active_offset));
- } else {
- guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- __ load_and_test_byte(Rtmp1, Address(Z_thread, active_offset));
- }
+
+ generate_pre_barrier_fast_path(masm, Z_thread, Rtmp1);
__ z_bre(filtered); // Activity indicator is zero, so there is no marking going on currently.
RegisterSaver::save_live_registers(masm, RegisterSaver::arg_registers); // Creates frame.
@@ -100,6 +131,181 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas
}
}
+#if defined(COMPILER2)
+
+#undef __
+#define __ masm->
+
+static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register pre_val, const address runtime_path) {
+ BLOCK_COMMENT("generate_c2_barrier_runtime_call {");
+ SaveLiveRegisters save_registers(masm, stub);
+ __ call_VM_leaf(runtime_path, pre_val, Z_thread);
+ BLOCK_COMMENT("} generate_c2_barrier_runtime_call");
+}
+
+void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp1,
+ G1PreBarrierStubC2* stub) {
+
+ BLOCK_COMMENT("g1_write_barrier_pre_c2 {");
+
+ assert(thread == Z_thread, "must be");
+ assert_different_registers(obj, pre_val, tmp1);
+ assert(pre_val != noreg && tmp1 != noreg, "expecting a register");
+
+ stub->initialize_registers(obj, pre_val, thread, tmp1, noreg);
+
+ generate_pre_barrier_fast_path(masm, thread, tmp1);
+ __ branch_optimized(Assembler::bcondNotEqual, *stub->entry()); // Activity indicator is zero, so there is no marking going on currently.
+
+ __ bind(*stub->continuation());
+
+ BLOCK_COMMENT("} g1_write_barrier_pre_c2");
+}
+
+void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
+ G1PreBarrierStubC2* stub) const {
+
+ BLOCK_COMMENT("generate_c2_pre_barrier_stub {");
+
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+
+ Label runtime;
+ Register obj = stub->obj();
+ Register pre_val = stub->pre_val();
+ Register thread = stub->thread();
+ Register tmp1 = stub->tmp1();
+
+ __ bind(*stub->entry());
+
+ BLOCK_COMMENT("generate_pre_val_not_null_test {");
+ if (obj != noreg) {
+ __ load_heap_oop(pre_val, Address(obj), noreg, noreg, AS_RAW);
+ }
+ __ z_ltgr(pre_val, pre_val);
+ __ branch_optimized(Assembler::bcondEqual, *stub->continuation());
+ BLOCK_COMMENT("} generate_pre_val_not_null_test");
+
+ generate_queue_test_and_insertion(masm,
+ G1ThreadLocalData::satb_mark_queue_index_offset(),
+ G1ThreadLocalData::satb_mark_queue_buffer_offset(),
+ runtime,
+ Z_thread, pre_val, tmp1);
+
+ __ branch_optimized(Assembler::bcondAlways, *stub->continuation());
+
+ __ bind(runtime);
+
+ generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry));
+
+ __ branch_optimized(Assembler::bcondAlways, *stub->continuation());
+
+ BLOCK_COMMENT("} generate_c2_pre_barrier_stub");
+}
+
+void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2,
+ G1PostBarrierStubC2* stub) {
+ BLOCK_COMMENT("g1_write_barrier_post_c2 {");
+
+ assert(thread == Z_thread, "must be");
+ assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, Z_R1_scratch);
+
+ assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register");
+
+ stub->initialize_registers(thread, tmp1, tmp2);
+
+ BLOCK_COMMENT("generate_region_crossing_test {");
+ if (VM_Version::has_DistinctOpnds()) {
+ __ z_xgrk(tmp1, store_addr, new_val);
+ } else {
+ __ z_lgr(tmp1, store_addr);
+ __ z_xgr(tmp1, new_val);
+ }
+ __ z_srag(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes);
+ __ branch_optimized(Assembler::bcondEqual, *stub->continuation());
+ BLOCK_COMMENT("} generate_region_crossing_test");
+
+ // crosses regions, storing null?
+ if ((stub->barrier_data() & G1C2BarrierPostNotNull) == 0) {
+ __ z_ltgr(new_val, new_val);
+ __ branch_optimized(Assembler::bcondEqual, *stub->continuation());
+ }
+
+ BLOCK_COMMENT("generate_card_young_test {");
+ CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set());
+ // calculate address of card
+ __ load_const_optimized(tmp2, (address)ct->card_table()->byte_map_base()); // Card table base.
+ __ z_srlg(tmp1, store_addr, CardTable::card_shift()); // Index into card table.
+ __ z_algr(tmp1, tmp2); // Explicit calculation needed for cli.
+
+ // Filter young.
+ __ z_cli(0, tmp1, G1CardTable::g1_young_card_val());
+
+ BLOCK_COMMENT("} generate_card_young_test");
+
+ // From here on, tmp1 holds the card address.
+ __ branch_optimized(Assembler::bcondNotEqual, *stub->entry());
+
+ __ bind(*stub->continuation());
+
+ BLOCK_COMMENT("} g1_write_barrier_post_c2");
+}
+
+void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
+ G1PostBarrierStubC2* stub) const {
+
+ BLOCK_COMMENT("generate_c2_post_barrier_stub {");
+
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ Label runtime;
+
+ Register thread = stub->thread();
+ Register tmp1 = stub->tmp1(); // tmp1 holds the card address.
+ Register tmp2 = stub->tmp2();
+ Register Rcard_addr = tmp1;
+
+ __ bind(*stub->entry());
+
+ BLOCK_COMMENT("generate_card_clean_test {");
+ __ z_sync(); // Required to support concurrent cleaning.
+ __ z_cli(0, Rcard_addr, 0); // Reload after membar.
+ __ branch_optimized(Assembler::bcondEqual, *stub->continuation());
+ BLOCK_COMMENT("} generate_card_clean_test");
+
+ BLOCK_COMMENT("generate_dirty_card {");
+ // Storing a region crossing, non-null oop, card is clean.
+ // Dirty card and log.
+ STATIC_ASSERT(CardTable::dirty_card_val() == 0);
+ __ z_mvi(0, Rcard_addr, CardTable::dirty_card_val());
+ BLOCK_COMMENT("} generate_dirty_card");
+
+ generate_queue_test_and_insertion(masm,
+ G1ThreadLocalData::dirty_card_queue_index_offset(),
+ G1ThreadLocalData::dirty_card_queue_buffer_offset(),
+ runtime,
+ Z_thread, tmp1, tmp2);
+
+ __ branch_optimized(Assembler::bcondAlways, *stub->continuation());
+
+ __ bind(runtime);
+
+ generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry));
+
+ __ branch_optimized(Assembler::bcondAlways, *stub->continuation());
+
+ BLOCK_COMMENT("} generate_c2_post_barrier_stub");
+}
+
+#endif //COMPILER2
+
void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
const Address& src, Register dst, Register tmp1, Register tmp2, Label *L_handle_null) {
bool on_oop = is_reference_type(type);
@@ -136,9 +342,6 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator
const Register Robj = obj ? obj->base() : noreg,
Roff = obj ? obj->index() : noreg;
- const int active_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
- const int buffer_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
- const int index_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
assert_different_registers(Rtmp1, Rtmp2, Z_R0_scratch); // None of the Rtmp must be Z_R0!!
assert_different_registers(Robj, Z_R0_scratch); // Used for addressing. Furthermore, push_frame destroys Z_R0!!
assert_different_registers(Rval, Z_R0_scratch); // push_frame destroys Z_R0!!
@@ -147,14 +350,7 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator
BLOCK_COMMENT("g1_write_barrier_pre {");
- // Is marking active?
- // Note: value is loaded for test purposes only. No further use here.
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- __ load_and_test_int(Rtmp1, Address(Z_thread, active_offset));
- } else {
- guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- __ load_and_test_byte(Rtmp1, Address(Z_thread, active_offset));
- }
+ generate_pre_barrier_fast_path(masm, Z_thread, Rtmp1);
__ z_bre(filtered); // Activity indicator is zero, so there is no marking going on currently.
assert(Rpre_val != noreg, "must have a real register");
@@ -194,24 +390,14 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator
// We can store the original value in the thread's buffer
// only if index > 0. Otherwise, we need runtime to handle.
// (The index field is typed as size_t.)
- Register Rbuffer = Rtmp1, Rindex = Rtmp2;
- assert_different_registers(Rbuffer, Rindex, Rpre_val);
-
- __ z_lg(Rbuffer, buffer_offset, Z_thread);
- __ load_and_test_long(Rindex, Address(Z_thread, index_offset));
- __ z_bre(callRuntime); // If index == 0, goto runtime.
-
- __ add2reg(Rindex, -wordSize); // Decrement index.
- __ z_stg(Rindex, index_offset, Z_thread);
-
- // Record the previous value.
- __ z_stg(Rpre_val, 0, Rbuffer, Rindex);
+ generate_queue_test_and_insertion(masm,
+ G1ThreadLocalData::satb_mark_queue_index_offset(),
+ G1ThreadLocalData::satb_mark_queue_buffer_offset(),
+ callRuntime,
+ Z_thread, Rpre_val, Rtmp2);
__ z_bru(filtered); // We are done.
- Rbuffer = noreg; // end of life
- Rindex = noreg; // end of life
-
__ bind(callRuntime);
// Save some registers (inputs and result) over runtime call
@@ -326,23 +512,16 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato
Register Rcard_addr_x = Rcard_addr;
Register Rqueue_index = (Rtmp2 != Z_R0_scratch) ? Rtmp2 : Rtmp1;
- Register Rqueue_buf = (Rtmp3 != Z_R0_scratch) ? Rtmp3 : Rtmp1;
- const int qidx_off = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset());
- const int qbuf_off = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset());
- if ((Rcard_addr == Rqueue_buf) || (Rcard_addr == Rqueue_index)) {
+ if (Rcard_addr == Rqueue_index) {
Rcard_addr_x = Z_R0_scratch; // Register shortage. We have to use Z_R0.
}
__ lgr_if_needed(Rcard_addr_x, Rcard_addr);
- __ load_and_test_long(Rqueue_index, Address(Z_thread, qidx_off));
- __ z_bre(callRuntime); // Index == 0 then jump to runtime.
-
- __ z_lg(Rqueue_buf, qbuf_off, Z_thread);
-
- __ add2reg(Rqueue_index, -wordSize); // Decrement index.
- __ z_stg(Rqueue_index, qidx_off, Z_thread);
-
- __ z_stg(Rcard_addr_x, 0, Rqueue_index, Rqueue_buf); // Store card.
+ generate_queue_test_and_insertion(masm,
+ G1ThreadLocalData::dirty_card_queue_index_offset(),
+ G1ThreadLocalData::dirty_card_queue_buffer_offset(),
+ callRuntime,
+ Z_thread, Rcard_addr_x, Rqueue_index);
__ z_bru(filtered);
__ bind(callRuntime);
diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp
index cc1d51d2fa1..0f0bdd8b83c 100644
--- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp
+++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018 SAP SE. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,8 @@ class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
class G1PostBarrierStub;
+class G1PreBarrierStubC2;
+class G1PostBarrierStubC2;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@@ -62,7 +64,27 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
-#endif
+#endif // COMPILER1
+
+#ifdef COMPILER2
+ void g1_write_barrier_pre_c2(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp1,
+ G1PreBarrierStubC2* c2_stub);
+ void generate_c2_pre_barrier_stub(MacroAssembler* masm,
+ G1PreBarrierStubC2* stub) const;
+ void g1_write_barrier_post_c2(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp1,
+ Register tmp2,
+ G1PostBarrierStubC2* c2_stub);
+ void generate_c2_post_barrier_stub(MacroAssembler* masm,
+ G1PostBarrierStubC2* stub) const;
+#endif // COMPILER2
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
const Address& src, Register dst, Register tmp1, Register tmp2, Label *L_handle_null = nullptr);
diff --git a/src/hotspot/cpu/s390/gc/g1/g1_s390.ad b/src/hotspot/cpu/s390/gc/g1/g1_s390.ad
new file mode 100644
index 00000000000..31f60c4aeff
--- /dev/null
+++ b/src/hotspot/cpu/s390/gc/g1/g1_s390.ad
@@ -0,0 +1,457 @@
+//
+// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+// Copyright 2024 IBM Corporation. All rights reserved.
+// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+//
+// This code is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 2 only, as
+// published by the Free Software Foundation.
+//
+// This code is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// version 2 for more details (a copy is included in the LICENSE file that
+// accompanied this code).
+//
+// You should have received a copy of the GNU General Public License version
+// 2 along with this work; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+// or visit www.oracle.com if you need additional information or have any
+// questions.
+//
+
+source_hpp %{
+
+#include "gc/g1/c2/g1BarrierSetC2.hpp"
+#include "gc/shared/gc_globals.hpp"
+
+%}
+
+source %{
+
+#include "gc/g1/g1BarrierSetAssembler_s390.hpp"
+#include "gc/g1/g1BarrierSetRuntime.hpp"
+
+static void write_barrier_pre(MacroAssembler* masm,
+ const MachNode* node,
+ Register obj,
+ Register pre_val,
+ Register tmp1,
+ RegSet preserve = RegSet(),
+ RegSet no_preserve = RegSet()) {
+ if (!G1PreBarrierStubC2::needs_barrier(node)) {
+ return;
+ }
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
+ G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node);
+ for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) {
+ stub->preserve(*reg);
+ }
+ for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) {
+ stub->dont_preserve(*reg);
+ }
+ g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, Z_thread, tmp1, stub);
+}
+
+static void write_barrier_post(MacroAssembler* masm,
+ const MachNode* node,
+ Register store_addr,
+ Register new_val,
+ Register tmp1,
+ Register tmp2) {
+ if (!G1PostBarrierStubC2::needs_barrier(node)) {
+ return;
+ }
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
+ G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
+ g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, Z_thread, tmp1, tmp2, stub);
+}
+
+%} // source
+
+// store pointer
+instruct g1StoreP(indirect dst, memoryRegP src, iRegL tmp1, iRegL tmp2, flagsReg cr) %{
+ predicate(UseG1GC && n->as_Store()->barrier_data() != 0);
+ match(Set dst (StoreP dst src));
+ effect(TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(MEMORY_REF_COST);
+ format %{ "STG $src,$dst\t # ptr" %}
+ ins_encode %{
+ __ block_comment("g1StoreP {");
+ write_barrier_pre(masm, this,
+ $dst$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ RegSet::of($dst$$Register, $src$$Register) /* preserve */);
+
+ __ z_stg($src$$Register, Address($dst$$Register));
+
+ write_barrier_post(masm, this,
+ $dst$$Register, /* store_addr */
+ $src$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ __ block_comment("} g1StoreP");
+ %}
+ ins_pipe(pipe_class_dummy);
+%}
+
+// Store Compressed Pointer
+instruct g1StoreN(indirect mem, iRegN_P2N src, iRegL tmp1, iRegL tmp2, iRegL tmp3, flagsReg cr) %{
+ predicate(UseG1GC && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreN mem src));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(MEMORY_REF_COST);
+ format %{ "STY $src,$mem\t # (cOop)" %}
+ ins_encode %{
+ __ block_comment("g1StoreN {");
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+
+ __ z_sty($src$$Register, Address($mem$$Register));
+
+ if ((barrier_data() & G1C2BarrierPost) != 0) {
+ if ((barrier_data() & G1C2BarrierPostNotNull) == 0) {
+ __ oop_decoder($tmp1$$Register, $src$$Register, true /* maybe_null */);
+ } else {
+ __ oop_decoder($tmp1$$Register, $src$$Register, false /* maybe_null */);
+ }
+ }
+
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ __ block_comment("} g1StoreN");
+ %}
+
+ ins_pipe(pipe_class_dummy);
+%}
+
+instruct g1CompareAndSwapN(indirect mem_ptr, rarg5RegN oldval, iRegN_P2N newval, iRegI res, iRegL tmp1, iRegL tmp2, iRegL tmp3, flagsReg cr) %{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval)));
+ match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval)));
+ effect(USE mem_ptr, TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, USE_KILL oldval, KILL cr);
+ format %{ "$res = CompareAndSwapN $oldval,$newval,$mem_ptr" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem_ptr$$Register);
+ assert_different_registers($newval$$Register, $mem_ptr$$Register);
+ __ block_comment("g1compareAndSwapN {");
+
+ Register Rcomp = reg_to_register_object($oldval$$reg);
+ Register Rnew = reg_to_register_object($newval$$reg);
+ Register Raddr = reg_to_register_object($mem_ptr$$reg);
+ Register Rres = reg_to_register_object($res$$reg);
+
+ write_barrier_pre(masm, this,
+ Raddr /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ RegSet::of(Raddr, Rcomp, Rnew) /* preserve */,
+ RegSet::of(Rres) /* no_preserve */);
+
+ __ z_cs(Rcomp, Rnew, 0, Raddr);
+
+ assert_different_registers(Rres, Raddr);
+ if (VM_Version::has_LoadStoreConditional()) {
+ __ load_const_optimized(Z_R0_scratch, 0L); // false (failed)
+ __ load_const_optimized(Rres, 1L); // true (succeed)
+ __ z_locgr(Rres, Z_R0_scratch, Assembler::bcondNotEqual);
+ } else {
+ Label done;
+ __ load_const_optimized(Rres, 0L); // false (failed)
+ __ z_brne(done); // Assume true to be the common case.
+ __ load_const_optimized(Rres, 1L); // true (succeed)
+ __ bind(done);
+ }
+
+ __ oop_decoder($tmp3$$Register, Rnew, true /* maybe_null */);
+
+ write_barrier_post(masm, this,
+ Raddr /* store_addr */,
+ $tmp3$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ __ block_comment("} g1compareAndSwapN");
+ %}
+ ins_pipe(pipe_class_dummy);
+%}
+
+instruct g1CompareAndExchangeN(iRegP mem_ptr, rarg5RegN oldval, iRegN_P2N newval, iRegN res, iRegL tmp1, iRegL tmp2, iRegL tmp3, flagsReg cr) %{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndExchangeN mem_ptr (Binary oldval newval)));
+ effect(USE mem_ptr, TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, USE_KILL oldval, KILL cr);
+ format %{ "$res = CompareAndExchangeN $oldval,$newval,$mem_ptr" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem_ptr$$Register);
+ assert_different_registers($newval$$Register, $mem_ptr$$Register);
+ __ block_comment("g1CompareAndExchangeN {");
+ write_barrier_pre(masm, this,
+ $mem_ptr$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ RegSet::of($mem_ptr$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+
+ Register Rcomp = reg_to_register_object($oldval$$reg);
+ Register Rnew = reg_to_register_object($newval$$reg);
+ Register Raddr = reg_to_register_object($mem_ptr$$reg);
+
+ Register Rres = reg_to_register_object($res$$reg);
+ assert_different_registers(Rres, Raddr);
+
+ __ z_lgr(Rres, Rcomp); // previous contents
+ __ z_csy(Rres, Rnew, 0, Raddr); // Try to store new value.
+
+ __ oop_decoder($tmp1$$Register, Rnew, true /* maybe_null */);
+
+ write_barrier_post(masm, this,
+ Raddr /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ __ block_comment("} g1CompareAndExchangeN");
+ %}
+ ins_pipe(pipe_class_dummy);
+%}
+
+// Load narrow oop
+instruct g1LoadN(iRegN dst, indirect mem, iRegP tmp1, iRegP tmp2, flagsReg cr) %{
+ predicate(UseG1GC && n->as_Load()->barrier_data() != 0);
+ match(Set dst (LoadN mem));
+ effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(MEMORY_REF_COST);
+ format %{ "LoadN $dst,$mem\t # (cOop)" %}
+ ins_encode %{
+ __ block_comment("g1LoadN {");
+ __ z_llgf($dst$$Register, Address($mem$$Register));
+ if ((barrier_data() & G1C2BarrierPre) != 0) {
+ __ oop_decoder($tmp1$$Register, $dst$$Register, true);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register );
+ }
+ __ block_comment("} g1LoadN");
+ %}
+ ins_pipe(pipe_class_dummy);
+%}
+
+instruct g1GetAndSetN(indirect mem, iRegN dst, iRegI tmp, iRegL tmp1, iRegL tmp2, iRegL tmp3, flagsReg cr) %{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set dst (GetAndSetN mem dst));
+ effect(KILL cr, TEMP tmp, TEMP tmp1, TEMP tmp2, TEMP tmp3); // USE_DEF dst by match rule.
+ format %{ "XCHGN $dst,[$mem]\t # EXCHANGE (coop, atomic), temp $tmp" %}
+ ins_encode %{
+ __ block_comment("g1GetAndSetN {");
+ assert_different_registers($mem$$Register, $dst$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ RegSet::of($mem$$Register, $dst$$Register) /* preserve */);
+
+ Register Rdst = reg_to_register_object($dst$$reg);
+ Register Rtmp = reg_to_register_object($tmp$$reg);
+ guarantee(Rdst != Rtmp, "Fix match rule to use TEMP_DEF");
+ Label retry;
+
+ // Iterate until swap succeeds.
+ __ z_llgf(Rtmp, Address($mem$$Register)); // current contents
+ __ bind(retry);
+ // Calculate incremented value.
+ __ z_csy(Rtmp, Rdst, Address($mem$$Register)); // Try to store new value.
+ __ z_brne(retry); // Yikes, concurrent update, need to retry.
+
+ __ oop_decoder($tmp1$$Register, $dst$$Register, true /* maybe_null */);
+
+ __ z_lgr(Rdst, Rtmp); // Exchanged value from memory is return value.
+
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+
+ __ block_comment("} g1GetAndSetN");
+ %}
+ ins_pipe(pipe_class_dummy);
+%}
+
+instruct g1CompareAndSwapP(iRegP mem_ptr, rarg5RegP oldval, iRegP_N2P newval, iRegI res, iRegL tmp1, iRegL tmp2, flagsReg cr) %{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval)));
+ match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, USE mem_ptr, USE_KILL oldval, KILL cr);
+ format %{ "$res = CompareAndSwapP $oldval,$newval,$mem_ptr" %}
+ ins_encode %{
+ __ block_comment("g1CompareAndSwapP {");
+ assert_different_registers($oldval$$Register, $mem_ptr$$Register);
+ assert_different_registers($newval$$Register, $mem_ptr$$Register);
+
+ Register Rcomp = reg_to_register_object($oldval$$reg);
+ Register Rnew = reg_to_register_object($newval$$reg);
+ Register Raddr = reg_to_register_object($mem_ptr$$reg);
+ Register Rres = reg_to_register_object($res$$reg);
+
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ Rcomp /* pre_val */,
+ $tmp1$$Register /* tmp1 */,
+ RegSet::of(Raddr, Rcomp, Rnew) /* preserve */,
+ RegSet::of(Rres) /* no_preserve */);
+
+ __ z_csg(Rcomp, Rnew, 0, Raddr);
+
+ if (VM_Version::has_LoadStoreConditional()) {
+ __ load_const_optimized(Z_R0_scratch, 0L); // false (failed)
+ __ load_const_optimized(Rres, 1L); // true (succeed)
+ __ z_locgr(Rres, Z_R0_scratch, Assembler::bcondNotEqual);
+ } else {
+ Label done;
+ __ load_const_optimized(Rres, 0L); // false (failed)
+ __ z_brne(done); // Assume true to be the common case.
+ __ load_const_optimized(Rres, 1L); // true (succeed)
+ __ bind(done);
+ }
+
+ write_barrier_post(masm, this,
+ Raddr /* store_addr */,
+ Rnew /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ __ block_comment("} g1CompareAndSwapP");
+ %}
+ ins_pipe(pipe_class_dummy);
+%}
+
+instruct g1CompareAndExchangeP(iRegP mem_ptr, rarg5RegP oldval, iRegP_N2P newval, iRegP res, iRegL tmp1, iRegL tmp2, flagsReg cr) %{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndExchangeP mem_ptr (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, USE mem_ptr, USE_KILL oldval, KILL cr);
+ format %{ "$res = CompareAndExchangeP $oldval,$newval,$mem_ptr" %}
+ ins_encode %{
+ __ block_comment("g1CompareAndExchangeP {");
+ assert_different_registers($oldval$$Register, $mem_ptr$$Register);
+ assert_different_registers($newval$$Register, $mem_ptr$$Register);
+
+ // Pass $oldval to the pre-barrier (instead of loading from $mem), because
+ // $oldval is the only value that can be overwritten.
+ // The same holds for g1CompareAndSwapP.
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $oldval$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ RegSet::of($mem_ptr$$Register, $oldval$$Register, $newval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+
+ __ z_lgr($res$$Register, $oldval$$Register); // previous content
+
+ __ z_csg($oldval$$Register, $newval$$Register, 0, $mem_ptr$$reg);
+
+ write_barrier_post(masm, this,
+ $mem_ptr$$Register /* store_addr */,
+ $newval$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ __ block_comment("} g1CompareAndExchangeP");
+ %}
+ ins_pipe(pipe_class_dummy);
+%}
+
+// Load Pointer
+instruct g1LoadP(iRegP dst, memory mem, iRegL tmp1, flagsReg cr) %{
+ predicate(UseG1GC && n->as_Load()->barrier_data() != 0);
+ match(Set dst (LoadP mem));
+ effect(TEMP dst, TEMP tmp1, KILL cr);
+ ins_cost(MEMORY_REF_COST);
+ format %{ "LG $dst,$mem\t # ptr" %}
+ ins_encode %{
+ __ block_comment("g1LoadP {");
+ __ z_lg($dst$$Register, $mem$$Address);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $dst$$Register /* pre_val */,
+ $tmp1$$Register );
+ __ block_comment("} g1LoadP");
+ %}
+ ins_pipe(pipe_class_dummy);
+%}
+
+instruct g1GetAndSetP(indirect mem, iRegP dst, iRegL tmp, iRegL tmp1, iRegL tmp2, flagsReg cr) %{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set dst (GetAndSetP mem dst));
+ effect(KILL cr, TEMP tmp, TEMP tmp1, TEMP tmp2); // USE_DEF dst by match rule.
+ format %{ "XCHGP $dst,[$mem]\t # EXCHANGE (oop, atomic), temp $tmp" %}
+ ins_encode %{
+ __ block_comment("g1GetAndSetP {");
+
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp$$Register /* pre_val (as a temporary register) */,
+ $tmp1$$Register /* tmp1 */,
+ RegSet::of($mem$$Register, $dst$$Register) /* preserve */);
+
+ __ z_lgr($tmp1$$Register, $dst$$Register);
+ Register Rdst = reg_to_register_object($dst$$reg);
+ Register Rtmp = reg_to_register_object($tmp$$reg);
+ guarantee(Rdst != Rtmp, "Fix match rule to use TEMP_DEF");
+ Label retry;
+
+ // Iterate until swap succeeds.
+ __ z_lg(Rtmp, Address($mem$$Register)); // current contents
+ __ bind(retry);
+ // Calculate incremented value.
+ __ z_csg(Rtmp, Rdst, Address($mem$$Register)); // Try to store new value.
+ __ z_brne(retry); // Yikes, concurrent update, need to retry.
+ __ z_lgr(Rdst, Rtmp); // Exchanged value from memory is return value.
+
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp$$Register /* tmp2 */);
+ __ block_comment("} g1GetAndSetP");
+ %}
+ ins_pipe(pipe_class_dummy);
+%}
+
+instruct g1EncodePAndStoreN(indirect mem, iRegP src, iRegL tmp1, iRegL tmp2, flagsReg cr)
+%{
+ predicate(UseG1GC && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreN mem (EncodeP src)));
+ effect(TEMP tmp1, TEMP tmp2, KILL cr);
+ // ins_cost(INSN_COST);
+ format %{ "encode_heap_oop $tmp1, $src\n\t"
+ "st $tmp1, $mem\t# compressed ptr" %}
+ ins_encode %{
+ __ block_comment("g1EncodePAndStoreN {");
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp1 */,
+ RegSet::of($mem$$Register, $src$$Register) /* preserve */);
+ if ((barrier_data() & G1C2BarrierPostNotNull) == 0) {
+ __ oop_encoder($tmp1$$Register, $src$$Register, true /* maybe_null */);
+ } else {
+ __ oop_encoder($tmp1$$Register, $src$$Register, false /* maybe_null */);
+ }
+ __ z_st($tmp1$$Register, Address($mem$$Register));
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $src$$Register /* new_val */,
+ $tmp1$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ __ block_comment("} g1EncodePAndStoreN");
+ %}
+ ins_pipe(pipe_class_dummy);
+%}
diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp
index d3457916bc9..d826b4a06f3 100644
--- a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp
+++ b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp
@@ -33,6 +33,9 @@
#include "runtime/jniHandles.hpp"
#include "runtime/stubRoutines.hpp"
#include "utilities/macros.hpp"
+#ifdef COMPILER2
+#include "gc/shared/c2/barrierSetC2.hpp"
+#endif // COMPILER2
#define __ masm->
@@ -105,16 +108,60 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators
}
}
+// Generic implementation. GCs can provide an optimized one.
void BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2) {
- NearLabel Ldone;
- __ z_ltgr(tmp1, value);
- __ z_bre(Ldone); // Use null result as-is.
- __ z_nill(value, ~JNIHandles::tag_mask);
- __ z_lg(value, 0, value); // Resolve (untagged) jobject.
+ assert_different_registers(value, tmp1, tmp2);
+ NearLabel done, weak_tag, verify, tagged;
+ __ z_ltgr(value, value);
+ __ z_bre(done); // Use null result as-is.
+
+ __ z_tmll(value, JNIHandles::tag_mask);
+ __ z_btrue(tagged); // not zero
+
+ // Resolve Local handle
+ __ access_load_at(T_OBJECT, IN_NATIVE | AS_RAW, Address(value, 0), value, tmp1, tmp2);
+ __ z_bru(verify);
+
+ __ bind(tagged);
+ __ testbit(value, exact_log2(JNIHandles::TypeTag::weak_global)); // test for weak tag
+ __ z_btrue(weak_tag);
+
+ // resolve global handle
+ __ access_load_at(T_OBJECT, IN_NATIVE, Address(value, -JNIHandles::TypeTag::global), value, tmp1, tmp2);
+ __ z_bru(verify);
+
+ __ bind(weak_tag);
+ // resolve jweak.
+ __ access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF,
+ Address(value, -JNIHandles::TypeTag::weak_global), value, tmp1, tmp2);
+ __ bind(verify);
+ __ verify_oop(value, FILE_AND_LINE);
+ __ bind(done);
+}
+
+// Generic implementation. GCs can provide an optimized one.
+void BarrierSetAssembler::resolve_global_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2) {
+ assert_different_registers(value, tmp1, tmp2);
+ NearLabel done;
+
+ __ z_ltgr(value, value);
+ __ z_bre(done); // use null as-is.
+#ifdef ASSERT
+ {
+ NearLabel valid_global_tag;
+ __ testbit(value, exact_log2(JNIHandles::TypeTag::global)); // test for global tag
+ __ z_btrue(valid_global_tag);
+ __ stop("non global jobject using resolve_global_jobject");
+ __ bind(valid_global_tag);
+ }
+#endif // ASSERT
+
+ // Resolve global handle
+ __ access_load_at(T_OBJECT, IN_NATIVE, Address(value, -JNIHandles::TypeTag::global), value, tmp1, tmp2);
__ verify_oop(value, FILE_AND_LINE);
- __ bind(Ldone);
+ __ bind(done);
}
void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
@@ -150,8 +197,93 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) {
#ifdef COMPILER2
-OptoReg::Name BarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) {
- Unimplemented(); // This must be implemented to support late barrier expansion.
+OptoReg::Name BarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) const {
+ if (!OptoReg::is_reg(opto_reg)) {
+ return OptoReg::Bad;
+ }
+
+ VMReg vm_reg = OptoReg::as_VMReg(opto_reg);
+ if ((vm_reg->is_Register() || vm_reg ->is_FloatRegister()) && (opto_reg & 1) != 0) {
+ return OptoReg::Bad;
+ }
+
+ return opto_reg;
+}
+
+#undef __
+#define __ _masm->
+
+SaveLiveRegisters::SaveLiveRegisters(MacroAssembler *masm, BarrierStubC2 *stub)
+ : _masm(masm), _reg_mask(stub->preserve_set()) {
+
+ const int register_save_size = iterate_over_register_mask(ACTION_COUNT_ONLY) * BytesPerWord;
+
+ _frame_size = align_up(register_save_size, frame::alignment_in_bytes) + frame::z_abi_160_size; // FIXME: this could be restricted to argument only
+
+ __ save_return_pc();
+ __ push_frame(_frame_size, Z_R14); // FIXME: check if Z_R1_scaratch can do a job here;
+
+ __ z_lg(Z_R14, _z_common_abi(return_pc) + _frame_size, Z_SP);
+
+ iterate_over_register_mask(ACTION_SAVE, _frame_size);
+}
+
+SaveLiveRegisters::~SaveLiveRegisters() {
+ iterate_over_register_mask(ACTION_RESTORE, _frame_size);
+
+ __ pop_frame();
+
+ __ restore_return_pc();
+}
+
+int SaveLiveRegisters::iterate_over_register_mask(IterationAction action, int offset) {
+ int reg_save_index = 0;
+ RegMaskIterator live_regs_iterator(_reg_mask);
+
+ while(live_regs_iterator.has_next()) {
+ const OptoReg::Name opto_reg = live_regs_iterator.next();
+
+ // Filter out stack slots (spilled registers, i.e., stack-allocated registers).
+ if (!OptoReg::is_reg(opto_reg)) {
+ continue;
+ }
+
+ const VMReg vm_reg = OptoReg::as_VMReg(opto_reg);
+ if (vm_reg->is_Register()) {
+ Register std_reg = vm_reg->as_Register();
+
+ if (std_reg->encoding() >= Z_R2->encoding() && std_reg->encoding() <= Z_R15->encoding()) {
+ reg_save_index++;
+
+ if (action == ACTION_SAVE) {
+ __ z_stg(std_reg, offset - reg_save_index * BytesPerWord, Z_SP);
+ } else if (action == ACTION_RESTORE) {
+ __ z_lg(std_reg, offset - reg_save_index * BytesPerWord, Z_SP);
+ } else {
+ assert(action == ACTION_COUNT_ONLY, "Sanity");
+ }
+ }
+ } else if (vm_reg->is_FloatRegister()) {
+ FloatRegister fp_reg = vm_reg->as_FloatRegister();
+ if (fp_reg->encoding() >= Z_F0->encoding() && fp_reg->encoding() <= Z_F15->encoding()
+ && fp_reg->encoding() != Z_F1->encoding()) {
+ reg_save_index++;
+
+ if (action == ACTION_SAVE) {
+ __ z_std(fp_reg, offset - reg_save_index * BytesPerWord, Z_SP);
+ } else if (action == ACTION_RESTORE) {
+ __ z_ld(fp_reg, offset - reg_save_index * BytesPerWord, Z_SP);
+ } else {
+ assert(action == ACTION_COUNT_ONLY, "Sanity");
+ }
+ }
+ } else if (false /* vm_reg->is_VectorRegister() */){
+ fatal("Vector register support is not there yet!");
+ } else {
+ fatal("Register type is not known");
+ }
+ }
+ return reg_save_index;
}
#endif // COMPILER2
diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp
index f83bbb864ea..fb61adc55b5 100644
--- a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp
+++ b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp
@@ -32,7 +32,9 @@
#ifdef COMPILER2
#include "code/vmreg.hpp"
#include "opto/optoreg.hpp"
+#include "opto/regmask.hpp"
+class BarrierStubC2;
class Node;
#endif // COMPILER2
@@ -51,6 +53,7 @@ class BarrierSetAssembler: public CHeapObj {
const Address& addr, Register val, Register tmp1, Register tmp2, Register tmp3);
virtual void resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2);
+ virtual void resolve_global_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2);
virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
Register obj, Register tmp, Label& slowpath);
@@ -61,8 +64,42 @@ class BarrierSetAssembler: public CHeapObj {
#ifdef COMPILER2
OptoReg::Name refine_register(const Node* node,
- OptoReg::Name opto_reg);
+ OptoReg::Name opto_reg) const;
#endif // COMPILER2
};
+#ifdef COMPILER2
+
+// This class saves and restores the registers that need to be preserved across
+// the runtime call represented by a given C2 barrier stub. Use as follows:
+// {
+// SaveLiveRegisters save(masm, stub);
+// ..
+// __ call_VM_leaf(...);
+// ..
+// }
+
+class SaveLiveRegisters {
+ MacroAssembler* _masm;
+ RegMask _reg_mask;
+ Register _result_reg;
+ int _frame_size;
+
+ public:
+ SaveLiveRegisters(MacroAssembler *masm, BarrierStubC2 *stub);
+
+ ~SaveLiveRegisters();
+
+ private:
+ enum IterationAction : int {
+ ACTION_SAVE,
+ ACTION_RESTORE,
+ ACTION_COUNT_ONLY
+ };
+
+ int iterate_over_register_mask(IterationAction action, int offset = 0);
+};
+
+#endif // COMPILER2
+
#endif // CPU_S390_GC_SHARED_BARRIERSETASSEMBLER_S390_HPP
diff --git a/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.cpp
index fd21dd85e11..f44a72c27ab 100644
--- a/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.cpp
+++ b/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018, 2019 SAP SE. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "gc/shared/modRefBarrierSetAssembler.hpp"
+#include "runtime/jniHandles.hpp"
#define __ masm->
@@ -58,3 +59,16 @@ void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet deco
BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
}
}
+
+void ModRefBarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2) {
+ NearLabel done;
+
+ __ z_ltgr(value, value);
+ __ z_bre(done); // use null as-is.
+
+ __ z_nill(value, ~JNIHandles::tag_mask);
+ __ z_lg(value, 0, value); // Resolve (untagged) jobject.
+
+ __ verify_oop(value, FILE_AND_LINE);
+ __ bind(done);
+}
diff --git a/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.hpp b/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.hpp
index 865638477cd..7f53d033780 100644
--- a/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.hpp
+++ b/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018 SAP SE. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -48,6 +48,8 @@ class ModRefBarrierSetAssembler: public BarrierSetAssembler {
virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3);
+
+ virtual void resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2);
};
#endif // CPU_S390_GC_SHARED_MODREFBARRIERSETASSEMBLER_S390_HPP
diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp
index 14bb98cea6a..d00b6c3e2cc 100644
--- a/src/hotspot/cpu/s390/interp_masm_s390.cpp
+++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp
@@ -1007,12 +1007,12 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp, object);
- testbit(Address(tmp, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS));
+ z_tm(Address(tmp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class);
z_btrue(slow_case);
}
if (LockingMode == LM_LIGHTWEIGHT) {
- lightweight_lock(object, header, tmp, slow_case);
+ lightweight_lock(monitor, object, header, tmp, slow_case);
} else if (LockingMode == LM_LEGACY) {
// Load markWord from object into header.
@@ -1072,16 +1072,9 @@ 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);
- 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);
- }
+ call_VM(noreg,
+ CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter),
+ monitor);
// }
bind(done);
diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp
index 66d6f25f0fd..6bfe5125959 100644
--- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp
+++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2024 SAP SE. All rights reserved.
+ * Copyright 2024 IBM Corporation. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -2126,8 +2127,9 @@ unsigned int MacroAssembler::push_frame_abi160(unsigned int bytes) {
// Pop current C frame.
void MacroAssembler::pop_frame() {
- BLOCK_COMMENT("pop_frame:");
+ BLOCK_COMMENT("pop_frame {");
Assembler::z_lg(Z_SP, _z_abi(callers_sp), Z_SP);
+ BLOCK_COMMENT("} pop_frame");
}
// Pop current C frame and restore return PC register (Z_R14).
@@ -2750,7 +2752,7 @@ void MacroAssembler::reserved_stack_check(Register return_pc) {
pop_frame();
restore_return_pc();
- load_const_optimized(Z_R1, StubRoutines::throw_delayed_StackOverflowError_entry());
+ load_const_optimized(Z_R1, SharedRuntime::throw_delayed_StackOverflowError_entry());
// Don't use call() or z_basr(), they will invalidate Z_R14 which contains the return pc.
z_br(Z_R1);
@@ -3152,6 +3154,301 @@ void MacroAssembler::check_klass_subtype(Register sub_klass,
BLOCK_COMMENT("} check_klass_subtype");
}
+// scans r_count pointer sized words at [r_addr] for occurrence of r_value,
+// generic (r_count must be >0)
+// iff found: CC eq, r_result == 0
+void MacroAssembler::repne_scan(Register r_addr, Register r_value, Register r_count, Register r_result) {
+ NearLabel L_loop, L_exit;
+
+ BLOCK_COMMENT("repne_scan {");
+#ifdef ASSERT
+ z_chi(r_count, 0);
+ asm_assert(bcondHigh, "count must be positive", 11);
+#endif
+
+ clear_reg(r_result, true /* whole_reg */, false /* set_cc */); // sets r_result=0, let's hope that search will be successful
+
+ bind(L_loop);
+ z_cg(r_value, Address(r_addr));
+ z_bre(L_exit); // branch on success
+ z_la(r_addr, wordSize, r_addr);
+ z_brct(r_count, L_loop);
+
+ // z_brct above doesn't change CC.
+ // If we reach here, then the value in r_value is not present. Set r_result to 1.
+ z_lghi(r_result, 1);
+
+ bind(L_exit);
+ BLOCK_COMMENT("} repne_scan");
+}
+
+// Ensure that the inline code and the stub are using the same registers.
+#define LOOKUP_SECONDARY_SUPERS_TABLE_REGISTERS \
+do { \
+ assert(r_super_klass == Z_ARG1 && \
+ r_array_base == Z_ARG5 && \
+ r_array_length == Z_ARG4 && \
+ (r_array_index == Z_ARG3 || r_array_index == noreg) && \
+ (r_sub_klass == Z_ARG2 || r_sub_klass == noreg) && \
+ (r_bitmap == Z_R10 || r_bitmap == noreg) && \
+ (r_result == Z_R11 || r_result == noreg), "registers must match s390.ad"); \
+} while(0)
+
+// Note: this method also kills Z_R1_scratch register on machines older than z15
+void MacroAssembler::lookup_secondary_supers_table(Register r_sub_klass,
+ Register r_super_klass,
+ Register r_temp1,
+ Register r_temp2,
+ Register r_temp3,
+ Register r_temp4,
+ Register r_result,
+ u1 super_klass_slot) {
+ NearLabel L_done, L_failure;
+
+ BLOCK_COMMENT("lookup_secondary_supers_table {");
+
+ const Register
+ r_array_base = r_temp1,
+ r_array_length = r_temp2,
+ r_array_index = r_temp3,
+ r_bitmap = r_temp4;
+
+ LOOKUP_SECONDARY_SUPERS_TABLE_REGISTERS;
+
+ z_lg(r_bitmap, Address(r_sub_klass, Klass::bitmap_offset()));
+
+ // First check the bitmap to see if super_klass might be present. If
+ // the bit is zero, we are certain that super_klass is not one of
+ // the secondary supers.
+ u1 bit = super_klass_slot;
+ int shift_count = Klass::SECONDARY_SUPERS_TABLE_MASK - bit;
+
+ z_sllg(r_array_index, r_bitmap, shift_count); // take the bit to 63rd location
+
+ // Initialize r_result with 0 (indicating success). If searching fails, r_result will be loaded
+ // with 1 (failure) at the end of this method.
+ clear_reg(r_result, true /* whole_reg */, false /* set_cc */); // r_result = 0
+
+ // We test the MSB of r_array_index, i.e., its sign bit
+ testbit(r_array_index, 63);
+ z_bfalse(L_failure); // if not set, then jump!!!
+
+ // We will consult the secondary-super array.
+ z_lg(r_array_base, Address(r_sub_klass, Klass::secondary_supers_offset()));
+
+ // The value i in r_array_index is >= 1, so even though r_array_base
+ // points to the length, we don't need to adjust it to point to the
+ // data.
+ assert(Array::base_offset_in_bytes() == wordSize, "Adjust this code");
+
+ // Get the first array index that can contain super_klass.
+ if (bit != 0) {
+ pop_count_long(r_array_index, r_array_index, Z_R1_scratch); // kills Z_R1_scratch on machines older than z15
+
+ // NB! r_array_index is off by 1. It is compensated by keeping r_array_base off by 1 word.
+ z_sllg(r_array_index, r_array_index, LogBytesPerWord); // scale
+ } else {
+ // Actually use index 0, but r_array_base and r_array_index are off by 1 word
+ // such that the sum is precise.
+ z_lghi(r_array_index, BytesPerWord); // for slow path (scaled)
+ }
+
+ z_cg(r_super_klass, Address(r_array_base, r_array_index));
+ branch_optimized(bcondEqual, L_done); // found a match; success
+
+ // Is there another entry to check? Consult the bitmap.
+ testbit(r_bitmap, (bit + 1) & Klass::SECONDARY_SUPERS_TABLE_MASK);
+ z_bfalse(L_failure);
+
+ // Linear probe. Rotate the bitmap so that the next bit to test is
+ // in Bit 2 for the look-ahead check in the slow path.
+ if (bit != 0) {
+ z_rllg(r_bitmap, r_bitmap, 64-bit); // rotate right
+ }
+
+ // Calls into the stub generated by lookup_secondary_supers_table_slow_path.
+ // Arguments: r_super_klass, r_array_base, r_array_index, r_bitmap.
+ // Kills: r_array_length.
+ // Returns: r_result
+
+ call_stub(StubRoutines::lookup_secondary_supers_table_slow_path_stub());
+
+ z_bru(L_done); // pass whatever result we got from a slow path
+
+ bind(L_failure);
+ // TODO: use load immediate on condition and z_bru above will not be required
+ z_lghi(r_result, 1);
+
+ bind(L_done);
+ BLOCK_COMMENT("} lookup_secondary_supers_table");
+
+ if (VerifySecondarySupers) {
+ verify_secondary_supers_table(r_sub_klass, r_super_klass, r_result,
+ r_temp1, r_temp2, r_temp3);
+ }
+}
+
+// Called by code generated by check_klass_subtype_slow_path
+// above. This is called when there is a collision in the hashed
+// lookup in the secondary supers array.
+void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_klass,
+ Register r_array_base,
+ Register r_array_index,
+ Register r_bitmap,
+ Register r_result,
+ Register r_temp1) {
+ assert_different_registers(r_super_klass, r_array_base, r_array_index, r_bitmap, r_result, r_temp1);
+
+ const Register
+ r_array_length = r_temp1,
+ r_sub_klass = noreg;
+
+ LOOKUP_SECONDARY_SUPERS_TABLE_REGISTERS;
+
+ BLOCK_COMMENT("lookup_secondary_supers_table_slow_path {");
+ NearLabel L_done, L_failure;
+
+ // Load the array length.
+ z_llgf(r_array_length, Address(r_array_base, Array::length_offset_in_bytes()));
+
+ // And adjust the array base to point to the data.
+ // NB!
+ // Effectively increments the current slot index by 1.
+ assert(Array::base_offset_in_bytes() == wordSize, "");
+ add2reg(r_array_base, Array::base_offset_in_bytes());
+
+ // Linear probe
+ NearLabel L_huge;
+
+ // The bitmap is full to bursting.
+ z_chi(r_array_length, Klass::SECONDARY_SUPERS_BITMAP_FULL - 2);
+ z_brh(L_huge);
+
+ // NB! Our caller has checked bits 0 and 1 in the bitmap. The
+ // current slot (at secondary_supers[r_array_index]) has not yet
+ // been inspected, and r_array_index may be out of bounds if we
+ // wrapped around the end of the array.
+
+ { // This is conventional linear probing, but instead of terminating
+ // when a null entry is found in the table, we maintain a bitmap
+ // in which a 0 indicates missing entries.
+ // The check above guarantees there are 0s in the bitmap, so the loop
+ // eventually terminates.
+
+#ifdef ASSERT
+ // r_result is set to 0 by lookup_secondary_supers_table.
+ // clear_reg(r_result, true /* whole_reg */, false /* set_cc */);
+ z_cghi(r_result, 0);
+ asm_assert(bcondEqual, "r_result required to be 0, used by z_locgr", 44);
+
+ // We should only reach here after having found a bit in the bitmap.
+ z_ltgr(r_array_length, r_array_length);
+ asm_assert(bcondHigh, "array_length > 0, should hold", 22);
+#endif // ASSERT
+
+ // Compute limit in r_array_length
+ add2reg(r_array_length, -1);
+ z_sllg(r_array_length, r_array_length, LogBytesPerWord);
+
+ NearLabel L_loop;
+ bind(L_loop);
+
+ // Check for wraparound.
+ z_cgr(r_array_index, r_array_length);
+ z_locgr(r_array_index, r_result, bcondHigh); // r_result is containing 0
+
+ z_cg(r_super_klass, Address(r_array_base, r_array_index));
+ z_bre(L_done); // success
+
+ // look-ahead check: if Bit 2 is 0, we're done
+ testbit(r_bitmap, 2);
+ z_bfalse(L_failure);
+
+ z_rllg(r_bitmap, r_bitmap, 64-1); // rotate right
+ add2reg(r_array_index, BytesPerWord);
+
+ z_bru(L_loop);
+ }
+
+ { // Degenerate case: more than 64 secondary supers.
+ // FIXME: We could do something smarter here, maybe a vectorized
+ // comparison or a binary search, but is that worth any added
+ // complexity?
+
+ bind(L_huge);
+ repne_scan(r_array_base, r_super_klass, r_array_length, r_result);
+
+ z_bru(L_done); // forward the result we got from repne_scan
+ }
+
+ bind(L_failure);
+ z_lghi(r_result, 1);
+
+ bind(L_done);
+ BLOCK_COMMENT("} lookup_secondary_supers_table_slow_path");
+}
+
+// Make sure that the hashed lookup and a linear scan agree.
+void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass,
+ Register r_super_klass,
+ Register r_result /* expected */,
+ Register r_temp1,
+ Register r_temp2,
+ Register r_temp3) {
+ assert_different_registers(r_sub_klass, r_super_klass, r_result, r_temp1, r_temp2, r_temp3);
+
+ const Register
+ r_array_base = r_temp1,
+ r_array_length = r_temp2,
+ r_array_index = r_temp3,
+ r_bitmap = noreg; // unused
+
+ const Register r_one = Z_R0_scratch;
+ z_lghi(r_one, 1); // for locgr down there, to a load result for failure
+
+ LOOKUP_SECONDARY_SUPERS_TABLE_REGISTERS;
+
+ BLOCK_COMMENT("verify_secondary_supers_table {");
+
+ Label L_passed, L_failure;
+
+ // We will consult the secondary-super array.
+ z_lg(r_array_base, Address(r_sub_klass, in_bytes(Klass::secondary_supers_offset())));
+
+ // Load the array length.
+ z_llgf(r_array_length, Address(r_array_base, Array::length_offset_in_bytes()));
+
+ // And adjust the array base to point to the data.
+ z_aghi(r_array_base, Array::base_offset_in_bytes());
+
+ const Register r_linear_result = r_array_index; // reuse
+ z_chi(r_array_length, 0);
+ z_locgr(r_linear_result, r_one, bcondNotHigh); // load failure if array_length <= 0
+ z_brc(bcondNotHigh, L_failure);
+ repne_scan(r_array_base, r_super_klass, r_array_length, r_linear_result);
+ bind(L_failure);
+
+ z_cr(r_result, r_linear_result);
+ z_bre(L_passed);
+
+ assert_different_registers(Z_ARG1, r_sub_klass, r_linear_result, r_result);
+ lgr_if_needed(Z_ARG1, r_super_klass);
+ assert_different_registers(Z_ARG2, r_linear_result, r_result);
+ lgr_if_needed(Z_ARG2, r_sub_klass);
+ assert_different_registers(Z_ARG3, r_result);
+ z_lgr(Z_ARG3, r_linear_result);
+ z_lgr(Z_ARG4, r_result);
+ const char* msg = "mismatch";
+ load_const_optimized(Z_ARG5, (address)msg);
+
+ call_VM_leaf(CAST_FROM_FN_PTR(address, Klass::on_secondary_supers_verification_failure));
+ should_not_reach_here();
+
+ bind(L_passed);
+
+ BLOCK_COMMENT("} verify_secondary_supers_table");
+}
+
void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fast_path, Label* L_slow_path) {
assert(L_fast_path != nullptr || L_slow_path != nullptr, "at least one is required");
@@ -3162,7 +3459,8 @@ void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fa
L_slow_path = &L_fallthrough;
}
- // Fast path check: class is fully initialized
+ // Fast path check: class is fully initialized.
+ // init_state needs acquire, but S390 is TSO, and so we are already good.
z_cli(Address(klass, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized);
z_bre(*L_fast_path);
@@ -3211,9 +3509,7 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(temp, oop);
- z_l(temp, Address(temp, Klass::access_flags_offset()));
- assert((JVM_ACC_IS_VALUE_BASED_CLASS & 0xFFFF) == 0, "or change following instruction");
- z_nilh(temp, JVM_ACC_IS_VALUE_BASED_CLASS >> 16);
+ z_tm(Address(temp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class);
z_brne(done);
}
@@ -3361,12 +3657,38 @@ void MacroAssembler::compiler_fast_unlock_object(Register oop, Register box, Reg
bind(not_recursive);
+ NearLabel check_succ, set_eq_unlocked;
+
+ // Set owner to null.
+ // Release to satisfy the JMM
+ z_release();
+ z_lghi(temp, 0);
+ z_stg(temp, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), currentHeader);
+ // We need a full fence after clearing owner to avoid stranding.
+ z_fence();
+
+ // Check if the entry lists are empty.
load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)));
- z_brne(done);
+ z_brne(check_succ);
load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)));
- z_brne(done);
- z_release();
- z_stg(temp/*=0*/, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), currentHeader);
+ z_bre(done); // If so we are done.
+
+ bind(check_succ);
+
+ // Check if there is a successor.
+ load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)));
+ z_brne(set_eq_unlocked); // If so we are done.
+
+ // Save the monitor pointer in the current thread, so we can try to
+ // reacquire the lock in SharedRuntime::monitor_exit_helper().
+ z_xilf(currentHeader, markWord::monitor_value);
+ z_stg(currentHeader, Address(Z_thread, JavaThread::unlocked_inflated_monitor_offset()));
+
+ z_ltgr(oop, oop); // Set flag = NE
+ z_bru(done);
+
+ bind(set_eq_unlocked);
+ z_cr(temp, temp); // Set flag = EQ
bind(done);
@@ -3380,6 +3702,11 @@ void MacroAssembler::resolve_jobject(Register value, Register tmp1, Register tmp
bs->resolve_jobject(this, value, tmp1, tmp2);
}
+void MacroAssembler::resolve_global_jobject(Register value, Register tmp1, Register tmp2) {
+ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->resolve_global_jobject(this, value, tmp1, tmp2);
+}
+
// Last_Java_sp must comply to the rules in frame_s390.hpp.
void MacroAssembler::set_last_Java_frame(Register last_Java_sp, Register last_Java_pc, bool allow_relocation) {
BLOCK_COMMENT("set_last_Java_frame {");
@@ -5708,10 +6035,10 @@ SkipIfEqual::~SkipIfEqual() {
// - obj: the object to be locked, contents preserved.
// - temp1, temp2: temporary registers, contents destroyed.
// Note: make sure Z_R1 is not manipulated here when C2 compiler is in play
-void MacroAssembler::lightweight_lock(Register obj, Register temp1, Register temp2, Label& slow) {
+void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Register temp1, Register temp2, Label& slow) {
assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking");
- assert_different_registers(obj, temp1, temp2);
+ assert_different_registers(basic_lock, obj, temp1, temp2);
Label push;
const Register top = temp1;
@@ -5723,6 +6050,11 @@ void MacroAssembler::lightweight_lock(Register obj, Register temp1, Register tem
// instruction emitted as it is part of C1's null check semantics.
z_lg(mark, Address(obj, mark_offset));
+ if (UseObjectMonitorTable) {
+ // Clear cache in case fast locking succeeds.
+ const Address om_cache_addr = Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes())));
+ z_mvghi(om_cache_addr, 0);
+ }
// First we need to check if the lock-stack has room for pushing the object reference.
z_lgf(top, Address(Z_thread, ls_top_offset));
@@ -5846,8 +6178,8 @@ void MacroAssembler::lightweight_unlock(Register obj, Register temp1, Register t
bind(unlocked);
}
-void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Register tmp1, Register tmp2) {
- assert_different_registers(obj, tmp1, tmp2);
+void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Register box, Register tmp1, Register tmp2) {
+ assert_different_registers(obj, box, tmp1, tmp2);
// Handle inflated monitor.
NearLabel inflated;
@@ -5856,11 +6188,14 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Registe
// Finish fast lock unsuccessfully. MUST branch to with flag == EQ
NearLabel slow_path;
+ if (UseObjectMonitorTable) {
+ // Clear cache in case fast locking succeeds.
+ z_mvghi(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0);
+ }
+
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp1, obj);
- z_l(tmp1, Address(tmp1, Klass::access_flags_offset()));
- assert((JVM_ACC_IS_VALUE_BASED_CLASS & 0xFFFF) == 0, "or change following instruction");
- z_nilh(tmp1, JVM_ACC_IS_VALUE_BASED_CLASS >> 16);
+ z_tm(Address(tmp1, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class);
z_brne(slow_path);
}
@@ -5922,26 +6257,77 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Registe
{ // Handle inflated monitor.
bind(inflated);
+ const Register tmp1_monitor = tmp1;
+ if (!UseObjectMonitorTable) {
+ assert(tmp1_monitor == mark, "should be the same here");
+ } else {
+ NearLabel monitor_found;
+
+ // load cache address
+ z_la(tmp1, Address(Z_thread, JavaThread::om_cache_oops_offset()));
+
+ const int num_unrolled = 2;
+ for (int i = 0; i < num_unrolled; i++) {
+ z_cg(obj, Address(tmp1));
+ z_bre(monitor_found);
+ add2reg(tmp1, in_bytes(OMCache::oop_to_oop_difference()));
+ }
+
+ NearLabel loop;
+ // Search for obj in cache
+
+ bind(loop);
+
+ // check for match.
+ z_cg(obj, Address(tmp1));
+ z_bre(monitor_found);
+
+ // search until null encountered, guaranteed _null_sentinel at end.
+ add2reg(tmp1, in_bytes(OMCache::oop_to_oop_difference()));
+ z_cghsi(0, tmp1, 0);
+ z_brne(loop); // if not EQ to 0, go for another loop
+
+ // we reached to the end, cache miss
+ z_ltgr(obj, obj); // set CC to NE
+ z_bru(slow_path);
+
+ // cache hit
+ bind(monitor_found);
+ z_lg(tmp1_monitor, Address(tmp1, OMCache::oop_to_monitor_difference()));
+ }
+ NearLabel monitor_locked;
+ // lock the monitor
+
// mark contains the tagged ObjectMonitor*.
const Register tagged_monitor = mark;
const Register zero = tmp2;
+ const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value));
+ const Address owner_address(tmp1_monitor, ObjectMonitor::owner_offset() - monitor_tag);
+ const Address recursions_address(tmp1_monitor, ObjectMonitor::recursions_offset() - monitor_tag);
+
+
// Try to CAS m->owner from null to current thread.
// If m->owner is null, then csg succeeds and sets m->owner=THREAD and CR=EQ.
// Otherwise, register zero is filled with the current owner.
z_lghi(zero, 0);
- z_csg(zero, Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), tagged_monitor);
- z_bre(locked);
+ z_csg(zero, Z_thread, owner_address);
+ z_bre(monitor_locked);
// Check if recursive.
z_cgr(Z_thread, zero); // zero contains the owner from z_csg instruction
z_brne(slow_path);
// Recursive
- z_agsi(Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 1ll);
- z_cgr(zero, zero);
- // z_bru(locked);
- // Uncomment above line in the future, for now jump address is right next to us.
+ z_agsi(recursions_address, 1ll);
+
+ bind(monitor_locked);
+ if (UseObjectMonitorTable) {
+ // Cache the monitor for unlock
+ z_stg(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
+ }
+ // set the CC now
+ z_cgr(obj, obj);
}
BLOCK_COMMENT("} handle_inflated_monitor_lightweight_locking");
@@ -5966,11 +6352,11 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Registe
// C2 uses the value of flag (NE vs EQ) to determine the continuation.
}
-void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Register tmp1, Register tmp2) {
- assert_different_registers(obj, tmp1, tmp2);
+void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Register box, Register tmp1, Register tmp2) {
+ assert_different_registers(obj, box, tmp1, tmp2);
// Handle inflated monitor.
- NearLabel inflated, inflated_load_monitor;
+ NearLabel inflated, inflated_load_mark;
// Finish fast unlock successfully. MUST reach to with flag == EQ.
NearLabel unlocked;
// Finish fast unlock unsuccessfully. MUST branch to with flag == NE.
@@ -5983,13 +6369,14 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis
BLOCK_COMMENT("compiler_fast_lightweight_unlock {");
{ // Lightweight Unlock
+ NearLabel push_and_slow_path;
// Check if obj is top of lock-stack.
z_lgf(top, Address(Z_thread, ls_top_offset));
z_aghi(top, -oopSize);
z_cg(obj, Address(Z_thread, top));
- branch_optimized(bcondNotEqual, inflated_load_monitor);
+ branch_optimized(bcondNotEqual, inflated_load_mark);
// Pop lock-stack.
#ifdef ASSERT
@@ -6010,9 +6397,16 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis
// Not recursive
// Check for monitor (0b10).
+ // Because we got here by popping (meaning we pushed in locked)
+ // there will be no monitor in the box. So we need to push back the obj
+ // so that the runtime can fix any potential anonymous owner.
z_lg(mark, Address(obj, mark_offset));
z_tmll(mark, markWord::monitor_value);
- z_brnaz(inflated);
+ if (!UseObjectMonitorTable) {
+ z_brnaz(inflated);
+ } else {
+ z_brnaz(push_and_slow_path);
+ }
#ifdef ASSERT
// Check header not unlocked (0b01).
@@ -6031,6 +6425,7 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis
branch_optimized(Assembler::bcondEqual, unlocked);
}
+ bind(push_and_slow_path);
// Restore lock-stack and handle the unlock in runtime.
z_lgf(top, Address(Z_thread, ls_top_offset));
DEBUG_ONLY(z_stg(obj, Address(Z_thread, top));)
@@ -6043,7 +6438,7 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis
{ // Handle inflated monitor.
- bind(inflated_load_monitor);
+ bind(inflated_load_mark);
z_lg(mark, Address(obj, mark_offset));
@@ -6068,42 +6463,77 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis
bind(check_done);
#endif // ASSERT
+ const Register tmp1_monitor = tmp1;
+
+ if (!UseObjectMonitorTable) {
+ assert(tmp1_monitor == mark, "should be the same here");
+ } else {
+ // Uses ObjectMonitorTable. Look for the monitor in our BasicLock on the stack.
+ z_lg(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
+ // null check with ZF == 0, no valid pointer below alignof(ObjectMonitor*)
+ z_cghi(tmp1_monitor, alignof(ObjectMonitor*));
+
+ z_brl(slow_path);
+ }
+
// mark contains the tagged ObjectMonitor*.
const Register monitor = mark;
+ const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value));
+ const Address recursions_address{monitor, ObjectMonitor::recursions_offset() - monitor_tag};
+ const Address cxq_address{monitor, ObjectMonitor::cxq_offset() - monitor_tag};
+ const Address succ_address{monitor, ObjectMonitor::succ_offset() - monitor_tag};
+ const Address EntryList_address{monitor, ObjectMonitor::EntryList_offset() - monitor_tag};
+ const Address owner_address{monitor, ObjectMonitor::owner_offset() - monitor_tag};
+
NearLabel not_recursive;
const Register recursions = tmp2;
// Check if recursive.
- load_and_test_long(recursions, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)));
+ load_and_test_long(recursions, recursions_address);
z_bre(not_recursive); // if 0 then jump, it's not recursive locking
// Recursive unlock
- z_agsi(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), -1ll);
+ z_agsi(recursions_address, -1ll);
z_cgr(monitor, monitor); // set the CC to EQUAL
z_bru(unlocked);
bind(not_recursive);
- NearLabel not_ok;
- // Check if the entry lists are empty.
- load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)));
- z_brne(not_ok);
- load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)));
- z_brne(not_ok);
+ NearLabel check_succ, set_eq_unlocked;
+ // Set owner to null.
+ // Release to satisfy the JMM
z_release();
- z_stg(tmp2 /*=0*/, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor);
+ z_lghi(tmp2, 0);
+ z_stg(tmp2 /*=0*/, owner_address);
+ // We need a full fence after clearing owner to avoid stranding.
+ z_fence();
+
+ // Check if the entry lists are empty.
+ load_and_test_long(tmp2, EntryList_address);
+ z_brne(check_succ);
+ load_and_test_long(tmp2, cxq_address);
+ z_bre(unlocked); // If so we are done.
+
+ bind(check_succ);
- z_bru(unlocked); // CC = EQ here
+ // Check if there is a successor.
+ load_and_test_long(tmp2, succ_address);
+ z_brne(set_eq_unlocked); // If so we are done.
- bind(not_ok);
+ // Save the monitor pointer in the current thread, so we can try to
+ // reacquire the lock in SharedRuntime::monitor_exit_helper().
+ if (!UseObjectMonitorTable) {
+ z_xilf(monitor, markWord::monitor_value);
+ }
+ z_stg(monitor, Address(Z_thread, JavaThread::unlocked_inflated_monitor_offset()));
+
+ z_ltgr(obj, obj); // Set flag = NE
+ z_bru(slow_path);
- // The owner may be anonymous, and we removed the last obj entry in
- // the lock-stack. This loses the information about the owner.
- // Write the thread to the owner field so the runtime knows the owner.
- z_stg(Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor);
- z_bru(slow_path); // CC = NE here
+ bind(set_eq_unlocked);
+ z_cr(tmp2, tmp2); // Set flag = EQ
}
bind(unlocked);
diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp
index 684741d79db..5d3a4c29940 100644
--- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp
+++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp
@@ -708,6 +708,31 @@ class MacroAssembler: public Assembler {
Label* L_success,
Label* L_failure);
+ void repne_scan(Register r_addr, Register r_value, Register r_count, Register r_scratch);
+
+ void lookup_secondary_supers_table(Register r_sub_klass,
+ Register r_super_klass,
+ Register r_temp1,
+ Register r_temp2,
+ Register r_temp3,
+ Register r_temp4,
+ Register r_result,
+ u1 super_klass_slot);
+
+ void lookup_secondary_supers_table_slow_path(Register r_super_klass,
+ Register r_array_base,
+ Register r_array_index,
+ Register r_bitmap,
+ Register r_result,
+ Register r_temp1);
+
+ void verify_secondary_supers_table(Register r_sub_klass,
+ Register r_super_klass,
+ Register r_result /* expected */,
+ Register r_temp1,
+ Register r_temp2,
+ Register r_temp3);
+
// Simplified, combined version, good for typical uses.
// Falls through on failure.
void check_klass_subtype(Register sub_klass,
@@ -727,12 +752,13 @@ 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 tmp1, Register tmp2, Label& slow);
+ void lightweight_lock(Register basic_lock, Register obj, Register tmp1, Register tmp2, Label& slow);
void lightweight_unlock(Register obj, Register tmp1, Register tmp2, Label& slow);
- void compiler_fast_lock_lightweight_object(Register obj, Register tmp1, Register tmp2);
- void compiler_fast_unlock_lightweight_object(Register obj, Register tmp1, Register tmp2);
+ void compiler_fast_lock_lightweight_object(Register obj, Register box, Register tmp1, Register tmp2);
+ void compiler_fast_unlock_lightweight_object(Register obj, Register box, Register tmp1, Register tmp2);
void resolve_jobject(Register value, Register tmp1, Register tmp2);
+ void resolve_global_jobject(Register value, Register tmp1, Register tmp2);
// Support for last Java frame (but use call_VM instead where possible).
private:
@@ -794,7 +820,6 @@ class MacroAssembler: public Assembler {
void compare_klass_ptr(Register Rop1, int64_t disp, Register Rbase, bool maybenull);
// Access heap oop, handle encoding and GC barriers.
- private:
void access_store_at(BasicType type, DecoratorSet decorators,
const Address& addr, Register val,
Register tmp1, Register tmp2, Register tmp3);
diff --git a/src/hotspot/cpu/s390/matcher_s390.hpp b/src/hotspot/cpu/s390/matcher_s390.hpp
index 6c6cae3c58f..d8b1ae68f6f 100644
--- a/src/hotspot/cpu/s390/matcher_s390.hpp
+++ b/src/hotspot/cpu/s390/matcher_s390.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2017, 2022 SAP SE. All rights reserved.
+ * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2024 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -63,11 +63,16 @@
return true;
}
- // Suppress CMOVL. Conditional move available on z/Architecture only from z196 onwards. Not exploited yet.
- static int long_cmove_cost() { return ConditionalMoveLimit; }
+ // Use conditional move (CMOVL)
+ static int long_cmove_cost() {
+ // z196/z11 or later hardware support conditional moves
+ return VM_Version::has_LoadStoreConditional() ? 0 : ConditionalMoveLimit;
+ }
- // Suppress CMOVF. Conditional move available on z/Architecture only from z196 onwards. Not exploited yet.
- static int float_cmove_cost() { return ConditionalMoveLimit; }
+ static int float_cmove_cost() {
+ // z196/z11 or later hardware support conditional moves
+ return VM_Version::has_LoadStoreConditional() ? 0 : ConditionalMoveLimit;
+ }
// Set this as clone_shift_expressions.
static bool narrow_oop_use_complex_address() {
diff --git a/src/hotspot/cpu/s390/methodHandles_s390.cpp b/src/hotspot/cpu/s390/methodHandles_s390.cpp
index ef8722f2499..b42822a6eee 100644
--- a/src/hotspot/cpu/s390/methodHandles_s390.cpp
+++ b/src/hotspot/cpu/s390/methodHandles_s390.cpp
@@ -180,8 +180,8 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth
__ z_br(target);
__ bind(L_no_such_method);
- assert(StubRoutines::throw_AbstractMethodError_entry() != nullptr, "not yet generated!");
- __ load_const_optimized(target, StubRoutines::throw_AbstractMethodError_entry());
+ assert(SharedRuntime::throw_AbstractMethodError_entry() != nullptr, "not yet generated!");
+ __ load_const_optimized(target, SharedRuntime::throw_AbstractMethodError_entry());
__ z_br(target);
}
@@ -543,7 +543,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
__ bind(L_no_such_interface);
// Throw exception.
- __ load_const_optimized(Z_R1, StubRoutines::throw_IncompatibleClassChangeError_entry());
+ __ load_const_optimized(Z_R1, SharedRuntime::throw_IncompatibleClassChangeError_entry());
__ z_br(Z_R1);
break;
}
diff --git a/src/hotspot/cpu/s390/nativeInst_s390.cpp b/src/hotspot/cpu/s390/nativeInst_s390.cpp
index 9f083fa8904..4db73395d3a 100644
--- a/src/hotspot/cpu/s390/nativeInst_s390.cpp
+++ b/src/hotspot/cpu/s390/nativeInst_s390.cpp
@@ -658,8 +658,8 @@ void NativeGeneralJump::insert_unconditional(address code_pos, address entry) {
void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) {
assert(((intptr_t)instr_addr & (BytesPerWord-1)) == 0, "requirement for mt safe patching");
- // Bytes_after_jump cannot change, because we own the Patching_lock.
- assert(Patching_lock->owned_by_self(), "must hold lock to patch instruction");
+ // Bytes_after_jump cannot change, because we own the CodeCache_lock.
+ assert(CodeCache_lock->owned_by_self(), "must hold lock to patch instruction");
intptr_t bytes_after_jump = (*(intptr_t*)instr_addr) & 0x000000000000ffffL; // 2 bytes after jump.
intptr_t load_const_bytes = (*(intptr_t*)code_buffer) & 0xffffffffffff0000L;
*(intptr_t*)instr_addr = load_const_bytes | bytes_after_jump;
diff --git a/src/hotspot/cpu/s390/register_s390.hpp b/src/hotspot/cpu/s390/register_s390.hpp
index 931e899257e..18af232e569 100644
--- a/src/hotspot/cpu/s390/register_s390.hpp
+++ b/src/hotspot/cpu/s390/register_s390.hpp
@@ -448,4 +448,12 @@ constexpr Register Z_R0_scratch = Z_R0;
constexpr Register Z_R1_scratch = Z_R1;
constexpr FloatRegister Z_fscratch_1 = Z_F1;
+typedef AbstractRegSet RegSet;
+
+template <>
+inline Register AbstractRegSet::first() {
+ if (_bitset == 0) { return noreg; }
+ return as_Register(count_trailing_zeros(_bitset));
+}
+
#endif // CPU_S390_REGISTER_S390_HPP
diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad
index 0fe3840b9b5..8b897033aa5 100644
--- a/src/hotspot/cpu/s390/s390.ad
+++ b/src/hotspot/cpu/s390/s390.ad
@@ -356,6 +356,8 @@ reg_class z_rarg3_ptr_reg(Z_R4_H,Z_R4);
reg_class z_rarg4_ptr_reg(Z_R5_H,Z_R5);
reg_class z_rarg5_ptr_reg(Z_R6_H,Z_R6);
reg_class z_thread_ptr_reg(Z_R8_H,Z_R8);
+reg_class z_r10_ptr_reg(Z_R10_H, Z_R10);
+reg_class z_r11_ptr_reg(Z_R11_H, Z_R11);
reg_class z_ptr_reg(
/*Z_R0_H,Z_R0*/ // R0
@@ -1475,10 +1477,6 @@ const RegMask* Matcher::predicate_reg_mask(void) {
return nullptr;
}
-const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) {
- return nullptr;
-}
-
// Vector calling convention not yet implemented.
bool Matcher::supports_vector_calling_convention(void) {
return false;
@@ -1642,6 +1640,10 @@ const RegMask Matcher::method_handle_invoke_SP_save_mask() {
// Should the matcher clone input 'm' of node 'n'?
bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) {
+ if (is_encode_and_store_pattern(n, m)) {
+ mstack.push(m, Visit);
+ return true;
+ }
return false;
}
@@ -2985,6 +2987,8 @@ operand iRegP() %{
match(rarg5RegP);
match(revenRegP);
match(roddRegP);
+ match(r10TempRegP);
+ match(r11TempRegP);
format %{ %}
interface(REG_INTER);
%}
@@ -2997,6 +3001,20 @@ operand threadRegP() %{
interface(REG_INTER);
%}
+operand r10TempRegP() %{
+ constraint(ALLOC_IN_RC(z_r10_ptr_reg));
+ match(iRegP);
+ format %{ %}
+ interface(REG_INTER);
+%}
+
+operand r11TempRegP() %{
+ constraint(ALLOC_IN_RC(z_r11_ptr_reg));
+ match(iRegP);
+ format %{ %}
+ interface(REG_INTER);
+%}
+
operand noArg_iRegP() %{
constraint(ALLOC_IN_RC(z_no_arg_ptr_reg));
match(iRegP);
@@ -3895,6 +3913,7 @@ instruct loadL_unaligned(iRegL dst, memory mem) %{
// Load Pointer
instruct loadP(iRegP dst, memory mem) %{
match(Set dst (LoadP mem));
+ predicate(n->as_Load()->barrier_data() == 0);
ins_cost(MEMORY_REF_COST);
size(Z_DISP3_SIZE);
format %{ "LG $dst,$mem\t # ptr" %}
@@ -3906,6 +3925,7 @@ instruct loadP(iRegP dst, memory mem) %{
// LoadP + CastP2L
instruct castP2X_loadP(iRegL dst, memory mem) %{
match(Set dst (CastP2X (LoadP mem)));
+ predicate(n->as_Load()->barrier_data() == 0);
ins_cost(MEMORY_REF_COST);
size(Z_DISP3_SIZE);
format %{ "LG $dst,$mem\t # ptr + p2x" %}
@@ -4202,28 +4222,6 @@ instruct storeB(memory mem, iRegI src) %{
ins_pipe(pipe_class_dummy);
%}
-instruct storeCM(memory mem, immI_0 src) %{
- match(Set mem (StoreCM mem src));
- ins_cost(MEMORY_REF_COST);
- // TODO: s390 port size(VARIABLE_SIZE);
- format %{ "STC(Y) $src,$mem\t # CMS card-mark byte (must be 0!)" %}
- ins_encode %{
- guarantee($mem$$index$$Register != Z_R0, "content will not be used.");
- if ($mem$$index$$Register != noreg) {
- // Can't use clear_mem --> load const zero and store character.
- __ load_const_optimized(Z_R0_scratch, (long)0);
- if (Immediate::is_uimm12($mem$$disp)) {
- __ z_stc(Z_R0_scratch, $mem$$Address);
- } else {
- __ z_stcy(Z_R0_scratch, $mem$$Address);
- }
- } else {
- __ clear_mem(Address($mem$$Address), 1);
- }
- %}
- ins_pipe(pipe_class_dummy);
-%}
-
// CHAR/SHORT
// Store Char/Short
@@ -4268,6 +4266,7 @@ instruct storeL(memory mem, iRegL src) %{
// Store Pointer
instruct storeP(memory dst, memoryRegP src) %{
match(Set dst (StoreP dst src));
+ predicate(n->as_Store()->barrier_data() == 0);
ins_cost(MEMORY_REF_COST);
size(Z_DISP3_SIZE);
format %{ "STG $src,$dst\t # ptr" %}
@@ -4370,6 +4369,7 @@ instruct memInitL(memoryRS mem, immL16 src) %{
// Move Immediate to 8-byte memory.
instruct memInitP(memoryRS mem, immP16 src) %{
match(Set mem (StoreP mem src));
+ predicate(n->as_Store()->barrier_data() == 0);
ins_cost(MEMORY_REF_COST);
size(6);
format %{ "MVGHI $mem,$src\t # direct mem init 8" %}
@@ -4399,6 +4399,7 @@ instruct negL_reg_reg(iRegL dst, immL_0 zero, iRegL src, flagsReg cr) %{
// Load narrow oop
instruct loadN(iRegN dst, memory mem) %{
match(Set dst (LoadN mem));
+ predicate(n->as_Load()->barrier_data() == 0);
ins_cost(MEMORY_REF_COST);
size(Z_DISP3_SIZE);
format %{ "LoadN $dst,$mem\t # (cOop)" %}
@@ -4462,7 +4463,7 @@ instruct loadConNKlass(iRegN dst, immNKlass src) %{
instruct decodeLoadN(iRegP dst, memory mem) %{
match(Set dst (DecodeN (LoadN mem)));
- predicate(false && (CompressedOops::base()==nullptr)&&(CompressedOops::shift()==0));
+ predicate(false && (CompressedOops::base()==nullptr) && (CompressedOops::shift()==0));
ins_cost(MEMORY_REF_COST);
size(Z_DISP3_SIZE);
format %{ "DecodeLoadN $dst,$mem\t # (cOop Load+Decode)" %}
@@ -4610,7 +4611,7 @@ instruct encodeP(iRegN dst, iRegP src, flagsReg cr) %{
match(Set dst (EncodeP src));
effect(KILL cr);
predicate((n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull) &&
- (CompressedOops::base() == 0 ||
+ (CompressedOops::base() == nullptr ||
CompressedOops::base_disjoint() ||
!ExpandLoadingBaseEncode));
ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST);
@@ -4633,7 +4634,7 @@ instruct encodeP_NN(iRegN dst, iRegP src, flagsReg cr) %{
match(Set dst (EncodeP src));
effect(KILL cr);
predicate((n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull) &&
- (CompressedOops::base() == 0 ||
+ (CompressedOops::base() == nullptr ||
CompressedOops::base_disjoint() ||
!ExpandLoadingBaseEncode_NN));
ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST);
@@ -4717,6 +4718,7 @@ instruct encodeP_NN_Ex(iRegN dst, iRegP src, flagsReg cr) %{
// Store Compressed Pointer
instruct storeN(memory mem, iRegN_P2N src) %{
match(Set mem (StoreN mem src));
+ predicate(n->as_Store()->barrier_data() == 0);
ins_cost(MEMORY_REF_COST);
size(Z_DISP_SIZE);
format %{ "ST $src,$mem\t # (cOop)" %}
@@ -5128,6 +5130,7 @@ instruct compareAndSwapL_bool(iRegP mem_ptr, rarg5RegL oldval, iRegL newval, iRe
instruct compareAndSwapP_bool(iRegP mem_ptr, rarg5RegP oldval, iRegP_N2P newval, iRegI res, flagsReg cr) %{
match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval)));
+ predicate(n->as_LoadStore()->barrier_data() == 0);
effect(USE mem_ptr, USE_KILL oldval, KILL cr);
size(18);
format %{ "$res = CompareAndSwapP $oldval,$newval,$mem_ptr" %}
@@ -5138,6 +5141,7 @@ instruct compareAndSwapP_bool(iRegP mem_ptr, rarg5RegP oldval, iRegP_N2P newval,
instruct compareAndSwapN_bool(iRegP mem_ptr, rarg5RegN oldval, iRegN_P2N newval, iRegI res, flagsReg cr) %{
match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval)));
+ predicate(n->as_LoadStore()->barrier_data() == 0);
effect(USE mem_ptr, USE_KILL oldval, KILL cr);
size(16);
format %{ "$res = CompareAndSwapN $oldval,$newval,$mem_ptr" %}
@@ -5425,6 +5429,7 @@ instruct xchgL_reg_mem(memoryRSY mem, iRegL dst, iRegL tmp, flagsReg cr) %{
%}
instruct xchgN_reg_mem(memoryRSY mem, iRegN dst, iRegI tmp, flagsReg cr) %{
+ predicate(n->as_LoadStore()->barrier_data() == 0);
match(Set dst (GetAndSetN mem dst));
effect(KILL cr, TEMP tmp); // USE_DEF dst by match rule.
format %{ "XCHGN $dst,[$mem]\t # EXCHANGE (coop, atomic), temp $tmp" %}
@@ -5434,6 +5439,7 @@ instruct xchgN_reg_mem(memoryRSY mem, iRegN dst, iRegI tmp, flagsReg cr) %{
instruct xchgP_reg_mem(memoryRSY mem, iRegP dst, iRegL tmp, flagsReg cr) %{
match(Set dst (GetAndSetP mem dst));
+ predicate(n->as_LoadStore()->barrier_data() == 0);
effect(KILL cr, TEMP tmp); // USE_DEF dst by match rule.
format %{ "XCHGP $dst,[$mem]\t # EXCHANGE (oop, atomic), temp $tmp" %}
ins_encode(z_enc_SwapL(mem, dst, tmp));
@@ -5908,7 +5914,7 @@ instruct addP_regN_reg_imm20(iRegP dst, iRegP_N2P src1, iRegL src2, immL20 con)
instruct addP_mem_imm(memoryRSY mem, immL8 src, flagsReg cr) %{
match(Set mem (StoreP mem (AddP (LoadP mem) src)));
effect(KILL cr);
- predicate(VM_Version::has_MemWithImmALUOps());
+ predicate(VM_Version::has_MemWithImmALUOps() && n->as_LoadStore()->barrier_data() == 0);
ins_cost(MEMORY_REF_COST);
size(6);
format %{ "AGSI $mem,$src\t # direct mem add 8 (ptr)" %}
@@ -9499,6 +9505,20 @@ instruct tailjmpInd(iRegP jump_target, rarg1RegP ex_oop) %{
ins_pipe(pipe_class_dummy);
%}
+// Forward exception.
+instruct ForwardExceptionjmp() %{
+ match(ForwardException);
+ ins_cost(CALL_COST);
+ format %{ "Jmp forward_exception_stub" %}
+ ins_encode %{
+ __ set_inst_mark();
+ __ load_const_optimized(Z_R1_scratch, (address)StubRoutines::forward_exception_entry());
+ __ z_br(Z_R1_scratch);
+ __ clear_inst_mark();
+ %}
+ ins_pipe(pipe_class_dummy);
+%}
+
// Create exception oop: created by stack-crawling runtime code.
// Created exception is now available to this handler, and is setup
// just prior to jumping to this handler. No code emitted.
@@ -9560,6 +9580,32 @@ instruct partialSubtypeCheck(rarg1RegP index, rarg2RegP sub, rarg3RegP super, fl
ins_pipe(pipe_class_dummy);
%}
+instruct partialSubtypeCheckConstSuper(rarg2RegP sub, rarg1RegP super, immP super_con,
+ r11TempRegP result, rarg5RegP temp1, rarg4RegP temp2,
+ rarg3RegP temp3, r10TempRegP temp4, flagsReg pcc) %{
+ match(Set result (PartialSubtypeCheck sub (Binary super super_con)));
+ predicate(UseSecondarySupersTable);
+ effect(KILL pcc, TEMP temp1, TEMP temp2, TEMP temp3, TEMP temp4);
+ ins_cost(7 * DEFAULT_COST); // needs to be less than competing nodes
+ format %{ "partialSubtypeCheck $result, $sub, $super, $super_con" %}
+
+ ins_encode %{
+ u1 super_klass_slot = ((Klass*)$super_con$$constant)->hash_slot();
+ if (InlineSecondarySupersTest) {
+ __ lookup_secondary_supers_table($sub$$Register, $super$$Register,
+ $temp1$$Register, $temp2$$Register, $temp3$$Register,
+ $temp4$$Register, $result$$Register, super_klass_slot);
+ } else {
+ AddressLiteral stub_address(StubRoutines::lookup_secondary_supers_table_stub(super_klass_slot));
+ __ load_const_optimized(Z_ARG4, stub_address);
+ __ z_basr(Z_R14, Z_ARG4);
+ }
+
+ %}
+
+ ins_pipe(pipe_class_dummy);
+%}
+
instruct partialSubtypeCheck_vs_zero(flagsReg pcc, rarg2RegP sub, rarg3RegP super, immP0 zero,
rarg1RegP index, rarg4RegP scratch1, rarg5RegP scratch2) %{
match(Set pcc (CmpI (PartialSubtypeCheck sub super) zero));
diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp
index 0ee88345282..468610b588e 100644
--- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp
+++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp
@@ -43,6 +43,7 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/signature.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/timerTrace.hpp"
#include "runtime/vframeArray.hpp"
#include "utilities/align.hpp"
#include "utilities/macros.hpp"
@@ -1713,7 +1714,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
// Try fastpath for locking.
if (LockingMode == LM_LIGHTWEIGHT) {
// Fast_lock kills r_temp_1, r_temp_2.
- __ compiler_fast_lock_lightweight_object(r_oop, r_tmp1, r_tmp2);
+ __ compiler_fast_lock_lightweight_object(r_oop, r_box, r_tmp1, r_tmp2);
} else {
// Fast_lock kills r_temp_1, r_temp_2.
__ compiler_fast_lock_object(r_oop, r_box, r_tmp1, r_tmp2);
@@ -1917,7 +1918,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
// Try fastpath for unlocking.
if (LockingMode == LM_LIGHTWEIGHT) {
// Fast_unlock kills r_tmp1, r_tmp2.
- __ compiler_fast_unlock_lightweight_object(r_oop, r_tmp1, r_tmp2);
+ __ compiler_fast_unlock_lightweight_object(r_oop, r_box, r_tmp1, r_tmp2);
} else {
// Fast_unlock kills r_tmp1, r_tmp2.
__ compiler_fast_unlock_object(r_oop, r_box, r_tmp1, r_tmp2);
@@ -2488,7 +2489,8 @@ void SharedRuntime::generate_deopt_blob() {
// Allocate space for the code.
ResourceMark rm;
// Setup code generation tools.
- CodeBuffer buffer("deopt_blob", 2048, 1024);
+ const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id);
+ CodeBuffer buffer(name, 2048, 1024);
InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer);
Label exec_mode_initialized;
OopMap* map = nullptr;
@@ -2706,7 +2708,7 @@ void SharedRuntime::generate_deopt_blob() {
#ifdef COMPILER2
//------------------------------generate_uncommon_trap_blob--------------------
-void SharedRuntime::generate_uncommon_trap_blob() {
+void OptoRuntime::generate_uncommon_trap_blob() {
// Allocate space for the code
ResourceMark rm;
// Setup code generation tools
@@ -2769,7 +2771,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
} else {
__ z_cliy(unpack_kind_byte_offset, unroll_block_reg, Deoptimization::Unpack_uncommon_trap);
}
- __ asm_assert(Assembler::bcondEqual, "SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap", 0);
+ __ asm_assert(Assembler::bcondEqual, "OptoRuntime::generate_deopt_blob: expected Unpack_uncommon_trap", 0);
#endif
__ zap_from_to(Z_SP, Z_SP, Z_R0_scratch, Z_R1, 500, -1);
@@ -2834,23 +2836,25 @@ void SharedRuntime::generate_uncommon_trap_blob() {
//
// Generate a special Compile2Runtime blob that saves all registers,
// and setup oopmap.
-SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) {
+SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) {
assert(StubRoutines::forward_exception_entry() != nullptr,
"must be generated before");
+ assert(is_polling_page_id(id), "expected a polling page stub id");
ResourceMark rm;
OopMapSet *oop_maps = new OopMapSet();
OopMap* map;
// Allocate space for the code. Setup code generation tools.
- CodeBuffer buffer("handler_blob", 2048, 1024);
+ const char* name = SharedRuntime::stub_name(id);
+ CodeBuffer buffer(name, 2048, 1024);
MacroAssembler* masm = new MacroAssembler(&buffer);
unsigned int start_off = __ offset();
address call_pc = nullptr;
int frame_size_in_bytes;
- bool cause_return = (poll_type == POLL_AT_RETURN);
+ bool cause_return = (id == SharedStubId::polling_page_return_handler_id);
// Make room for return address (or push it again)
if (!cause_return) {
__ z_lg(Z_R14, Address(Z_thread, JavaThread::saved_exception_pc_offset()));
@@ -2935,12 +2939,14 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
// but since this is generic code we don't know what they are and the caller
// must do any gc of the args.
//
-RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) {
+RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) {
assert (StubRoutines::forward_exception_entry() != nullptr, "must be generated before");
+ assert(is_resolve_id(id), "expected a resolve stub id");
// allocate space for the code
ResourceMark rm;
+ const char* name = SharedRuntime::stub_name(id);
CodeBuffer buffer(name, 1000, 512);
MacroAssembler* masm = new MacroAssembler(&buffer);
@@ -3010,6 +3016,88 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha
}
+// Continuation point for throwing of implicit exceptions that are
+// not handled in the current activation. Fabricates an exception
+// oop and initiates normal exception dispatching in this
+// frame. Only callee-saved registers are preserved (through the
+// normal RegisterMap handling). If the compiler
+// needs all registers to be preserved between the fault point and
+// the exception handler then it must assume responsibility for that
+// in AbstractCompiler::continuation_for_implicit_null_exception or
+// continuation_for_implicit_division_by_zero_exception. All other
+// implicit exceptions (e.g., NullPointerException or
+// AbstractMethodError on entry) are either at call sites or
+// otherwise assume that stack unwinding will be initiated, so
+// caller saved registers were assumed volatile in the compiler.
+
+// Note that we generate only this stub into a RuntimeStub, because
+// it needs to be properly traversed and ignored during GC, so we
+// change the meaning of the "__" macro within this method.
+
+// Note: the routine set_pc_not_at_call_for_caller in
+// SharedRuntime.cpp requires that this code be generated into a
+// RuntimeStub.
+
+RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) {
+ assert(is_throw_id(id), "expected a throw stub id");
+
+ const char* name = SharedRuntime::stub_name(id);
+
+ int insts_size = 256;
+ int locs_size = 0;
+
+ ResourceMark rm;
+ const char* timer_msg = "SharedRuntime generate_throw_exception";
+ TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime));
+
+ CodeBuffer code(name, insts_size, locs_size);
+ MacroAssembler* masm = new MacroAssembler(&code);
+ int framesize_in_bytes;
+ address start = __ pc();
+
+ __ save_return_pc();
+ framesize_in_bytes = __ push_frame_abi160(0);
+
+ address frame_complete_pc = __ pc();
+
+ // Note that we always have a runtime stub frame on the top of stack at this point.
+ __ get_PC(Z_R1);
+ __ set_last_Java_frame(/*sp*/Z_SP, /*pc*/Z_R1);
+
+ // Do the call.
+ BLOCK_COMMENT("call runtime_entry");
+ __ call_VM_leaf(runtime_entry, Z_thread);
+
+ __ reset_last_Java_frame();
+
+#ifdef ASSERT
+ // Make sure that this code is only executed if there is a pending exception.
+ { Label L;
+ __ z_lg(Z_R0,
+ in_bytes(Thread::pending_exception_offset()),
+ Z_thread);
+ __ z_ltgr(Z_R0, Z_R0);
+ __ z_brne(L);
+ __ stop("SharedRuntime::throw_exception: no pending exception");
+ __ bind(L);
+ }
+#endif
+
+ __ pop_frame();
+ __ restore_return_pc();
+
+ __ load_const_optimized(Z_R1, StubRoutines::forward_exception_entry());
+ __ z_br(Z_R1);
+
+ RuntimeStub* stub =
+ RuntimeStub::new_runtime_stub(name, &code,
+ frame_complete_pc - start,
+ framesize_in_bytes/wordSize,
+ nullptr /*oop_maps*/, false);
+
+ return stub;
+}
+
//------------------------------Montgomery multiplication------------------------
//
@@ -3263,3 +3351,18 @@ extern "C"
int SpinPause() {
return 0;
}
+
+#if INCLUDE_JFR
+RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() {
+ if (!Continuations::enabled()) return nullptr;
+ Unimplemented();
+ return nullptr;
+}
+
+RuntimeStub* SharedRuntime::generate_jfr_return_lease() {
+ if (!Continuations::enabled()) return nullptr;
+ Unimplemented();
+ return nullptr;
+}
+
+#endif // INCLUDE_JFR
diff --git a/src/hotspot/cpu/s390/smallRegisterMap_s390.inline.hpp b/src/hotspot/cpu/s390/smallRegisterMap_s390.inline.hpp
index 8c74eb7dd6d..625d17cf992 100644
--- a/src/hotspot/cpu/s390/smallRegisterMap_s390.inline.hpp
+++ b/src/hotspot/cpu/s390/smallRegisterMap_s390.inline.hpp
@@ -30,8 +30,15 @@
// Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap
class SmallRegisterMap {
+ constexpr SmallRegisterMap() = default;
+ ~SmallRegisterMap() = default;
+ NONCOPYABLE(SmallRegisterMap);
+
public:
- static constexpr SmallRegisterMap* instance = nullptr;
+ static const SmallRegisterMap* instance() {
+ static constexpr SmallRegisterMap the_instance{};
+ return &the_instance;
+ }
private:
static void assert_is_rfp(VMReg r) NOT_DEBUG_RETURN
DEBUG_ONLY({ Unimplemented(); })
@@ -46,12 +53,6 @@ class SmallRegisterMap {
return map;
}
- SmallRegisterMap() {}
-
- SmallRegisterMap(const RegisterMap* map) {
- Unimplemented();
- }
-
inline address location(VMReg reg, intptr_t* sp) const {
Unimplemented();
return nullptr;
diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp
index dfd20730b84..dd9ed4c9546 100644
--- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp
+++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2023 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -572,89 +572,6 @@ class StubGenerator: public StubCodeGenerator {
#undef pending_exception_offset
}
- // Continuation point for throwing of implicit exceptions that are
- // not handled in the current activation. Fabricates an exception
- // oop and initiates normal exception dispatching in this
- // frame. Only callee-saved registers are preserved (through the
- // normal RegisterMap handling). If the compiler
- // needs all registers to be preserved between the fault point and
- // the exception handler then it must assume responsibility for that
- // in AbstractCompiler::continuation_for_implicit_null_exception or
- // continuation_for_implicit_division_by_zero_exception. All other
- // implicit exceptions (e.g., NullPointerException or
- // AbstractMethodError on entry) are either at call sites or
- // otherwise assume that stack unwinding will be initiated, so
- // caller saved registers were assumed volatile in the compiler.
-
- // Note that we generate only this stub into a RuntimeStub, because
- // it needs to be properly traversed and ignored during GC, so we
- // change the meaning of the "__" macro within this method.
-
- // Note: the routine set_pc_not_at_call_for_caller in
- // SharedRuntime.cpp requires that this code be generated into a
- // RuntimeStub.
-#undef __
-#define __ masm->
-
- address generate_throw_exception(const char* name, address runtime_entry,
- bool restore_saved_exception_pc,
- Register arg1 = noreg, Register arg2 = noreg) {
- assert_different_registers(arg1, Z_R0_scratch); // would be destroyed by push_frame()
- assert_different_registers(arg2, Z_R0_scratch); // would be destroyed by push_frame()
-
- int insts_size = 256;
- int locs_size = 0;
- CodeBuffer code(name, insts_size, locs_size);
- MacroAssembler* masm = new MacroAssembler(&code);
- int framesize_in_bytes;
- address start = __ pc();
-
- __ save_return_pc();
- framesize_in_bytes = __ push_frame_abi160(0);
-
- address frame_complete_pc = __ pc();
- if (restore_saved_exception_pc) {
- __ unimplemented("StubGenerator::throw_exception", 74);
- }
-
- // Note that we always have a runtime stub frame on the top of stack at this point.
- __ get_PC(Z_R1);
- __ set_last_Java_frame(/*sp*/Z_SP, /*pc*/Z_R1);
-
- // Do the call.
- BLOCK_COMMENT("call runtime_entry");
- __ call_VM_leaf(runtime_entry, Z_thread, arg1, arg2);
-
- __ reset_last_Java_frame();
-
-#ifdef ASSERT
- // Make sure that this code is only executed if there is a pending exception.
- { Label L;
- __ z_lg(Z_R0,
- in_bytes(Thread::pending_exception_offset()),
- Z_thread);
- __ z_ltgr(Z_R0, Z_R0);
- __ z_brne(L);
- __ stop("StubRoutines::throw_exception: no pending exception");
- __ bind(L);
- }
-#endif
-
- __ pop_frame();
- __ restore_return_pc();
-
- __ load_const_optimized(Z_R1, StubRoutines::forward_exception_entry());
- __ z_br(Z_R1);
-
- RuntimeStub* stub =
- RuntimeStub::new_runtime_stub(name, &code,
- frame_complete_pc - start,
- framesize_in_bytes/wordSize,
- nullptr /*oop_maps*/, false);
-
- return stub->entry_point();
- }
-
#undef __
#ifdef PRODUCT
#define __ _masm->
@@ -705,6 +622,50 @@ class StubGenerator: public StubCodeGenerator {
return start;
}
+ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) {
+ StubCodeMark mark(this, "StubRoutines", "lookup_secondary_supers_table");
+
+ const Register
+ r_super_klass = Z_ARG1,
+ r_sub_klass = Z_ARG2,
+ r_array_index = Z_ARG3,
+ r_array_length = Z_ARG4,
+ r_array_base = Z_ARG5,
+ r_bitmap = Z_R10,
+ r_result = Z_R11;
+ address start = __ pc();
+
+ __ lookup_secondary_supers_table(r_sub_klass, r_super_klass,
+ r_array_base, r_array_length, r_array_index,
+ r_bitmap, r_result, super_klass_index);
+
+ __ z_br(Z_R14);
+
+ return start;
+ }
+
+ // Slow path implementation for UseSecondarySupersTable.
+ address generate_lookup_secondary_supers_table_slow_path_stub() {
+ StubCodeMark mark(this, "StubRoutines", "lookup_secondary_supers_table_slow_path");
+
+ address start = __ pc();
+
+ const Register
+ r_super_klass = Z_ARG1,
+ r_array_base = Z_ARG5,
+ r_temp1 = Z_ARG4,
+ r_array_index = Z_ARG3,
+ r_bitmap = Z_R10,
+ r_result = Z_R11;
+
+ __ lookup_secondary_supers_table_slow_path(r_super_klass, r_array_base,
+ r_array_index, r_bitmap, r_result, r_temp1);
+
+ __ z_br(Z_R14);
+
+ return start;
+ }
+
#if !defined(PRODUCT)
// Wrapper which calls oopDesc::is_oop_or_null()
// Only called by MacroAssembler::verify_oop
@@ -3077,21 +3038,6 @@ class StubGenerator: public StubCodeGenerator {
return nullptr;
}
- #if INCLUDE_JFR
- RuntimeStub* generate_jfr_write_checkpoint() {
- if (!Continuations::enabled()) return nullptr;
- Unimplemented();
- return nullptr;
- }
-
- RuntimeStub* generate_jfr_return_lease() {
- if (!Continuations::enabled()) return nullptr;
- Unimplemented();
- return nullptr;
- }
-
- #endif // INCLUDE_JFR
-
// exception handler for upcall stubs
address generate_upcall_stub_exception_handler() {
StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler");
@@ -3107,6 +3053,29 @@ class StubGenerator: public StubCodeGenerator {
return start;
}
+ // load Method* target of MethodHandle
+ // Z_ARG1 = jobject receiver
+ // Z_method = Method* result
+ address generate_upcall_stub_load_target() {
+ StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target");
+ address start = __ pc();
+
+ __ resolve_global_jobject(Z_ARG1, Z_tmp_1, Z_tmp_2);
+ // Load target method from receiver
+ __ load_heap_oop(Z_method, Address(Z_ARG1, java_lang_invoke_MethodHandle::form_offset()),
+ noreg, noreg, IS_NOT_NULL);
+ __ load_heap_oop(Z_method, Address(Z_method, java_lang_invoke_LambdaForm::vmentry_offset()),
+ noreg, noreg, IS_NOT_NULL);
+ __ load_heap_oop(Z_method, Address(Z_method, java_lang_invoke_MemberName::method_offset()),
+ noreg, noreg, IS_NOT_NULL);
+ __ z_lg(Z_method, Address(Z_method, java_lang_invoke_ResolvedMethodName::vmtarget_offset()));
+ __ z_stg(Z_method, Address(Z_thread, JavaThread::callee_target_offset())); // just in case callee is deoptimized
+
+ __ z_br(Z_R14);
+
+ return start;
+ }
+
void generate_initial_stubs() {
// Generates all stubs and initializes the entry points.
@@ -3120,14 +3089,6 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_call_stub_entry = generate_call_stub(StubRoutines::_call_stub_return_address);
StubRoutines::_catch_exception_entry = generate_catch_exception();
- // Build this early so it's available for the interpreter.
- StubRoutines::_throw_StackOverflowError_entry =
- generate_throw_exception("StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false);
- StubRoutines::_throw_delayed_StackOverflowError_entry =
- generate_throw_exception("delayed StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError), false);
-
//----------------------------------------------------------------------
// Entry points that are platform specific.
@@ -3152,29 +3113,13 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_cont_thaw = generate_cont_thaw();
StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier();
StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception();
-
- JFR_ONLY(generate_jfr_stubs();)
- }
-
-#if INCLUDE_JFR
- void generate_jfr_stubs() {
- StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint();
- StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point();
- StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease();
- StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point();
}
-#endif // INCLUDE_JFR
void generate_final_stubs() {
// Generates all stubs and initializes the entry points.
StubRoutines::zarch::_partial_subtype_check = generate_partial_subtype_check();
- // These entry points require SharedInfo::stack0 to be set up in non-core builds.
- StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError), false);
- StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false);
- StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false);
-
// Support for verify_oop (must happen after universe_init).
StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop_subroutine();
@@ -3188,6 +3133,7 @@ class StubGenerator: public StubCodeGenerator {
}
StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler();
+ StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target();
}
void generate_compiler_stubs() {
@@ -3247,6 +3193,14 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_montgomerySquare
= CAST_FROM_FN_PTR(address, SharedRuntime::montgomery_square);
}
+ if (UseSecondarySupersTable) {
+ StubRoutines::_lookup_secondary_supers_table_slow_path_stub = generate_lookup_secondary_supers_table_slow_path_stub();
+ if (!InlineSecondarySupersTest) {
+ for (int slot = 0; slot < Klass::SECONDARY_SUPERS_TABLE_SIZE; slot++) {
+ StubRoutines::_lookup_secondary_supers_table_stubs[slot] = generate_lookup_secondary_supers_table_stub(slot);
+ }
+ }
+ }
#endif
#endif // COMPILER2_OR_JVMCI
}
diff --git a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp
index 87025826400..2c2e8ed9e3b 100644
--- a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp
+++ b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp
@@ -850,9 +850,9 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(Register frame_
// Note also that the restored frame is not necessarily interpreted.
// Use the shared runtime version of the StackOverflowError.
- assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "stub not yet generated");
- AddressLiteral stub(StubRoutines::throw_StackOverflowError_entry());
- __ load_absolute_address(tmp1, StubRoutines::throw_StackOverflowError_entry());
+ assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "stub not yet generated");
+ AddressLiteral stub(SharedRuntime::throw_StackOverflowError_entry());
+ __ load_absolute_address(tmp1, SharedRuntime::throw_StackOverflowError_entry());
__ z_br(tmp1);
// If you get to here, then there is enough stack space.
@@ -1224,6 +1224,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
case Interpreter::java_lang_math_sin : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin); break;
case Interpreter::java_lang_math_cos : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos); break;
case Interpreter::java_lang_math_tan : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan); break;
+ case Interpreter::java_lang_math_tanh : /* run interpreted */ break;
case Interpreter::java_lang_math_abs : /* run interpreted */ break;
case Interpreter::java_lang_math_sqrt : /* runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsqrt); not available */ break;
case Interpreter::java_lang_math_log : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog); break;
diff --git a/src/hotspot/cpu/s390/templateTable_s390.cpp b/src/hotspot/cpu/s390/templateTable_s390.cpp
index ef68a5ac83a..0c9f9e031b0 100644
--- a/src/hotspot/cpu/s390/templateTable_s390.cpp
+++ b/src/hotspot/cpu/s390/templateTable_s390.cpp
@@ -2321,7 +2321,7 @@ void TemplateTable::_return(TosState state) {
assert(state == vtos, "only valid state");
__ z_lg(Rthis, aaddress(0));
__ load_klass(Rklass, Rthis);
- __ testbit(Address(Rklass, Klass::access_flags_offset()), exact_log2(JVM_ACC_HAS_FINALIZER));
+ __ z_tm(Address(Rklass, Klass::misc_flags_offset()), KlassFlags::_misc_has_finalizer);
__ z_bfalse(skip_register_finalizer);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), Rthis);
__ bind(skip_register_finalizer);
diff --git a/src/hotspot/cpu/s390/upcallLinker_s390.cpp b/src/hotspot/cpu/s390/upcallLinker_s390.cpp
index 734b4e89c7c..8baad40a519 100644
--- a/src/hotspot/cpu/s390/upcallLinker_s390.cpp
+++ b/src/hotspot/cpu/s390/upcallLinker_s390.cpp
@@ -23,6 +23,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
+#include "classfile/javaClasses.hpp"
#include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
#include "prims/upcallLinker.hpp"
@@ -116,7 +117,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr
static const int upcall_stub_code_base_size = 1024;
static const int upcall_stub_size_per_arg = 16; // arg save & restore + move
-address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
+address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
@@ -206,7 +207,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
__ block_comment("on_entry {");
__ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry));
__ z_aghik(Z_ARG1, Z_SP, frame_data_offset);
- __ load_const_optimized(Z_ARG2, (intptr_t)receiver);
__ call(call_target_address);
__ z_lgr(Z_thread, Z_RET);
__ block_comment("} on_entry");
@@ -216,12 +216,11 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
arg_shuffle.generate(_masm, shuffle_reg, abi._shadow_space_bytes, frame::z_jit_out_preserve_size);
__ block_comment("} argument_shuffle");
- __ block_comment("receiver {");
- __ get_vm_result(Z_ARG1);
- __ block_comment("} receiver");
-
- __ load_const_optimized(Z_method, (intptr_t)entry);
- __ z_stg(Z_method, Address(Z_thread, in_bytes(JavaThread::callee_target_offset())));
+ __ block_comment("load_target {");
+ __ load_const_optimized(Z_ARG1, (intptr_t)receiver);
+ __ load_const_optimized(call_target_address, StubRoutines::upcall_stub_load_target());
+ __ call(call_target_address); // load taget Method* into Z_method
+ __ block_comment("} load_target");
__ z_lg(call_target_address, Address(Z_method, in_bytes(Method::from_compiled_offset())));
__ call(call_target_address);
@@ -274,7 +273,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
#ifndef PRODUCT
stringStream ss;
- ss.print("upcall_stub_%s", entry->signature()->as_C_string());
+ ss.print("upcall_stub_%s", signature->as_C_string());
const char* name = _masm->code_string(ss.as_string());
#else // PRODUCT
const char* name = "upcall_stub";
diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp
index af0903884fb..4b17ff4594c 100644
--- a/src/hotspot/cpu/s390/vm_version_s390.cpp
+++ b/src/hotspot/cpu/s390/vm_version_s390.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2023 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2024 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -272,6 +272,13 @@ void VM_Version::initialize() {
FLAG_SET_DEFAULT(UseSHA, false);
}
+ if (UseSecondarySupersTable && VM_Version::get_model_index() < 5 /* z196/z11 */) {
+ if (!FLAG_IS_DEFAULT(UseSecondarySupersTable)) {
+ warning("UseSecondarySupersTable requires z196 or later.");
+ }
+ FLAG_SET_DEFAULT(UseSecondarySupersTable, false);
+ }
+
#ifdef COMPILER2
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true);
diff --git a/src/hotspot/cpu/s390/vm_version_s390.hpp b/src/hotspot/cpu/s390/vm_version_s390.hpp
index 4f963c4e485..31fdedc59f6 100644
--- a/src/hotspot/cpu/s390/vm_version_s390.hpp
+++ b/src/hotspot/cpu/s390/vm_version_s390.hpp
@@ -413,6 +413,8 @@ class VM_Version: public Abstract_VM_Version {
// s390 supports fast class initialization checks
static bool supports_fast_class_init_checks() { return true; }
+ constexpr static bool supports_secondary_supers_table() { return true; }
+
constexpr static bool supports_recursive_lightweight_locking() { return true; }
// CPU feature query functions
diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp
index 001ff472f40..0b021bbbf5e 100644
--- a/src/hotspot/cpu/x86/assembler_x86.cpp
+++ b/src/hotspot/cpu/x86/assembler_x86.cpp
@@ -1385,6 +1385,14 @@ void Assembler::addl(Address dst, int32_t imm32) {
emit_arith_operand(0x81, rax, dst, imm32);
}
+void Assembler::eaddl(Register dst, Address src, int32_t imm32, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith_operand(0x81, rax, src, imm32);
+}
+
void Assembler::addb(Address dst, int imm8) {
InstructionMark im(this);
prefix(dst);
@@ -1405,12 +1413,6 @@ void Assembler::addb(Register dst, int imm8) {
emit_arith_b(0x80, 0xC0, dst, imm8);
}
-void Assembler::addw(Register dst, Register src) {
- emit_int8(0x66);
- (void)prefix_and_encode(dst->encoding(), src->encoding());
- emit_arith(0x03, 0xC0, dst, src);
-}
-
void Assembler::addw(Address dst, int imm16) {
InstructionMark im(this);
emit_int8(0x66);
@@ -1435,11 +1437,26 @@ void Assembler::addl(Address dst, Register src) {
emit_operand(src, dst, 0);
}
+void Assembler::eaddl(Register dst, Address src1, Register src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x01);
+ emit_operand(src2, src1, 0);
+}
+
void Assembler::addl(Register dst, int32_t imm32) {
prefix(dst);
emit_arith(0x81, 0xC0, dst, imm32);
}
+void Assembler::eaddl(Register dst, Register src, int32_t imm32, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith(0x81, 0xC0, src, imm32);
+}
+
void Assembler::addl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
@@ -1447,11 +1464,27 @@ void Assembler::addl(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::eaddl(Register dst, Register src1, Address src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x03);
+ emit_operand(src1, src2, 0);
+}
+
void Assembler::addl(Register dst, Register src) {
(void) prefix_and_encode(dst->encoding(), src->encoding());
emit_arith(0x03, 0xC0, dst, src);
}
+void Assembler::eaddl(Register dst, Register src1, Register src2, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ // opcode matches gcc
+ emit_arith(0x01, 0xC0, src1, src2);
+}
+
void Assembler::addr_nop_4() {
assert(UseAddressNop, "no CPU support");
// 4 bytes: NOP DWORD PTR [EAX+0]
@@ -1632,22 +1665,31 @@ void Assembler::andb(Address dst, Register src) {
emit_operand(src, dst, 0);
}
-void Assembler::andw(Register dst, Register src) {
- (void)prefix_and_encode(dst->encoding(), src->encoding());
- emit_arith(0x23, 0xC0, dst, src);
-}
-
void Assembler::andl(Address dst, int32_t imm32) {
InstructionMark im(this);
prefix(dst);
emit_arith_operand(0x81, as_Register(4), dst, imm32);
}
+void Assembler::eandl(Register dst, Address src, int32_t imm32, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith_operand(0x81, rsp, src, imm32);
+}
+
void Assembler::andl(Register dst, int32_t imm32) {
prefix(dst);
emit_arith(0x81, 0xE0, dst, imm32);
}
+void Assembler::eandl(Register dst, Register src, int32_t imm32, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith(0x81, 0xE0, src, imm32);
+}
+
void Assembler::andl(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src);
@@ -1662,11 +1704,27 @@ void Assembler::andl(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::eandl(Register dst, Register src1, Address src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x23);
+ emit_operand(src1, src2, 0);
+}
+
void Assembler::andl(Register dst, Register src) {
(void) prefix_and_encode(dst->encoding(), src->encoding());
emit_arith(0x23, 0xC0, dst, src);
}
+void Assembler::eandl(Register dst, Register src1, Register src2, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ // opcode matches gcc
+ emit_arith(0x21, 0xC0, src1, src2);
+}
+
void Assembler::andnl(Register dst, Register src1, Register src2) {
assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
@@ -1780,6 +1838,7 @@ void Assembler::call(Register dst) {
void Assembler::call(Address adr) {
+ assert(!adr._rspec.reloc()->is_data(), "should not use ExternalAddress for call");
InstructionMark im(this);
prefix(adr);
emit_int8((unsigned char)0xFF);
@@ -1813,6 +1872,12 @@ void Assembler::cmovl(Condition cc, Register dst, Register src) {
emit_opcode_prefix_and_encoding(0x40 | cc, 0xC0, encode);
}
+void Assembler::ecmovl(Condition cc, Register dst, Register src1, Register src2) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes);
+ emit_int16((0x40 | cc), (0xC0 | encode));
+}
+
void Assembler::cmovl(Condition cc, Register dst, Address src) {
InstructionMark im(this);
NOT_LP64(guarantee(VM_Version::supports_cmov(), "illegal instruction"));
@@ -1821,6 +1886,15 @@ void Assembler::cmovl(Condition cc, Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::ecmovl(Condition cc, Register dst, Register src1, Address src2) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes);
+ emit_int8((0x40 | cc));
+ emit_operand(src1, src2, 0);
+}
+
void Assembler::cmpb(Address dst, Register reg) {
assert(reg->has_byte_register(), "must have byte register");
InstructionMark im(this);
@@ -1845,6 +1919,11 @@ void Assembler::cmpb(Address dst, int imm8) {
emit_int8(imm8);
}
+void Assembler::cmpb(Register dst, int imm8) {
+ prefix(dst);
+ emit_arith_b(0x80, 0xF8, dst, imm8);
+}
+
void Assembler::cmpl(Address dst, int32_t imm32) {
InstructionMark im(this);
prefix(dst);
@@ -2439,6 +2518,15 @@ void Assembler::decl(Address dst) {
emit_operand(rcx, dst, 0);
}
+void Assembler::edecl(Register dst, Address src, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xFF);
+ emit_operand(rcx, src, 0);
+}
+
void Assembler::divsd(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
@@ -2484,21 +2572,45 @@ void Assembler::idivl(Register src) {
emit_int16((unsigned char)0xF7, (0xF8 | encode));
}
+void Assembler::eidivl(Register src, bool no_flags) { // Signed
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xF7, (0xF8 | encode));
+}
+
void Assembler::divl(Register src) { // Unsigned
int encode = prefix_and_encode(src->encoding());
emit_int16((unsigned char)0xF7, (0xF0 | encode));
}
+void Assembler::edivl(Register src, bool no_flags) { // Unsigned
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xF7, (0xF0 | encode));
+}
+
void Assembler::imull(Register src) {
int encode = prefix_and_encode(src->encoding());
emit_int16((unsigned char)0xF7, (0xE8 | encode));
}
+void Assembler::eimull(Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xF7, (0xE8 | encode));
+}
+
void Assembler::imull(Register dst, Register src) {
int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */);
emit_opcode_prefix_and_encoding((unsigned char)0xAF, 0xC0, encode);
}
+void Assembler::eimull(Register dst, Register src1, Register src2, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xAF, (0xC0 | encode));
+}
+
void Assembler::imull(Register dst, Address src, int32_t value) {
InstructionMark im(this);
prefix(src, dst);
@@ -2513,6 +2625,22 @@ void Assembler::imull(Register dst, Address src, int32_t value) {
}
}
+void Assembler::eimull(Register dst, Address src, int32_t value, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (is8bit(value)) {
+ emit_int8((unsigned char)0x6B);
+ emit_operand(dst, src, 1);
+ emit_int8(value);
+ } else {
+ emit_int8((unsigned char)0x69);
+ emit_operand(dst, src, 4);
+ emit_int32(value);
+ }
+}
+
void Assembler::imull(Register dst, Register src, int value) {
int encode = prefix_and_encode(dst->encoding(), src->encoding());
if (is8bit(value)) {
@@ -2523,6 +2651,17 @@ void Assembler::imull(Register dst, Register src, int value) {
}
}
+void Assembler::eimull(Register dst, Register src, int value, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (is8bit(value)) {
+ emit_int24(0x6B, (0xC0 | encode), value & 0xFF);
+ } else {
+ emit_int16(0x69, (0xC0 | encode));
+ emit_int32(value);
+ }
+}
+
void Assembler::imull(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst, false, true /* is_map1 */);
@@ -2530,6 +2669,14 @@ void Assembler::imull(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::eimull(Register dst, Register src1, Address src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xAF);
+ emit_operand(src1, src2, 0);
+}
void Assembler::incl(Address dst) {
// Don't use it directly. Use MacroAssembler::increment() instead.
@@ -2539,6 +2686,16 @@ void Assembler::incl(Address dst) {
emit_operand(rax, dst, 0);
}
+void Assembler::eincl(Register dst, Address src, bool no_flags) {
+ // Don't use it directly. Use MacroAssembler::increment() instead.
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xFF);
+ emit_operand(rax, src, 0);
+}
+
void Assembler::jcc(Condition cc, Label& L, bool maybe_short) {
InstructionMark im(this);
assert((0 <= cc) && (cc < 16), "illegal cc");
@@ -2706,6 +2863,13 @@ void Assembler::lzcntl(Register dst, Register src) {
emit_opcode_prefix_and_encoding((unsigned char)0xBD, 0xC0, encode);
}
+void Assembler::elzcntl(Register dst, Register src, bool no_flags) {
+ assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xF5, (0xC0 | encode));
+}
+
void Assembler::lzcntl(Register dst, Address src) {
assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR");
InstructionMark im(this);
@@ -2715,6 +2879,16 @@ void Assembler::lzcntl(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::elzcntl(Register dst, Address src, bool no_flags) {
+ assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR");
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xF5);
+ emit_operand(dst, src, 0);
+}
+
// Emit mfence instruction
void Assembler::mfence() {
NOT_LP64(assert(VM_Version::supports_sse2(), "unsupported");)
@@ -3865,11 +4039,26 @@ void Assembler::mull(Address src) {
emit_operand(rsp, src, 0);
}
+void Assembler::emull(Address src, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_nf(src, 0, 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xF7);
+ emit_operand(rsp, src, 0);
+}
+
void Assembler::mull(Register src) {
int encode = prefix_and_encode(src->encoding());
emit_int16((unsigned char)0xF7, (0xE0 | encode));
}
+void Assembler::emull(Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xF7, (0xE0 | encode));
+}
+
void Assembler::mulsd(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
@@ -3911,6 +4100,12 @@ void Assembler::negl(Register dst) {
emit_int16((unsigned char)0xF7, (0xD8 | encode));
}
+void Assembler::enegl(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xF7, (0xD8 | encode));
+}
+
void Assembler::negl(Address dst) {
InstructionMark im(this);
prefix(dst);
@@ -3918,6 +4113,15 @@ void Assembler::negl(Address dst) {
emit_operand(as_Register(3), dst, 0);
}
+void Assembler::enegl(Register dst, Address src, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xF7);
+ emit_operand(as_Register(3), src, 0);
+}
+
void Assembler::nop(uint i) {
#ifdef ASSERT
assert(i > 0, " ");
@@ -4229,9 +4433,16 @@ void Assembler::notl(Register dst) {
emit_int16((unsigned char)0xF7, (0xD0 | encode));
}
-void Assembler::orw(Register dst, Register src) {
- (void)prefix_and_encode(dst->encoding(), src->encoding());
- emit_arith(0x0B, 0xC0, dst, src);
+void Assembler::enotl(Register dst, Register src) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes);
+ emit_int16((unsigned char)0xF7, (0xD0 | encode));
+}
+
+void Assembler::eorw(Register dst, Register src1, Register src2, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith(0x0B, 0xC0, src1, src2);
}
void Assembler::orl(Address dst, int32_t imm32) {
@@ -4240,11 +4451,25 @@ void Assembler::orl(Address dst, int32_t imm32) {
emit_arith_operand(0x81, rcx, dst, imm32);
}
+void Assembler::eorl(Register dst, Address src, int32_t imm32, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith_operand(0x81, rcx, src, imm32);
+}
+
void Assembler::orl(Register dst, int32_t imm32) {
prefix(dst);
emit_arith(0x81, 0xC8, dst, imm32);
}
+void Assembler::eorl(Register dst, Register src, int32_t imm32, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith(0x81, 0xC8, src, imm32);
+}
+
void Assembler::orl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
@@ -4252,11 +4477,27 @@ void Assembler::orl(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::eorl(Register dst, Register src1, Address src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x0B);
+ emit_operand(src1, src2, 0);
+}
+
void Assembler::orl(Register dst, Register src) {
(void) prefix_and_encode(dst->encoding(), src->encoding());
emit_arith(0x0B, 0xC0, dst, src);
}
+void Assembler::eorl(Register dst, Register src1, Register src2, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ // opcode matches gcc
+ emit_arith(0x09, 0xC0, src1, src2);
+}
+
void Assembler::orl(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src);
@@ -4264,6 +4505,15 @@ void Assembler::orl(Address dst, Register src) {
emit_operand(src, dst, 0);
}
+void Assembler::eorl(Register dst, Address src1, Register src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x09);
+ emit_operand(src2, src1, 0);
+}
+
void Assembler::orb(Address dst, int imm8) {
InstructionMark im(this);
prefix(dst);
@@ -4272,6 +4522,16 @@ void Assembler::orb(Address dst, int imm8) {
emit_int8(imm8);
}
+void Assembler::eorb(Register dst, Address src, int imm8, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_8bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0x80);
+ emit_operand(rcx, src, 1);
+ emit_int8(imm8);
+}
+
void Assembler::orb(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src, true);
@@ -4279,6 +4539,15 @@ void Assembler::orb(Address dst, Register src) {
emit_operand(src, dst, 0);
}
+void Assembler::eorb(Register dst, Address src1, Register src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_8bit);
+ evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x08);
+ emit_operand(src2, src1, 0);
+}
+
void Assembler::packsswb(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -4464,22 +4733,6 @@ void Assembler::vpermpd(XMMRegister dst, XMMRegister src, int imm8, int vector_l
emit_int24(0x01, (0xC0 | encode), imm8);
}
-void Assembler::evpermi2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
- assert(VM_Version::supports_evex(), "");
- InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
- attributes.set_is_evex_instruction();
- int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
- emit_int16(0x76, (0xC0 | encode));
-}
-
-void Assembler::evpermt2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
- assert(VM_Version::supports_avx512_vbmi(), "");
- InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
- attributes.set_is_evex_instruction();
- int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
- emit_int16(0x7D, (0xC0 | encode));
-}
-
void Assembler::evpmultishiftqb(XMMRegister dst, XMMRegister ctl, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx512_vbmi(), "");
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -5399,6 +5652,16 @@ void Assembler::popcntl(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::epopcntl(Register dst, Address src, bool no_flags) {
+ assert(VM_Version::supports_popcnt(), "must support");
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0x88);
+ emit_operand(dst, src, 0);
+}
+
void Assembler::popcntl(Register dst, Register src) {
assert(VM_Version::supports_popcnt(), "must support");
emit_int8((unsigned char)0xF3);
@@ -5406,6 +5669,13 @@ void Assembler::popcntl(Register dst, Register src) {
emit_opcode_prefix_and_encoding((unsigned char)0xB8, 0xC0, encode);
}
+void Assembler::epopcntl(Register dst, Register src, bool no_flags) {
+ assert(VM_Version::supports_popcnt(), "must support");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0x88, (0xC0 | encode));
+}
+
void Assembler::evpopcntb(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len) {
assert(VM_Version::supports_avx512_bitalg(), "must support avx512bitalg feature");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
@@ -5994,6 +6264,17 @@ void Assembler::rcll(Register dst, int imm8) {
}
}
+void Assembler::ercll(Register dst, Register src, int imm8) {
+ assert(isShiftCount(imm8), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes);
+ if (imm8 == 1) {
+ emit_int16((unsigned char)0xD1, (0xD0 | encode));
+ } else {
+ emit_int24((unsigned char)0xC1, (0xD0 | encode), imm8);
+ }
+}
+
void Assembler::rcpps(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
@@ -6074,11 +6355,28 @@ void Assembler::roll(Register dst, int imm8) {
}
}
+void Assembler::eroll(Register dst, Register src, int imm8, bool no_flags) {
+ assert(isShiftCount(imm8), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int16((unsigned char)0xD1, (0xC0 | encode));
+ } else {
+ emit_int24((unsigned char)0xC1, (0xc0 | encode), imm8);
+ }
+}
+
void Assembler::roll(Register dst) {
int encode = prefix_and_encode(dst->encoding());
emit_int16((unsigned char)0xD3, (0xC0 | encode));
}
+void Assembler::eroll(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xD3, (0xC0 | encode));
+}
+
void Assembler::rorl(Register dst, int imm8) {
assert(isShiftCount(imm8), "illegal shift count");
int encode = prefix_and_encode(dst->encoding());
@@ -6089,17 +6387,40 @@ void Assembler::rorl(Register dst, int imm8) {
}
}
+void Assembler::erorl(Register dst, Register src, int imm8, bool no_flags) {
+ assert(isShiftCount(imm8), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int16((unsigned char)0xD1, (0xC8 | encode));
+ } else {
+ emit_int24((unsigned char)0xC1, (0xc8 | encode), imm8);
+ }
+}
+
void Assembler::rorl(Register dst) {
int encode = prefix_and_encode(dst->encoding());
emit_int16((unsigned char)0xD3, (0xC8 | encode));
}
+void Assembler::erorl(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xD3, (0xC8 | encode));
+}
+
#ifdef _LP64
void Assembler::rorq(Register dst) {
int encode = prefixq_and_encode(dst->encoding());
emit_int16((unsigned char)0xD3, (0xC8 | encode));
}
+void Assembler::erorq(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xD3, (0xC8 | encode));
+}
+
void Assembler::rorq(Register dst, int imm8) {
assert(isShiftCount(imm8 >> 1), "illegal shift count");
int encode = prefixq_and_encode(dst->encoding());
@@ -6110,12 +6431,29 @@ void Assembler::rorq(Register dst, int imm8) {
}
}
+void Assembler::erorq(Register dst, Register src, int imm8, bool no_flags) {
+ assert(isShiftCount(imm8), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int16((unsigned char)0xD1, (0xC8 | encode));
+ } else {
+ emit_int24((unsigned char)0xC1, (0xC8 | encode), imm8);
+ }
+}
+
void Assembler::rolq(Register dst) {
int encode = prefixq_and_encode(dst->encoding());
emit_int16((unsigned char)0xD3, (0xC0 | encode));
}
-void Assembler::rolq(Register dst, int imm8) {
+void Assembler::erolq(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xD3, (0xC0 | encode));
+}
+
+void Assembler::rolq(Register dst, int imm8) {
assert(isShiftCount(imm8 >> 1), "illegal shift count");
int encode = prefixq_and_encode(dst->encoding());
if (imm8 == 1) {
@@ -6124,6 +6462,17 @@ void Assembler::rolq(Register dst, int imm8) {
emit_int24((unsigned char)0xC1, (0xc0 | encode), imm8);
}
}
+
+void Assembler::erolq(Register dst, Register src, int imm8, bool no_flags) {
+ assert(isShiftCount(imm8), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int16((unsigned char)0xD1, (0xC0 | encode));
+ } else {
+ emit_int24((unsigned char)0xC1, (0xc0 | encode), imm8);
+ }
+ }
#endif
void Assembler::sahf() {
@@ -6149,6 +6498,23 @@ void Assembler::sall(Address dst, int imm8) {
}
}
+void Assembler::esall(Register dst, Address src, int imm8, bool no_flags) {
+ InstructionMark im(this);
+ assert(isShiftCount(imm8), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int8((unsigned char)0xD1);
+ emit_operand(as_Register(4), src, 0);
+ }
+ else {
+ emit_int8((unsigned char)0xC1);
+ emit_operand(as_Register(4), src, 1);
+ emit_int8(imm8);
+ }
+}
+
void Assembler::sall(Address dst) {
InstructionMark im(this);
prefix(dst);
@@ -6156,6 +6522,15 @@ void Assembler::sall(Address dst) {
emit_operand(as_Register(4), dst, 0);
}
+void Assembler::esall(Register dst, Address src, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xD3);
+ emit_operand(as_Register(4), src, 0);
+}
+
void Assembler::sall(Register dst, int imm8) {
assert(isShiftCount(imm8), "illegal shift count");
int encode = prefix_and_encode(dst->encoding());
@@ -6166,11 +6541,28 @@ void Assembler::sall(Register dst, int imm8) {
}
}
+void Assembler::esall(Register dst, Register src, int imm8, bool no_flags) {
+ assert(isShiftCount(imm8), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int16((unsigned char)0xD1, (0xE0 | encode));
+ } else {
+ emit_int24((unsigned char)0xC1, (0xE0 | encode), imm8);
+ }
+}
+
void Assembler::sall(Register dst) {
int encode = prefix_and_encode(dst->encoding());
emit_int16((unsigned char)0xD3, (0xE0 | encode));
}
+void Assembler::esall(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xD3, (0xE0 | encode));
+}
+
void Assembler::sarl(Address dst, int imm8) {
assert(isShiftCount(imm8), "illegal shift count");
InstructionMark im(this);
@@ -6186,6 +6578,23 @@ void Assembler::sarl(Address dst, int imm8) {
}
}
+void Assembler::esarl(Register dst, Address src, int imm8, bool no_flags) {
+ assert(isShiftCount(imm8), "illegal shift count");
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int8((unsigned char)0xD1);
+ emit_operand(as_Register(7), src, 0);
+ }
+ else {
+ emit_int8((unsigned char)0xC1);
+ emit_operand(as_Register(7), src, 1);
+ emit_int8(imm8);
+ }
+}
+
void Assembler::sarl(Address dst) {
InstructionMark im(this);
prefix(dst);
@@ -6193,6 +6602,15 @@ void Assembler::sarl(Address dst) {
emit_operand(as_Register(7), dst, 0);
}
+void Assembler::esarl(Register dst, Address src, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xD3);
+ emit_operand(as_Register(7), src, 0);
+}
+
void Assembler::sarl(Register dst, int imm8) {
int encode = prefix_and_encode(dst->encoding());
assert(isShiftCount(imm8), "illegal shift count");
@@ -6203,11 +6621,28 @@ void Assembler::sarl(Register dst, int imm8) {
}
}
+void Assembler::esarl(Register dst, Register src, int imm8, bool no_flags) {
+ assert(isShiftCount(imm8), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int16((unsigned char)0xD1, (0xF8 | encode));
+ } else {
+ emit_int24((unsigned char)0xC1, (0xF8 | encode), imm8);
+ }
+}
+
void Assembler::sarl(Register dst) {
int encode = prefix_and_encode(dst->encoding());
emit_int16((unsigned char)0xD3, (0xF8 | encode));
}
+void Assembler::esarl(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xD3, (0xF8 | encode));
+}
+
void Assembler::sbbl(Address dst, int32_t imm32) {
InstructionMark im(this);
prefix(dst);
@@ -6219,7 +6654,6 @@ void Assembler::sbbl(Register dst, int32_t imm32) {
emit_arith(0x81, 0xD8, dst, imm32);
}
-
void Assembler::sbbl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
@@ -6312,6 +6746,26 @@ void Assembler::sha256msg2(XMMRegister dst, XMMRegister src) {
emit_int16((unsigned char)0xCD, (0xC0 | encode));
}
+void Assembler::sha512msg1(XMMRegister dst, XMMRegister src) {
+ assert(VM_Version::supports_sha512() && VM_Version::supports_avx(), "");
+ InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes);
+ emit_int16((unsigned char)0xCC, (0xC0 | encode));
+}
+
+void Assembler::sha512msg2(XMMRegister dst, XMMRegister src) {
+ assert(VM_Version::supports_sha512() && VM_Version::supports_avx(), "");
+ InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes);
+ emit_int16((unsigned char)0xCD, (0xC0 | encode));
+}
+
+void Assembler::sha512rnds2(XMMRegister dst, XMMRegister nds, XMMRegister src) {
+ assert(VM_Version::supports_sha512() && VM_Version::supports_avx(), "");
+ InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes);
+ emit_int16((unsigned char)0xCB, (0xC0 | encode));
+}
void Assembler::shll(Register dst, int imm8) {
assert(isShiftCount(imm8), "illegal shift count");
@@ -6323,11 +6777,28 @@ void Assembler::shll(Register dst, int imm8) {
}
}
+void Assembler::eshll(Register dst, Register src, int imm8, bool no_flags) {
+ assert(isShiftCount(imm8), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1 ) {
+ emit_int16((unsigned char)0xD1, (0xE0 | encode));
+ } else {
+ emit_int24((unsigned char)0xC1, (0xE0 | encode), imm8);
+ }
+}
+
void Assembler::shll(Register dst) {
int encode = prefix_and_encode(dst->encoding());
emit_int16((unsigned char)0xD3, (0xE0 | encode));
}
+void Assembler::eshll(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xD3, (0xE0 | encode));
+}
+
void Assembler::shrl(Register dst, int imm8) {
assert(isShiftCount(imm8), "illegal shift count");
int encode = prefix_and_encode(dst->encoding());
@@ -6339,11 +6810,29 @@ void Assembler::shrl(Register dst, int imm8) {
}
}
+void Assembler::eshrl(Register dst, Register src, int imm8, bool no_flags) {
+ assert(isShiftCount(imm8), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int16((unsigned char)0xD1, (0xE8 | encode));
+ }
+ else {
+ emit_int24((unsigned char)0xC1, (0xE8 | encode), imm8);
+ }
+}
+
void Assembler::shrl(Register dst) {
int encode = prefix_and_encode(dst->encoding());
emit_int16((unsigned char)0xD3, (0xE8 | encode));
}
+void Assembler::eshrl(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xD3, (0xE8 | encode));
+}
+
void Assembler::shrl(Address dst) {
InstructionMark im(this);
prefix(dst);
@@ -6351,6 +6840,15 @@ void Assembler::shrl(Address dst) {
emit_operand(as_Register(5), dst, 0);
}
+void Assembler::eshrl(Register dst, Address src, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xD3);
+ emit_operand(as_Register(5), src, 0);
+}
+
void Assembler::shrl(Address dst, int imm8) {
InstructionMark im(this);
assert(isShiftCount(imm8), "illegal shift count");
@@ -6366,37 +6864,89 @@ void Assembler::shrl(Address dst, int imm8) {
}
}
+void Assembler::eshrl(Register dst, Address src, int imm8, bool no_flags) {
+ InstructionMark im(this);
+ assert(isShiftCount(imm8), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int8((unsigned char)0xD1);
+ emit_operand(as_Register(5), src, 0);
+ }
+ else {
+ emit_int8((unsigned char)0xC1);
+ emit_operand(as_Register(5), src, 1);
+ emit_int8(imm8);
+ }
+}
void Assembler::shldl(Register dst, Register src) {
int encode = prefix_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */);
emit_opcode_prefix_and_encoding((unsigned char)0xA5, 0xC0, encode);
}
+void Assembler::eshldl(Register dst, Register src1, Register src2, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16(0xA5, (0xC0 | encode));
+}
+
void Assembler::shldl(Register dst, Register src, int8_t imm8) {
int encode = prefix_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */);
emit_opcode_prefix_and_encoding((unsigned char)0xA4, 0xC0, encode, imm8);
}
+void Assembler::eshldl(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int24(0x24, (0xC0 | encode), imm8);
+}
+
void Assembler::shrdl(Register dst, Register src) {
int encode = prefix_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */);
emit_opcode_prefix_and_encoding((unsigned char)0xAD, 0xC0, encode);
}
+void Assembler::eshrdl(Register dst, Register src1, Register src2, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16(0xAD, (0xC0 | encode));
+}
+
void Assembler::shrdl(Register dst, Register src, int8_t imm8) {
int encode = prefix_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */);
emit_opcode_prefix_and_encoding((unsigned char)0xAC, 0xC0, encode, imm8);
}
+void Assembler::eshrdl(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int24(0x2C, (0xC0 | encode), imm8);
+}
+
#ifdef _LP64
void Assembler::shldq(Register dst, Register src, int8_t imm8) {
int encode = prefixq_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */);
emit_opcode_prefix_and_encoding((unsigned char)0xA4, 0xC0, encode, imm8);
}
+void Assembler::eshldq(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int24(0x24, (0xC0 | encode), imm8);
+}
+
void Assembler::shrdq(Register dst, Register src, int8_t imm8) {
int encode = prefixq_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */);
emit_opcode_prefix_and_encoding((unsigned char)0xAC, 0xC0, encode, imm8);
}
+
+void Assembler::eshrdq(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int24(0x2C, (0xC0 | encode), imm8);
+}
#endif
// copies a single word from [esi] to [edi]
@@ -6487,6 +7037,14 @@ void Assembler::subl(Address dst, int32_t imm32) {
emit_arith_operand(0x81, rbp, dst, imm32);
}
+void Assembler::esubl(Register dst, Address src, int32_t imm32, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith_operand(0x81, rbp, src, imm32);
+}
+
void Assembler::subl(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src);
@@ -6494,17 +7052,38 @@ void Assembler::subl(Address dst, Register src) {
emit_operand(src, dst, 0);
}
+void Assembler::esubl(Register dst, Address src1, Register src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x29);
+ emit_operand(src2, src1, 0);
+}
+
void Assembler::subl(Register dst, int32_t imm32) {
prefix(dst);
emit_arith(0x81, 0xE8, dst, imm32);
}
+void Assembler::esubl(Register dst, Register src, int32_t imm32, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith(0x81, 0xE8, src, imm32);
+}
+
// Force generation of a 4 byte immediate value even if it fits into 8bit
void Assembler::subl_imm32(Register dst, int32_t imm32) {
prefix(dst);
emit_arith_imm32(0x81, 0xE8, dst, imm32);
}
+void Assembler::esubl_imm32(Register dst, Register src, int32_t imm32, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith_imm32(0x81, 0xE8, src, imm32);
+}
+
void Assembler::subl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
@@ -6512,11 +7091,27 @@ void Assembler::subl(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::esubl(Register dst, Register src1, Address src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x2B);
+ emit_operand(src1, src2, 0);
+}
+
void Assembler::subl(Register dst, Register src) {
(void) prefix_and_encode(dst->encoding(), src->encoding());
emit_arith(0x2B, 0xC0, dst, src);
}
+void Assembler::esubl(Register dst, Register src2, Register src1, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ // opcode matches gcc
+ emit_arith(0x29, 0xC0, src1, src2);
+}
+
void Assembler::subsd(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
@@ -6620,6 +7215,13 @@ void Assembler::tzcntl(Register dst, Register src) {
emit_opcode_prefix_and_encoding((unsigned char)0xBC, 0xC0, encode);
}
+void Assembler::etzcntl(Register dst, Register src, bool no_flags) {
+ assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xF4, (0xC0 | encode));
+}
+
void Assembler::tzcntl(Register dst, Address src) {
assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported");
InstructionMark im(this);
@@ -6629,6 +7231,16 @@ void Assembler::tzcntl(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::etzcntl(Register dst, Address src, bool no_flags) {
+ assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported");
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xF4);
+ emit_operand(dst, src, 0);
+}
+
void Assembler::tzcntq(Register dst, Register src) {
assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported");
emit_int8((unsigned char)0xF3);
@@ -6636,6 +7248,13 @@ void Assembler::tzcntq(Register dst, Register src) {
emit_opcode_prefix_and_encoding((unsigned char)0xBC, 0xC0, encode);
}
+void Assembler::etzcntq(Register dst, Register src, bool no_flags) {
+ assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xF4, (0xC0 | encode));
+}
+
void Assembler::tzcntq(Register dst, Address src) {
assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported");
InstructionMark im(this);
@@ -6645,6 +7264,16 @@ void Assembler::tzcntq(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::etzcntq(Register dst, Address src, bool no_flags) {
+ assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported");
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xF4);
+ emit_operand(dst, src, 0);
+}
+
void Assembler::ucomisd(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
@@ -6764,11 +7393,25 @@ void Assembler::xorl(Address dst, int32_t imm32) {
emit_arith_operand(0x81, as_Register(6), dst, imm32);
}
+void Assembler::exorl(Register dst, Address src, int32_t imm32, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith_operand(0x81, as_Register(6), src, imm32);
+}
+
void Assembler::xorl(Register dst, int32_t imm32) {
prefix(dst);
emit_arith(0x81, 0xF0, dst, imm32);
}
+void Assembler::exorl(Register dst, Register src, int32_t imm32, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith(0x81, 0xF0, src, imm32);
+}
+
void Assembler::xorl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
@@ -6776,11 +7419,27 @@ void Assembler::xorl(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::exorl(Register dst, Register src1, Address src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x33);
+ emit_operand(src1, src2, 0);
+}
+
void Assembler::xorl(Register dst, Register src) {
(void) prefix_and_encode(dst->encoding(), src->encoding());
emit_arith(0x33, 0xC0, dst, src);
}
+void Assembler::exorl(Register dst, Register src1, Register src2, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ // opcode matches gcc
+ emit_arith(0x31, 0xC0, src1, src2);
+}
+
void Assembler::xorl(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src);
@@ -6788,6 +7447,15 @@ void Assembler::xorl(Address dst, Register src) {
emit_operand(src, dst, 0);
}
+void Assembler::exorl(Register dst, Address src1, Register src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x31);
+ emit_operand(src2, src1, 0);
+}
+
void Assembler::xorb(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
@@ -6795,6 +7463,15 @@ void Assembler::xorb(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::exorb(Register dst, Register src1, Address src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_8bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x32);
+ emit_operand(src1, src2, 0);
+}
+
void Assembler::xorb(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src, true);
@@ -6802,9 +7479,13 @@ void Assembler::xorb(Address dst, Register src) {
emit_operand(src, dst, 0);
}
-void Assembler::xorw(Register dst, Register src) {
- (void)prefix_and_encode(dst->encoding(), src->encoding());
- emit_arith(0x33, 0xC0, dst, src);
+void Assembler::exorb(Register dst, Address src1, Register src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_8bit);
+ evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x30);
+ emit_operand(src2, src1, 0);
}
void Assembler::xorw(Register dst, Address src) {
@@ -6815,6 +7496,16 @@ void Assembler::xorw(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::exorw(Register dst, Register src1, Address src2, bool no_flags) {
+ InstructionMark im(this);
+ emit_int8(0x66);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x33);
+ emit_operand(src1, src2, 0);
+}
+
// AVX 3-operands scalar float-point arithmetic instructions
void Assembler::vaddsd(XMMRegister dst, XMMRegister nds, Address src) {
@@ -7362,6 +8053,14 @@ void Assembler::andpd(XMMRegister dst, XMMRegister src) {
emit_int16(0x54, (0xC0 | encode));
}
+void Assembler::andnpd(XMMRegister dst, XMMRegister src) {
+ NOT_LP64(assert(VM_Version::supports_sse2(), ""));
+ InstructionAttr attributes(AVX_128bit, /* rex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_rex_vex_w_reverted();
+ int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
+ emit_int16(0x55, (0xC0 | encode));
+}
+
void Assembler::andps(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -8973,6 +9672,15 @@ void Assembler::vinserti64x4(XMMRegister dst, XMMRegister nds, XMMRegister src,
emit_int24(0x3A, (0xC0 | encode), imm8 & 0x01);
}
+void Assembler::evinserti64x2(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8, int vector_len) {
+ assert(VM_Version::supports_avx512dq(), "");
+ assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
+ InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_is_evex_instruction();
+ int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
+ emit_int24(0x38, (0xC0 | encode), imm8 & 0x03);
+}
+
// vinsertf forms
@@ -10978,10 +11686,23 @@ void Assembler::evbroadcasti64x2(XMMRegister dst, Address src, int vector_len) {
emit_operand(dst, src, 0);
}
-// scalar single/double precision replicate
-
-// duplicate single precision data from src into programmed locations in dest : requires AVX512VL
-void Assembler::vbroadcastss(XMMRegister dst, XMMRegister src, int vector_len) {
+void Assembler::vbroadcasti128(XMMRegister dst, Address src, int vector_len) {
+ assert(VM_Version::supports_avx2(), "");
+ assert(vector_len == AVX_256bit, "");
+ assert(dst != xnoreg, "sanity");
+ InstructionMark im(this);
+ InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit);
+ // swap src<->dst for encoding
+ vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int8(0x5A);
+ emit_operand(dst, src, 0);
+}
+
+// scalar single/double precision replicate
+
+// duplicate single precision data from src into programmed locations in dest : requires AVX512VL
+void Assembler::vbroadcastss(XMMRegister dst, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx2(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
@@ -11037,6 +11758,21 @@ void Assembler::vbroadcastf128(XMMRegister dst, Address src, int vector_len) {
emit_operand(dst, src, 0);
}
+void Assembler::evbroadcastf64x2(XMMRegister dst, Address src, int vector_len) {
+ assert(VM_Version::supports_avx512dq(), "");
+ assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
+ assert(dst != xnoreg, "sanity");
+ InstructionMark im(this);
+ InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_T2, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_is_evex_instruction();
+ // swap src<->dst for encoding
+ vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int8(0x1A);
+ emit_operand(dst, src, 0);
+}
+
+
// gpr source broadcast forms
// duplicate 1-byte integer data from src into programmed locations in dest : requires AVX512BW and AVX512VL
@@ -11398,6 +12134,12 @@ void Assembler::decl(Register dst) {
emit_int8(0x48 | dst->encoding());
}
+void Assembler::edecl(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x48 | src->encoding());
+}
+
// 64bit doesn't use the x87
void Assembler::fabs() {
@@ -11836,7 +12578,7 @@ void Assembler::vex_prefix(bool vex_r, bool vex_b, bool vex_x, int nds_enc, VexS
// This is a 4 byte encoding
void Assembler::evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, bool eevex_b, bool evex_v,
- bool eevex_x, int nds_enc, VexSimdPrefix pre, VexOpcode opc) {
+ bool eevex_x, int nds_enc, VexSimdPrefix pre, VexOpcode opc, bool no_flags) {
// EVEX 0x62 prefix
// byte1 = EVEX_4bytes;
@@ -11862,11 +12604,17 @@ void Assembler::evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, boo
// of form {66, F3, F2}
byte3 |= pre;
- // P2: byte 4 as zL'Lbv'aaa
- // kregs are implemented in the low 3 bits as aaa
- int byte4 = (_attributes->is_no_reg_mask()) ?
- 0 :
- _attributes->get_embedded_opmask_register_specifier();
+ // P2: byte 4 as zL'Lbv'aaa or 00LXVF00 where V = V4, X(extended context) = ND and F = NF (no flags)
+ int byte4 = 0;
+ if (no_flags) {
+ assert(_attributes->is_no_reg_mask(), "mask register not supported with no_flags");
+ byte4 |= 0x4;
+ } else {
+ // kregs are implemented in the low 3 bits as aaa
+ byte4 = (_attributes->is_no_reg_mask()) ?
+ 0 :
+ _attributes->get_embedded_opmask_register_specifier();
+ }
// EVEX.v` for extending EVEX.vvvv or VIDX
byte4 |= (evex_v ? 0: EVEX_V);
// third EXEC.b for broadcast actions
@@ -11881,11 +12629,12 @@ void Assembler::evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, boo
emit_int32(EVEX_4bytes, byte2, byte3, byte4);
}
-void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes) {
- if (adr.base_needs_rex2() || adr.index_needs_rex2()) {
+void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool nds_is_ndd, bool no_flags) {
+ if (adr.base_needs_rex2() || adr.index_needs_rex2() || nds_is_ndd || no_flags) {
assert(UseAPX, "APX features not enabled");
}
- bool is_extended = adr.base_needs_rex2() || adr.index_needs_rex2() || nds_enc >= 16 || xreg_enc >= 16;
+ if (nds_is_ndd) attributes->set_extended_context();
+ bool is_extended = adr.base_needs_rex2() || adr.index_needs_rex2() || nds_enc >= 16 || xreg_enc >= 16 || nds_is_ndd;
bool vex_r = (xreg_enc & 8) == 8;
bool vex_b = adr.base_needs_rex();
bool vex_x;
@@ -11928,7 +12677,7 @@ void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix
bool eevex_x = adr.index_needs_rex2();
bool eevex_b = adr.base_needs_rex2();
attributes->set_is_evex_instruction();
- evex_prefix(vex_r, vex_b, vex_x, evex_r, eevex_b, evex_v, eevex_x, nds_enc, pre, opc);
+ evex_prefix(vex_r, vex_b, vex_x, evex_r, eevex_b, evex_v, eevex_x, nds_enc, pre, opc, no_flags);
} else {
if (UseAVX > 2 && attributes->is_rex_vex_w_reverted()) {
attributes->set_rex_vex_w(false);
@@ -11937,10 +12686,21 @@ void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix
}
}
-int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool src_is_gpr) {
- if (src_is_gpr && src_enc >= 16) {
+void Assembler::evex_prefix_ndd(Address adr, int ndd_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool no_flags) {
+ attributes->set_is_evex_instruction();
+ vex_prefix(adr, ndd_enc, xreg_enc, pre, opc, attributes, /* nds_is_ndd */ true, no_flags);
+}
+
+void Assembler::evex_prefix_nf(Address adr, int ndd_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool no_flags) {
+ attributes->set_is_evex_instruction();
+ vex_prefix(adr, ndd_enc, xreg_enc, pre, opc, attributes, /* nds_is_ndd */ false, no_flags);
+}
+
+int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool src_is_gpr, bool nds_is_ndd, bool no_flags) {
+ if (nds_is_ndd || no_flags || (src_is_gpr && src_enc >= 16)) {
assert(UseAPX, "APX features not enabled");
}
+ if (nds_is_ndd) attributes->set_extended_context();
bool is_extended = dst_enc >= 16 || nds_enc >= 16 || src_enc >=16;
bool vex_r = (dst_enc & 8) == 8;
bool vex_b = (src_enc & 8) == 8;
@@ -11982,7 +12742,7 @@ int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexS
// can use vex_x as bank extender on rm encoding
vex_x = (src_enc >= 16) && !src_is_gpr;
attributes->set_is_evex_instruction();
- evex_prefix(vex_r, vex_b, vex_x, evex_r, evex_b, evex_v, false /*eevex_x*/, nds_enc, pre, opc);
+ evex_prefix(vex_r, vex_b, vex_x, evex_r, evex_b, evex_v, false /*eevex_x*/, nds_enc, pre, opc, no_flags);
} else {
if (UseAVX > 2 && attributes->is_rex_vex_w_reverted()) {
attributes->set_rex_vex_w(false);
@@ -11994,6 +12754,18 @@ int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexS
return (((dst_enc & 7) << 3) | (src_enc & 7));
}
+int Assembler::evex_prefix_and_encode_ndd(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc,
+ InstructionAttr *attributes, bool no_flags) {
+ attributes->set_is_evex_instruction();
+ return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, attributes, /* src_is_gpr */ true, /* nds_is_ndd */ true, no_flags);
+}
+
+int Assembler::evex_prefix_and_encode_nf(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc,
+ InstructionAttr *attributes, bool no_flags) {
+ attributes->set_is_evex_instruction();
+ return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, attributes, /* src_is_gpr */ true, /* nds_is_ndd */ false, no_flags);
+}
+
void Assembler::simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr, VexSimdPrefix pre,
VexOpcode opc, InstructionAttr *attributes) {
if (UseAVX > 0) {
@@ -12838,6 +13610,12 @@ void Assembler::incl(Register dst) {
emit_int8(0x40 | dst->encoding());
}
+void Assembler::eincl(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x40 | src->encoding());
+}
+
void Assembler::lea(Register dst, Address src) {
leal(dst, src);
}
@@ -13462,28 +14240,67 @@ void Assembler::addq(Address dst, int32_t imm32) {
emit_arith_operand(0x81, rax, dst, imm32);
}
+void Assembler::eaddq(Register dst, Address src, int32_t imm32, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith_operand(0x81, rax, src, imm32);
+}
+
void Assembler::addq(Address dst, Register src) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(dst, src), 0x01);
emit_operand(src, dst, 0);
}
+void Assembler::eaddq(Register dst, Address src1, Register src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x01);
+ emit_operand(src2, src1, 0);
+}
+
void Assembler::addq(Register dst, int32_t imm32) {
(void) prefixq_and_encode(dst->encoding());
emit_arith(0x81, 0xC0, dst, imm32);
}
+void Assembler::eaddq(Register dst, Register src, int32_t imm32, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith(0x81, 0xC0, src, imm32);
+}
+
void Assembler::addq(Register dst, Address src) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(src, dst), 0x03);
emit_operand(dst, src, 0);
}
+void Assembler::eaddq(Register dst, Register src1, Address src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x03);
+ emit_operand(src1, src2, 0);
+}
+
void Assembler::addq(Register dst, Register src) {
(void) prefixq_and_encode(dst->encoding(), src->encoding());
emit_arith(0x03, 0xC0, dst, src);
}
+void Assembler::eaddq(Register dst, Register src1, Register src2, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ // opcode matches gcc
+ emit_arith(0x01, 0xC0, src1, src2);
+}
+
void Assembler::adcxq(Register dst, Register src) {
//assert(VM_Version::supports_adx(), "adx instructions not supported");
if (needs_rex2(dst, src)) {
@@ -13500,6 +14317,12 @@ void Assembler::adcxq(Register dst, Register src) {
}
}
+void Assembler::eadcxq(Register dst, Register src1, Register src2) {
+ InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3C, &attributes);
+ emit_int16((unsigned char)0x66, (0xC0 | encode));
+}
+
void Assembler::adoxq(Register dst, Register src) {
//assert(VM_Version::supports_adx(), "adx instructions not supported");
if (needs_rex2(dst, src)) {
@@ -13515,34 +14338,80 @@ void Assembler::adoxq(Register dst, Register src) {
(0xC0 | encode));
}
}
+
+void Assembler::eadoxq(Register dst, Register src1, Register src2) {
+ InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_3C, &attributes);
+ emit_int16((unsigned char)0x66, (0xC0 | encode));
+}
+
void Assembler::andq(Address dst, int32_t imm32) {
InstructionMark im(this);
prefixq(dst);
emit_arith_operand(0x81, as_Register(4), dst, imm32);
}
+void Assembler::eandq(Register dst, Address src, int32_t imm32, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith_operand(0x81, as_Register(4), src, imm32);
+}
+
void Assembler::andq(Register dst, int32_t imm32) {
(void) prefixq_and_encode(dst->encoding());
emit_arith(0x81, 0xE0, dst, imm32);
}
+void Assembler::eandq(Register dst, Register src, int32_t imm32, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith(0x81, 0xE0, src, imm32);
+}
+
void Assembler::andq(Register dst, Address src) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(src, dst), 0x23);
emit_operand(dst, src, 0);
}
+void Assembler::eandq(Register dst, Register src1, Address src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x23);
+ emit_operand(src1, src2, 0);
+}
+
void Assembler::andq(Register dst, Register src) {
(void) prefixq_and_encode(dst->encoding(), src->encoding());
emit_arith(0x23, 0xC0, dst, src);
}
+void Assembler::eandq(Register dst, Register src1, Register src2, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ // opcode matches gcc
+ emit_arith(0x21, 0xC0, src1, src2);
+}
+
void Assembler::andq(Address dst, Register src) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(dst, src), 0x21);
emit_operand(src, dst, 0);
}
+void Assembler::eandq(Register dst, Address src1, Register src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x21);
+ emit_operand(src2, src1, 0);
+}
+
void Assembler::andnq(Register dst, Register src1, Register src2) {
assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
@@ -13676,6 +14545,12 @@ void Assembler::cmovq(Condition cc, Register dst, Register src) {
emit_opcode_prefix_and_encoding((0x40 | cc), 0xC0, encode);
}
+void Assembler::ecmovq(Condition cc, Register dst, Register src1, Register src2) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes);
+ emit_int16((0x40 | cc), (0xC0 | encode));
+}
+
void Assembler::cmovq(Condition cc, Register dst, Address src) {
InstructionMark im(this);
int prefix = get_prefixq(src, dst, true /* is_map1 */);
@@ -13683,6 +14558,15 @@ void Assembler::cmovq(Condition cc, Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::ecmovq(Condition cc, Register dst, Register src1, Address src2) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes);
+ emit_int8((0x40 | cc));
+ emit_operand(src1, src2, 0);
+}
+
void Assembler::cmpq(Address dst, int32_t imm32) {
InstructionMark im(this);
prefixq(dst);
@@ -13784,6 +14668,12 @@ void Assembler::decl(Register dst) {
emit_int16((unsigned char)0xFF, (0xC8 | encode));
}
+void Assembler::edecl(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xFF, (0xC8 | encode));
+}
+
void Assembler::decq(Register dst) {
// Don't use it directly. Use MacroAssembler::decrementq() instead.
// Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
@@ -13791,6 +14681,12 @@ void Assembler::decq(Register dst) {
emit_int16((unsigned char)0xFF, 0xC8 | encode);
}
+void Assembler::edecq(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xFF, (0xC8 | encode));
+}
+
void Assembler::decq(Address dst) {
// Don't use it directly. Use MacroAssembler::decrementq() instead.
InstructionMark im(this);
@@ -13798,6 +14694,15 @@ void Assembler::decq(Address dst) {
emit_operand(rcx, dst, 0);
}
+void Assembler::edecq(Register dst, Address src, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xFF);
+ emit_operand(rcx, src, 0);
+}
+
// can't use REX2
void Assembler::fxrstor(Address src) {
InstructionMark im(this);
@@ -13831,21 +14736,51 @@ void Assembler::idivq(Register src) {
emit_int16((unsigned char)0xF7, (0xF8 | encode));
}
+void Assembler::eidivq(Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xF7, (0xF8 | encode));
+}
+
void Assembler::divq(Register src) {
int encode = prefixq_and_encode(src->encoding());
emit_int16((unsigned char)0xF7, (0xF0 | encode));
}
+void Assembler::edivq(Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xF7, (0xF0 | encode));
+}
+
void Assembler::imulq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */);
emit_opcode_prefix_and_encoding((unsigned char)0xAF, 0xC0, encode);
}
+void Assembler::eimulq(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xAF, (0xC0 | encode));
+}
+
+void Assembler::eimulq(Register dst, Register src1, Register src2, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xAF, (0xC0 | encode));
+}
+
void Assembler::imulq(Register src) {
int encode = prefixq_and_encode(src->encoding());
emit_int16((unsigned char)0xF7, (0xE8 | encode));
}
+void Assembler::eimulq(Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xF7, (0xE8 | encode));
+}
+
void Assembler::imulq(Register dst, Address src, int32_t value) {
InstructionMark im(this);
prefixq(src, dst);
@@ -13860,6 +14795,22 @@ void Assembler::imulq(Register dst, Address src, int32_t value) {
}
}
+void Assembler::eimulq(Register dst, Address src, int32_t value, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (is8bit(value)) {
+ emit_int8((unsigned char)0x6B);
+ emit_operand(dst, src, 1);
+ emit_int8(value);
+ } else {
+ emit_int8((unsigned char)0x69);
+ emit_operand(dst, src, 4);
+ emit_int32(value);
+ }
+}
+
void Assembler::imulq(Register dst, Register src, int value) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
if (is8bit(value)) {
@@ -13870,6 +14821,17 @@ void Assembler::imulq(Register dst, Register src, int value) {
}
}
+void Assembler::eimulq(Register dst, Register src, int value, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, /* src_is_gpr */ true, /* nds_is_ndd */ false, no_flags);
+ if (is8bit(value)) {
+ emit_int24(0x6B, (0xC0 | encode), (value & 0xFF));
+ } else {
+ emit_int16(0x69, (0xC0 | encode));
+ emit_int32(value);
+ }
+}
+
void Assembler::imulq(Register dst, Address src) {
InstructionMark im(this);
int prefix = get_prefixq(src, dst, true /* is_map1 */);
@@ -13877,6 +14839,23 @@ void Assembler::imulq(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::eimulq(Register dst, Address src, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes, /* nds_is_ndd */ false, no_flags);
+ emit_int8((unsigned char)0xAF);
+ emit_operand(dst, src, 0);
+}
+
+void Assembler::eimulq(Register dst, Register src1, Address src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xAF);
+ emit_operand(src1, src2, 0);
+}
+
void Assembler::incl(Register dst) {
// Don't use it directly. Use MacroAssembler::incrementl() instead.
// Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
@@ -13884,6 +14863,15 @@ void Assembler::incl(Register dst) {
emit_int16((unsigned char)0xFF, (0xC0 | encode));
}
+void Assembler::eincl(Register dst, Register src, bool no_flags) {
+ // Don't use it directly. Use MacroAssembler::incrementl() instead.
+ // Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ // int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xFF, (0xC0 | encode));
+}
+
void Assembler::incq(Register dst) {
// Don't use it directly. Use MacroAssembler::incrementq() instead.
// Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
@@ -13891,6 +14879,14 @@ void Assembler::incq(Register dst) {
emit_int16((unsigned char)0xFF, (0xC0 | encode));
}
+void Assembler::eincq(Register dst, Register src, bool no_flags) {
+ // Don't use it directly. Use MacroAssembler::incrementq() instead.
+ // Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xFF, (0xC0 | encode));
+}
+
void Assembler::incq(Address dst) {
// Don't use it directly. Use MacroAssembler::incrementq() instead.
InstructionMark im(this);
@@ -13898,6 +14894,16 @@ void Assembler::incq(Address dst) {
emit_operand(rax, dst, 0);
}
+void Assembler::eincq(Register dst, Address src, bool no_flags) {
+ // Don't use it directly. Use MacroAssembler::incrementq() instead.
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char) 0xFF);
+ emit_operand(rax, src, 0);
+}
+
void Assembler::lea(Register dst, Address src) {
leaq(dst, src);
}
@@ -13966,6 +14972,13 @@ void Assembler::lzcntq(Register dst, Register src) {
emit_opcode_prefix_and_encoding((unsigned char)0xBD, 0xC0, encode);
}
+void Assembler::elzcntq(Register dst, Register src, bool no_flags) {
+ assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xF5, (0xC0 | encode));
+}
+
void Assembler::lzcntq(Register dst, Address src) {
assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR");
InstructionMark im(this);
@@ -13975,6 +14988,16 @@ void Assembler::lzcntq(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::elzcntq(Register dst, Address src, bool no_flags) {
+ assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR");
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xF5);
+ emit_operand(dst, src, 0);
+}
+
void Assembler::movdq(XMMRegister dst, Register src) {
// table D-1 says MMX/SSE2
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
@@ -14097,11 +15120,26 @@ void Assembler::mulq(Address src) {
emit_operand(rsp, src, 0);
}
+void Assembler::emulq(Address src, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_nf(src, 0, 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0xF7);
+ emit_operand(rsp, src, 0);
+}
+
void Assembler::mulq(Register src) {
int encode = prefixq_and_encode(src->encoding());
emit_int16((unsigned char)0xF7, (0xE0 | encode));
}
+void Assembler::emulq(Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xF7, (0xE0 | encode));
+}
+
void Assembler::mulxq(Register dst1, Register dst2, Register src) {
assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported");
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
@@ -14114,17 +15152,38 @@ void Assembler::negq(Register dst) {
emit_int16((unsigned char)0xF7, (0xD8 | encode));
}
+void Assembler::enegq(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xF7, (0xD8 | encode));
+}
+
void Assembler::negq(Address dst) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xF7);
emit_operand(as_Register(3), dst, 0);
}
+void Assembler::enegq(Register dst, Address src, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xF7);
+ emit_operand(as_Register(3), src, 0);
+}
+
void Assembler::notq(Register dst) {
int encode = prefixq_and_encode(dst->encoding());
emit_int16((unsigned char)0xF7, (0xD0 | encode));
}
+void Assembler::enotq(Register dst, Register src) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes);
+ emit_int16((unsigned char)0xF7, (0xD0 | encode));
+}
+
void Assembler::btq(Register dst, Register src) {
int encode = prefixq_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */);
emit_opcode_prefix_and_encoding((unsigned char)0xA3, 0xC0, encode);
@@ -14161,33 +15220,78 @@ void Assembler::orq(Address dst, int32_t imm32) {
emit_arith_operand(0x81, as_Register(1), dst, imm32);
}
+void Assembler::eorq(Register dst, Address src, int32_t imm32, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith_operand(0x81, as_Register(1), src, imm32);
+}
+
void Assembler::orq(Address dst, Register src) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(dst, src), (unsigned char)0x09);
emit_operand(src, dst, 0);
}
+void Assembler::eorq(Register dst, Address src1, Register src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x09);
+ emit_operand(src2, src1, 0);
+}
+
void Assembler::orq(Register dst, int32_t imm32) {
(void) prefixq_and_encode(dst->encoding());
emit_arith(0x81, 0xC8, dst, imm32);
}
+void Assembler::eorq(Register dst, Register src, int32_t imm32, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith(0x81, 0xC8, src, imm32);
+}
+
void Assembler::orq_imm32(Register dst, int32_t imm32) {
(void) prefixq_and_encode(dst->encoding());
emit_arith_imm32(0x81, 0xC8, dst, imm32);
}
+void Assembler::eorq_imm32(Register dst, Register src, int32_t imm32, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith_imm32(0x81, 0xC8, src, imm32);
+}
+
void Assembler::orq(Register dst, Address src) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(src, dst), 0x0B);
emit_operand(dst, src, 0);
}
+void Assembler::eorq(Register dst, Register src1, Address src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x0B);
+ emit_operand(src1, src2, 0);
+}
+
void Assembler::orq(Register dst, Register src) {
(void) prefixq_and_encode(dst->encoding(), src->encoding());
emit_arith(0x0B, 0xC0, dst, src);
}
+void Assembler::eorq(Register dst, Register src1, Register src2, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ // opcode matches gcc
+ emit_arith(0x09, 0xC0, src1, src2);
+}
+
void Assembler::popcntq(Register dst, Address src) {
assert(VM_Version::supports_popcnt(), "must support");
InstructionMark im(this);
@@ -14196,6 +15300,16 @@ void Assembler::popcntq(Register dst, Address src) {
emit_operand(dst, src, 0);
}
+void Assembler::epopcntq(Register dst, Address src, bool no_flags) {
+ assert(VM_Version::supports_popcnt(), "must support");
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char) 0x88);
+ emit_operand(dst, src, 0);
+}
+
void Assembler::popcntq(Register dst, Register src) {
assert(VM_Version::supports_popcnt(), "must support");
emit_int8((unsigned char)0xF3);
@@ -14203,6 +15317,13 @@ void Assembler::popcntq(Register dst, Register src) {
emit_opcode_prefix_and_encoding((unsigned char)0xB8, 0xC0, encode);
}
+void Assembler::epopcntq(Register dst, Register src, bool no_flags) {
+ assert(VM_Version::supports_popcnt(), "must support");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0x88, (0xC0 | encode));
+}
+
void Assembler::popq(Address dst) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0x8F);
@@ -14421,6 +15542,17 @@ void Assembler::rclq(Register dst, int imm8) {
}
}
+void Assembler::erclq(Register dst, Register src, int imm8) {
+ assert(isShiftCount(imm8 >> 1), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes);
+ if (imm8 == 1) {
+ emit_int16((unsigned char)0xD1, (0xD0 | encode));
+ } else {
+ emit_int24((unsigned char)0xC1, (0xD0 | encode), imm8);
+ }
+}
+
void Assembler::rcrq(Register dst, int imm8) {
assert(isShiftCount(imm8 >> 1), "illegal shift count");
int encode = prefixq_and_encode(dst->encoding());
@@ -14431,6 +15563,17 @@ void Assembler::rcrq(Register dst, int imm8) {
}
}
+void Assembler::ercrq(Register dst, Register src, int imm8) {
+ assert(isShiftCount(imm8 >> 1), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes);
+ if (imm8 == 1) {
+ emit_int16((unsigned char)0xD1, (0xD8 | encode));
+ } else {
+ emit_int24((unsigned char)0xC1, (0xD8 | encode), imm8);
+ }
+}
+
void Assembler::rorxl(Register dst, Register src, int imm8) {
assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported");
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
@@ -14482,12 +15625,38 @@ void Assembler::salq(Address dst, int imm8) {
}
}
+void Assembler::esalq(Register dst, Address src, int imm8, bool no_flags) {
+ InstructionMark im(this);
+ assert(isShiftCount(imm8 >> 1), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int8((unsigned char)0xD1);
+ emit_operand(as_Register(4), src, 0);
+ }
+ else {
+ emit_int8((unsigned char)0xC1);
+ emit_operand(as_Register(4), src, 1);
+ emit_int8(imm8);
+ }
+}
+
void Assembler::salq(Address dst) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD3);
emit_operand(as_Register(4), dst, 0);
}
+void Assembler::esalq(Register dst, Address src, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xD3);
+ emit_operand(as_Register(4), src, 0);
+}
+
void Assembler::salq(Register dst, int imm8) {
assert(isShiftCount(imm8 >> 1), "illegal shift count");
int encode = prefixq_and_encode(dst->encoding());
@@ -14498,11 +15667,28 @@ void Assembler::salq(Register dst, int imm8) {
}
}
+void Assembler::esalq(Register dst, Register src, int imm8, bool no_flags) {
+ assert(isShiftCount(imm8 >> 1), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int16((unsigned char)0xD1, (0xE0 | encode));
+ } else {
+ emit_int24((unsigned char)0xC1, (0xE0 | encode), imm8);
+ }
+}
+
void Assembler::salq(Register dst) {
int encode = prefixq_and_encode(dst->encoding());
emit_int16((unsigned char)0xD3, (0xE0 | encode));
}
+void Assembler::esalq(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xD3, (0xE0 | encode));
+}
+
void Assembler::sarq(Address dst, int imm8) {
InstructionMark im(this);
assert(isShiftCount(imm8 >> 1), "illegal shift count");
@@ -14517,12 +15703,38 @@ void Assembler::sarq(Address dst, int imm8) {
}
}
+void Assembler::esarq(Register dst, Address src, int imm8, bool no_flags) {
+ assert(isShiftCount(imm8 >> 1), "illegal shift count");
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int8((unsigned char)0xD1);
+ emit_operand(as_Register(7), src, 0);
+ }
+ else {
+ emit_int8((unsigned char)0xC1);
+ emit_operand(as_Register(7), src, 1);
+ emit_int8(imm8);
+ }
+}
+
void Assembler::sarq(Address dst) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD3);
emit_operand(as_Register(7), dst, 0);
}
+void Assembler::esarq(Register dst, Address src, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xD3);
+ emit_operand(as_Register(7), src, 0);
+}
+
void Assembler::sarq(Register dst, int imm8) {
assert(isShiftCount(imm8 >> 1), "illegal shift count");
int encode = prefixq_and_encode(dst->encoding());
@@ -14533,10 +15745,26 @@ void Assembler::sarq(Register dst, int imm8) {
}
}
+void Assembler::esarq(Register dst, Register src, int imm8, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int16((unsigned char)0xD1, (0xF8 | encode));
+ } else {
+ emit_int24((unsigned char)0xC1, (0xF8 | encode), imm8);
+ }
+}
+
void Assembler::sarq(Register dst) {
int encode = prefixq_and_encode(dst->encoding());
emit_int16((unsigned char)0xD3, (0xF8 | encode));
}
+
+void Assembler::esarq(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xD3, (0xF8 | encode));
+}
#endif
void Assembler::sbbq(Address dst, int32_t imm32) {
@@ -14571,11 +15799,28 @@ void Assembler::shlq(Register dst, int imm8) {
}
}
+void Assembler::eshlq(Register dst, Register src, int imm8, bool no_flags) {
+ assert(isShiftCount(imm8 >> 1), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1 ) {
+ emit_int16((unsigned char)0xD1, (0xE0 | encode));
+ } else {
+ emit_int24((unsigned char)0xC1, (0xE0 | encode), imm8);
+ }
+}
+
void Assembler::shlq(Register dst) {
int encode = prefixq_and_encode(dst->encoding());
emit_int16((unsigned char)0xD3, (0xE0 | encode));
}
+void Assembler::eshlq(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xD3, (0xE0 | encode));
+}
+
void Assembler::shrq(Register dst, int imm8) {
assert(isShiftCount(imm8 >> 1), "illegal shift count");
int encode = prefixq_and_encode(dst->encoding());
@@ -14587,17 +15832,44 @@ void Assembler::shrq(Register dst, int imm8) {
}
}
+void Assembler::eshrq(Register dst, Register src, int imm8, bool no_flags) {
+ assert(isShiftCount(imm8 >> 1), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int16((unsigned char)0xD1, (0xE8 | encode));
+ }
+ else {
+ emit_int24((unsigned char)0xC1, (0xE8 | encode), imm8);
+ }
+}
+
void Assembler::shrq(Register dst) {
int encode = prefixq_and_encode(dst->encoding());
emit_int16((unsigned char)0xD3, 0xE8 | encode);
}
+void Assembler::eshrq(Register dst, Register src, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int16((unsigned char)0xD3, (0xE8 | encode));
+}
+
void Assembler::shrq(Address dst) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD3);
emit_operand(as_Register(5), dst, 0);
}
+void Assembler::eshrq(Register dst, Address src, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8((unsigned char)0xD3);
+ emit_operand(as_Register(5), src, 0);
+}
+
void Assembler::shrq(Address dst, int imm8) {
InstructionMark im(this);
assert(isShiftCount(imm8 >> 1), "illegal shift count");
@@ -14612,40 +15884,102 @@ void Assembler::shrq(Address dst, int imm8) {
}
}
+void Assembler::eshrq(Register dst, Address src, int imm8, bool no_flags) {
+ InstructionMark im(this);
+ assert(isShiftCount(imm8 >> 1), "illegal shift count");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ if (imm8 == 1) {
+ emit_int8((unsigned char)0xD1);
+ emit_operand(as_Register(5), src, 0);
+ }
+ else {
+ emit_int8((unsigned char)0xC1);
+ emit_operand(as_Register(5), src, 1);
+ emit_int8(imm8);
+ }
+}
+
void Assembler::subq(Address dst, int32_t imm32) {
InstructionMark im(this);
prefixq(dst);
emit_arith_operand(0x81, rbp, dst, imm32);
}
+void Assembler::esubq(Register dst, Address src, int32_t imm32, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith_operand(0x81, rbp, src, imm32);
+}
+
void Assembler::subq(Address dst, Register src) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(dst, src), 0x29);
emit_operand(src, dst, 0);
}
+void Assembler::esubq(Register dst, Address src1, Register src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x29);
+ emit_operand(src2, src1, 0);
+}
+
void Assembler::subq(Register dst, int32_t imm32) {
(void) prefixq_and_encode(dst->encoding());
emit_arith(0x81, 0xE8, dst, imm32);
}
+void Assembler::esubq(Register dst, Register src, int32_t imm32, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith(0x81, 0xE8, src, imm32);
+}
+
// Force generation of a 4 byte immediate value even if it fits into 8bit
void Assembler::subq_imm32(Register dst, int32_t imm32) {
(void) prefixq_and_encode(dst->encoding());
emit_arith_imm32(0x81, 0xE8, dst, imm32);
}
+void Assembler::esubq_imm32(Register dst, Register src, int32_t imm32, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith_imm32(0x81, 0xE8, src, imm32);
+}
+
void Assembler::subq(Register dst, Address src) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(src, dst), 0x2B);
emit_operand(dst, src, 0);
}
+void Assembler::esubq(Register dst, Register src1, Address src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x2B);
+ emit_operand(src1, src2, 0);
+}
+
void Assembler::subq(Register dst, Register src) {
(void) prefixq_and_encode(dst->encoding(), src->encoding());
emit_arith(0x2B, 0xC0, dst, src);
}
+void Assembler::esubq(Register dst, Register src1, Register src2, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ // opcode matches gcc
+ emit_arith(0x29, 0xC0, src1, src2);
+}
+
void Assembler::testq(Address dst, int32_t imm32) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xF7);
@@ -14703,29 +16037,77 @@ void Assembler::xorq(Register dst, Register src) {
emit_arith(0x33, 0xC0, dst, src);
}
+void Assembler::exorq(Register dst, Register src1, Register src2, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ // opcode matches gcc
+ emit_arith(0x31, 0xC0, src1, src2);
+}
+
void Assembler::xorq(Register dst, Address src) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(src, dst), 0x33);
emit_operand(dst, src, 0);
}
+void Assembler::exorq(Register dst, Register src1, Address src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x33);
+ emit_operand(src1, src2, 0);
+}
+
void Assembler::xorq(Register dst, int32_t imm32) {
(void) prefixq_and_encode(dst->encoding());
emit_arith(0x81, 0xF0, dst, imm32);
}
+void Assembler::exorq(Register dst, Register src, int32_t imm32, bool no_flags) {
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith(0x81, 0xF0, src, imm32);
+}
+
void Assembler::xorq(Address dst, int32_t imm32) {
InstructionMark im(this);
prefixq(dst);
emit_arith_operand(0x81, as_Register(6), dst, imm32);
}
+void Assembler::exorq(Register dst, Address src, int32_t imm32, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_arith_operand(0x81, as_Register(6), src, imm32);
+}
+
void Assembler::xorq(Address dst, Register src) {
InstructionMark im(this);
emit_prefix_and_int8(get_prefixq(dst, src), 0x31);
emit_operand(src, dst, 0);
}
+void Assembler::esetzucc(Condition cc, Register dst) {
+ assert(VM_Version::supports_apx_f(), "");
+ assert(0 <= cc && cc < 16, "illegal cc");
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ // Encoding Format : eevex_prefix (4 bytes) | opcode_cc | modrm
+ int encode = evex_prefix_and_encode_ndd(0, 0, dst->encoding(), VEX_SIMD_F2, /* MAP4 */VEX_OPCODE_0F_3C, &attributes);
+ emit_opcode_prefix_and_encoding((0x40 | cc), 0xC0, encode);
+}
+
+void Assembler::exorq(Register dst, Address src1, Register src2, bool no_flags) {
+ InstructionMark im(this);
+ InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit);
+ evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags);
+ emit_int8(0x31);
+ emit_operand(src2, src1, 0);
+}
+
#endif // !LP64
void InstructionAttr::set_address_attributes(int tuple_type, int input_size_in_bits) {
@@ -14734,3 +16116,59 @@ void InstructionAttr::set_address_attributes(int tuple_type, int input_size_in_b
_input_size_in_bits = input_size_in_bits;
}
}
+
+void Assembler::evpermi2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
+ assert(VM_Version::supports_avx512_vbmi() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), "");
+ InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_is_evex_instruction();
+ int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int16(0x75, (0xC0 | encode));
+}
+
+void Assembler::evpermi2w(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
+ assert(VM_Version::supports_avx512bw() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), "");
+ InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_is_evex_instruction();
+ int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int16(0x75, (0xC0 | encode));
+}
+
+void Assembler::evpermi2d(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
+ assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), "");
+ InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_is_evex_instruction();
+ int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int16(0x76, (0xC0 | encode));
+}
+
+void Assembler::evpermi2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
+ assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), "");
+ InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_is_evex_instruction();
+ int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int16(0x76, (0xC0 | encode));
+}
+
+void Assembler::evpermi2ps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
+ assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), "");
+ InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_is_evex_instruction();
+ int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int16(0x77, (0xC0 | encode));
+}
+
+void Assembler::evpermi2pd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
+ assert(VM_Version::supports_evex() && (vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl()), "");
+ InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_is_evex_instruction();
+ int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int16(0x77, (0xC0 | encode));
+}
+
+void Assembler::evpermt2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
+ assert(VM_Version::supports_avx512_vbmi(), "");
+ InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ attributes.set_is_evex_instruction();
+ int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int16(0x7D, (0xC0 | encode));
+}
diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp
index 28457b7005b..36dfafc8b5d 100644
--- a/src/hotspot/cpu/x86/assembler_x86.hpp
+++ b/src/hotspot/cpu/x86/assembler_x86.hpp
@@ -789,14 +789,26 @@ class Assembler : public AbstractAssembler {
void vex_prefix(bool vex_r, bool vex_b, bool vex_x, int nds_enc, VexSimdPrefix pre, VexOpcode opc);
void evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_v, bool evex_r, bool evex_b,
- bool eevex_x, int nds_enc, VexSimdPrefix pre, VexOpcode opc);
+ bool eevex_x, int nds_enc, VexSimdPrefix pre, VexOpcode opc, bool no_flags = false);
+
+ void evex_prefix_ndd(Address adr, int ndd_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc,
+ InstructionAttr *attributes, bool no_flags = false);
+
+ void evex_prefix_nf(Address adr, int ndd_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc,
+ InstructionAttr *attributes, bool no_flags = false);
void vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc,
- InstructionAttr *attributes);
+ InstructionAttr *attributes, bool nds_is_ndd = false, bool no_flags = false);
int vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc,
VexSimdPrefix pre, VexOpcode opc,
- InstructionAttr *attributes, bool src_is_gpr = false);
+ InstructionAttr *attributes, bool src_is_gpr = false, bool nds_is_ndd = false, bool no_flags = false);
+
+ int evex_prefix_and_encode_ndd(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc,
+ InstructionAttr *attributes, bool no_flags = false);
+
+ int evex_prefix_and_encode_nf(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc,
+ InstructionAttr *attributes, bool no_flags = false);
void simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr, VexSimdPrefix pre,
VexOpcode opc, InstructionAttr *attributes);
@@ -941,13 +953,20 @@ class Assembler : public AbstractAssembler {
// the product flag UseIncDec value.
void decl(Register dst);
+ void edecl(Register dst, Register src, bool no_flags);
void decl(Address dst);
+ void edecl(Register dst, Address src, bool no_flags);
void decq(Address dst);
+ void edecq(Register dst, Address src, bool no_flags);
void incl(Register dst);
+ void eincl(Register dst, Register src, bool no_flags);
void incl(Address dst);
+ void eincl(Register dst, Address src, bool no_flags);
void incq(Register dst);
+ void eincq(Register dst, Register src, bool no_flags);
void incq(Address dst);
+ void eincq(Register dst, Address src, bool no_flags);
// New cpus require use of movsd and movss to avoid partial register stall
// when loading from memory. But for old Opteron use movlpd instead of movsd.
@@ -1020,7 +1039,7 @@ class Assembler : public AbstractAssembler {
void pusha_uncached();
void popa_uncached();
- // APX ISA extensions for register save/restore optimizations.
+ // APX ISA Extensions for register save/restore optimizations.
void push2(Register src1, Register src2, bool with_ppx = false);
void pop2(Register src1, Register src2, bool with_ppx = false);
void push2p(Register src1, Register src2);
@@ -1028,9 +1047,13 @@ class Assembler : public AbstractAssembler {
void pushp(Register src);
void popp(Register src);
+ // New Zero Upper setcc instruction.
+ void esetzucc(Condition cc, Register dst);
+
#endif
void vzeroupper_uncached();
void decq(Register dst);
+ void edecq(Register dst, Register src, bool no_flags);
void pusha();
void popa();
@@ -1068,28 +1091,39 @@ class Assembler : public AbstractAssembler {
void addb(Address dst, int imm8);
void addb(Address dst, Register src);
void addb(Register dst, int imm8);
- void addw(Register dst, Register src);
void addw(Address dst, int imm16);
void addw(Address dst, Register src);
void addl(Address dst, int32_t imm32);
+ void eaddl(Register dst, Address src, int32_t imm32, bool no_flags);
void addl(Address dst, Register src);
+ void eaddl(Register dst, Address src1, Register src2, bool no_flags);
void addl(Register dst, int32_t imm32);
+ void eaddl(Register dst, Register src, int32_t imm32, bool no_flags);
void addl(Register dst, Address src);
+ void eaddl(Register dst, Register src1, Address src2, bool no_flags);
void addl(Register dst, Register src);
+ void eaddl(Register dst, Register src1, Register src2, bool no_flags);
void addq(Address dst, int32_t imm32);
+ void eaddq(Register dst, Address src, int32_t imm32, bool no_flags);
void addq(Address dst, Register src);
+ void eaddq(Register dst, Address src1, Register src2, bool no_flags);
void addq(Register dst, int32_t imm32);
+ void eaddq(Register dst, Register src, int32_t imm32, bool no_flags);
void addq(Register dst, Address src);
+ void eaddq(Register dst, Register src1, Address src2, bool no_flags);
void addq(Register dst, Register src);
+ void eaddq(Register dst, Register src1, Register src2, bool no_flags);
#ifdef _LP64
//Add Unsigned Integers with Carry Flag
void adcxq(Register dst, Register src);
+ void eadcxq(Register dst, Register src1, Register src2);
//Add Unsigned Integers with Overflow Flag
void adoxq(Register dst, Register src);
+ void eadoxq(Register dst, Register src1, Register src2);
#endif
void addr_nop_4();
@@ -1120,20 +1154,28 @@ class Assembler : public AbstractAssembler {
void vaesdec(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
void vaesdeclast(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
- void andw(Register dst, Register src);
void andb(Address dst, Register src);
void andl(Address dst, int32_t imm32);
+ void eandl(Register dst, Address src, int32_t imm32, bool no_flags);
void andl(Register dst, int32_t imm32);
+ void eandl(Register dst, Register src, int32_t imm32, bool no_flags);
void andl(Register dst, Address src);
+ void eandl(Register dst, Register src1, Address src2, bool no_flags);
void andl(Register dst, Register src);
+ void eandl(Register dst, Register src1, Register src2, bool no_flags);
void andl(Address dst, Register src);
void andq(Address dst, int32_t imm32);
+ void eandq(Register dst, Address src, int32_t imm32, bool no_flags);
void andq(Register dst, int32_t imm32);
+ void eandq(Register dst, Register src, int32_t imm32, bool no_flags);
void andq(Register dst, Address src);
+ void eandq(Register dst, Register src1, Address src2, bool no_flags);
void andq(Register dst, Register src);
+ void eandq(Register dst, Register src1, Register src2, bool no_flags);
void andq(Address dst, Register src);
+ void eandq(Register dst, Address src1, Register src2, bool no_flags);
// BMI instructions
void andnl(Register dst, Register src1, Register src2);
@@ -1184,15 +1226,20 @@ class Assembler : public AbstractAssembler {
void clwb(Address adr);
void cmovl(Condition cc, Register dst, Register src);
+ void ecmovl(Condition cc, Register dst, Register src1, Register src2);
void cmovl(Condition cc, Register dst, Address src);
+ void ecmovl(Condition cc, Register dst, Register src1, Address src2);
void cmovq(Condition cc, Register dst, Register src);
+ void ecmovq(Condition cc, Register dst, Register src1, Register src2);
void cmovq(Condition cc, Register dst, Address src);
+ void ecmovq(Condition cc, Register dst, Register src1, Address src2);
void cmpb(Address dst, int imm8);
void cmpb(Address dst, Register reg);
void cmpb(Register reg, Address dst);
+ void cmpb(Register reg, int imm8);
void cmpl(Address dst, int32_t imm32);
void cmpl(Register dst, int32_t imm32);
@@ -1490,25 +1537,41 @@ class Assembler : public AbstractAssembler {
void hlt();
void idivl(Register src);
+ void eidivl(Register src, bool no_flags);
void divl(Register src); // Unsigned division
+ void edivl(Register src, bool no_flags); // Unsigned division
#ifdef _LP64
void idivq(Register src);
+ void eidivq(Register src, bool no_flags);
void divq(Register src); // Unsigned division
+ void edivq(Register src, bool no_flags); // Unsigned division
#endif
void imull(Register src);
+ void eimull(Register src, bool no_flags);
void imull(Register dst, Register src);
+ void eimull(Register dst, Register src1, Register src2, bool no_flags);
void imull(Register dst, Register src, int value);
+ void eimull(Register dst, Register src, int value, bool no_flags);
void imull(Register dst, Address src, int value);
+ void eimull(Register dst, Address src, int value, bool no_flags);
void imull(Register dst, Address src);
+ void eimull(Register dst, Register src1, Address src2, bool no_flags);
#ifdef _LP64
void imulq(Register dst, Register src);
+ void eimulq(Register dst, Register src, bool no_flags);
+ void eimulq(Register dst, Register src1, Register src2, bool no_flags);
void imulq(Register dst, Register src, int value);
+ void eimulq(Register dst, Register src, int value, bool no_flags);
void imulq(Register dst, Address src, int value);
+ void eimulq(Register dst, Address src, int value, bool no_flags);
void imulq(Register dst, Address src);
+ void eimulq(Register dst, Address src, bool no_flags);
+ void eimulq(Register dst, Register src1, Address src2, bool no_flags);
void imulq(Register dst);
+ void eimulq(Register dst, bool no_flags);
#endif
// jcc is the generic conditional branch generator to run-
@@ -1567,11 +1630,15 @@ class Assembler : public AbstractAssembler {
void size_prefix();
void lzcntl(Register dst, Register src);
+ void elzcntl(Register dst, Register src, bool no_flags);
void lzcntl(Register dst, Address src);
+ void elzcntl(Register dst, Address src, bool no_flags);
#ifdef _LP64
void lzcntq(Register dst, Register src);
+ void elzcntq(Register dst, Register src, bool no_flags);
void lzcntq(Register dst, Address src);
+ void elzcntq(Register dst, Address src, bool no_flags);
#endif
enum Membar_mask_bits {
@@ -1787,11 +1854,15 @@ class Assembler : public AbstractAssembler {
// Unsigned multiply with RAX destination register
void mull(Address src);
+ void emull(Address src, bool no_flags);
void mull(Register src);
+ void emull(Register src, bool no_flags);
#ifdef _LP64
void mulq(Address src);
+ void emulq(Address src, bool no_flags);
void mulq(Register src);
+ void emulq(Register src, bool no_flags);
void mulxq(Register dst1, Register dst2, Register src);
#endif
@@ -1804,19 +1875,25 @@ class Assembler : public AbstractAssembler {
void mulss(XMMRegister dst, XMMRegister src);
void negl(Register dst);
+ void enegl(Register dst, Register src, bool no_flags);
void negl(Address dst);
+ void enegl(Register dst, Address src, bool no_flags);
#ifdef _LP64
void negq(Register dst);
+ void enegq(Register dst, Register src, bool no_flags);
void negq(Address dst);
+ void enegq(Register dst, Address src, bool no_flags);
#endif
void nop(uint i = 1);
void notl(Register dst);
+ void enotl(Register dst, Register src);
#ifdef _LP64
void notq(Register dst);
+ void enotq(Register dst, Register src);
void btsq(Address dst, int imm8);
void btrq(Address dst, int imm8);
@@ -1824,23 +1901,36 @@ class Assembler : public AbstractAssembler {
#endif
void btq(Register dst, Register src);
- void orw(Register dst, Register src);
+ void eorw(Register dst, Register src1, Register src2, bool no_flags);
void orl(Address dst, int32_t imm32);
+ void eorl(Register dst, Address src, int32_t imm32, bool no_flags);
void orl(Register dst, int32_t imm32);
+ void eorl(Register dst, Register src, int32_t imm32, bool no_flags);
void orl(Register dst, Address src);
+ void eorl(Register dst, Register src1, Address src2, bool no_flags);
void orl(Register dst, Register src);
+ void eorl(Register dst, Register src1, Register src2, bool no_flags);
void orl(Address dst, Register src);
+ void eorl(Register dst, Address src1, Register src2, bool no_flags);
void orb(Address dst, int imm8);
+ void eorb(Register dst, Address src, int imm8, bool no_flags);
void orb(Address dst, Register src);
+ void eorb(Register dst, Address src1, Register src2, bool no_flags);
void orq(Address dst, int32_t imm32);
+ void eorq(Register dst, Address src, int32_t imm32, bool no_flags);
void orq(Address dst, Register src);
+ void eorq(Register dst, Address src1, Register src2, bool no_flags);
void orq(Register dst, int32_t imm32);
+ void eorq(Register dst, Register src, int32_t imm32, bool no_flags);
void orq_imm32(Register dst, int32_t imm32);
+ void eorq_imm32(Register dst, Register src, int32_t imm32, bool no_flags);
void orq(Register dst, Address src);
+ void eorq(Register dst, Register src1, Address src2, bool no_flags);
void orq(Register dst, Register src);
+ void eorq(Register dst, Register src1, Register src2, bool no_flags);
// Pack with signed saturation
void packsswb(XMMRegister dst, XMMRegister src);
@@ -1871,9 +1961,14 @@ class Assembler : public AbstractAssembler {
void vpermilps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
void vpermilpd(XMMRegister dst, XMMRegister src, int imm8, int vector_len);
void vpermpd(XMMRegister dst, XMMRegister src, int imm8, int vector_len);
+ void evpmultishiftqb(XMMRegister dst, XMMRegister ctl, XMMRegister src, int vector_len);
+ void evpermi2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
+ void evpermi2w(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
+ void evpermi2d(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
void evpermi2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
+ void evpermi2ps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
+ void evpermi2pd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
void evpermt2b(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
- void evpmultishiftqb(XMMRegister dst, XMMRegister ctl, XMMRegister src, int vector_len);
void pause();
@@ -2026,7 +2121,9 @@ class Assembler : public AbstractAssembler {
#endif
void popcntl(Register dst, Address src);
+ void epopcntl(Register dst, Address src, bool no_flags);
void popcntl(Register dst, Register src);
+ void epopcntl(Register dst, Register src, bool no_flags);
void evpopcntb(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len);
void evpopcntw(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len);
@@ -2035,7 +2132,9 @@ class Assembler : public AbstractAssembler {
#ifdef _LP64
void popcntq(Register dst, Address src);
+ void epopcntq(Register dst, Address src, bool no_flags);
void popcntq(Register dst, Register src);
+ void epopcntq(Register dst, Register src, bool no_flags);
#endif
// Prefetches (SSE, SSE2, 3DNOW only)
@@ -2135,10 +2234,13 @@ class Assembler : public AbstractAssembler {
void pushq(Address src);
void rcll(Register dst, int imm8);
+ void ercll(Register dst, Register src, int imm8);
void rclq(Register dst, int imm8);
+ void erclq(Register dst, Register src, int imm8);
void rcrq(Register dst, int imm8);
+ void ercrq(Register dst, Register src, int imm8);
void rcpps(XMMRegister dst, XMMRegister src);
@@ -2149,18 +2251,26 @@ class Assembler : public AbstractAssembler {
void ret(int imm16);
void roll(Register dst);
+ void eroll(Register dst, Register src, bool no_flags);
void roll(Register dst, int imm8);
+ void eroll(Register dst, Register src, int imm8, bool no_flags);
void rorl(Register dst);
+ void erorl(Register dst, Register src, bool no_flags);
void rorl(Register dst, int imm8);
+ void erorl(Register dst, Register src, int imm8, bool no_flags);
#ifdef _LP64
void rolq(Register dst);
+ void erolq(Register dst, Register src, bool no_flags);
void rolq(Register dst, int imm8);
+ void erolq(Register dst, Register src, int imm8, bool no_flags);
void rorq(Register dst);
+ void erorq(Register dst, Register src, bool no_flags);
void rorq(Register dst, int imm8);
+ void erorq(Register dst, Register src, int imm8, bool no_flags);
void rorxl(Register dst, Register src, int imm8);
void rorxl(Register dst, Address src, int imm8);
void rorxq(Register dst, Register src, int imm8);
@@ -2170,25 +2280,41 @@ class Assembler : public AbstractAssembler {
void sahf();
void sall(Register dst, int imm8);
+ void esall(Register dst, Register src, int imm8, bool no_flags);
void sall(Register dst);
+ void esall(Register dst, Register src, bool no_flags);
void sall(Address dst, int imm8);
+ void esall(Register dst, Address src, int imm8, bool no_flags);
void sall(Address dst);
+ void esall(Register dst, Address src, bool no_flags);
void sarl(Address dst, int imm8);
+ void esarl(Register dst, Address src, int imm8, bool no_flags);
void sarl(Address dst);
+ void esarl(Register dst, Address src, bool no_flags);
void sarl(Register dst, int imm8);
+ void esarl(Register dst, Register src, int imm8, bool no_flags);
void sarl(Register dst);
+ void esarl(Register dst, Register src, bool no_flags);
#ifdef _LP64
void salq(Register dst, int imm8);
+ void esalq(Register dst, Register src, int imm8, bool no_flags);
void salq(Register dst);
+ void esalq(Register dst, Register src, bool no_flags);
void salq(Address dst, int imm8);
+ void esalq(Register dst, Address src, int imm8, bool no_flags);
void salq(Address dst);
+ void esalq(Register dst, Address src, bool no_flags);
void sarq(Address dst, int imm8);
+ void esarq(Register dst, Address src, int imm8, bool no_flags);
void sarq(Address dst);
+ void esarq(Register dst, Address src, bool no_flags);
void sarq(Register dst, int imm8);
+ void esarq(Register dst, Register src, int imm8, bool no_flags);
void sarq(Register dst);
+ void esarq(Register dst, Register src, bool no_flags);
#endif
void sbbl(Address dst, int32_t imm32);
@@ -2218,31 +2344,52 @@ class Assembler : public AbstractAssembler {
void sha256rnds2(XMMRegister dst, XMMRegister src);
void sha256msg1(XMMRegister dst, XMMRegister src);
void sha256msg2(XMMRegister dst, XMMRegister src);
+ void sha512rnds2(XMMRegister dst, XMMRegister nds, XMMRegister src);
+ void sha512msg1(XMMRegister dst, XMMRegister src);
+ void sha512msg2(XMMRegister dst, XMMRegister src);
void shldl(Register dst, Register src);
+ void eshldl(Register dst, Register src1, Register src2, bool no_flags);
void shldl(Register dst, Register src, int8_t imm8);
+ void eshldl(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags);
void shrdl(Register dst, Register src);
+ void eshrdl(Register dst, Register src1, Register src2, bool no_flags);
void shrdl(Register dst, Register src, int8_t imm8);
+ void eshrdl(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags);
#ifdef _LP64
void shldq(Register dst, Register src, int8_t imm8);
+ void eshldq(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags);
void shrdq(Register dst, Register src, int8_t imm8);
+ void eshrdq(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags);
#endif
void shll(Register dst, int imm8);
+ void eshll(Register dst, Register src, int imm8, bool no_flags);
void shll(Register dst);
+ void eshll(Register dst, Register src, bool no_flags);
void shlq(Register dst, int imm8);
+ void eshlq(Register dst, Register src, int imm8, bool no_flags);
void shlq(Register dst);
+ void eshlq(Register dst, Register src, bool no_flags);
void shrl(Register dst, int imm8);
+ void eshrl(Register dst, Register src, int imm8, bool no_flags);
void shrl(Register dst);
+ void eshrl(Register dst, Register src, bool no_flags);
void shrl(Address dst);
+ void eshrl(Register dst, Address src, bool no_flags);
void shrl(Address dst, int imm8);
+ void eshrl(Register dst, Address src, int imm8, bool no_flags);
void shrq(Register dst, int imm8);
+ void eshrq(Register dst, Register src, int imm8, bool no_flags);
void shrq(Register dst);
+ void eshrq(Register dst, Register src, bool no_flags);
void shrq(Address dst);
+ void eshrq(Register dst, Address src, bool no_flags);
void shrq(Address dst, int imm8);
+ void eshrq(Register dst, Address src, int imm8, bool no_flags);
void smovl(); // QQQ generic?
@@ -2262,20 +2409,32 @@ class Assembler : public AbstractAssembler {
void stmxcsr( Address dst );
void subl(Address dst, int32_t imm32);
+ void esubl(Register dst, Address src, int32_t imm32, bool no_flags);
void subl(Address dst, Register src);
+ void esubl(Register dst, Address src1, Register src2, bool no_flags);
void subl(Register dst, int32_t imm32);
+ void esubl(Register dst, Register src, int32_t imm32, bool no_flags);
void subl(Register dst, Address src);
+ void esubl(Register dst, Register src1, Address src2, bool no_flags);
void subl(Register dst, Register src);
+ void esubl(Register dst, Register src1, Register src2, bool no_flags);
void subq(Address dst, int32_t imm32);
+ void esubq(Register dst, Address src, int32_t imm32, bool no_flags);
void subq(Address dst, Register src);
+ void esubq(Register dst, Address src1, Register src2, bool no_flags);
void subq(Register dst, int32_t imm32);
+ void esubq(Register dst, Register src, int32_t imm32, bool no_flags);
void subq(Register dst, Address src);
+ void esubq(Register dst, Register src1, Address src2, bool no_flags);
void subq(Register dst, Register src);
+ void esubq(Register dst, Register src1, Register src2, bool no_flags);
// Force generation of a 4 byte immediate value even if it fits into 8bit
void subl_imm32(Register dst, int32_t imm32);
+ void esubl_imm32(Register dst, Register src, int32_t imm32, bool no_flags);
void subq_imm32(Register dst, int32_t imm32);
+ void esubq_imm32(Register dst, Register src, int32_t imm32, bool no_flags);
// Subtract Scalar Double-Precision Floating-Point Values
void subsd(XMMRegister dst, Address src);
@@ -2300,9 +2459,13 @@ class Assembler : public AbstractAssembler {
// BMI - count trailing zeros
void tzcntl(Register dst, Register src);
+ void etzcntl(Register dst, Register src, bool no_flags);
void tzcntl(Register dst, Address src);
+ void etzcntl(Register dst, Address src, bool no_flags);
void tzcntq(Register dst, Register src);
+ void etzcntq(Register dst, Register src, bool no_flags);
void tzcntq(Register dst, Address src);
+ void etzcntq(Register dst, Address src, bool no_flags);
// Unordered Compare Scalar Double-Precision Floating-Point Values and set EFLAGS
void ucomisd(XMMRegister dst, Address src);
@@ -2335,21 +2498,33 @@ class Assembler : public AbstractAssembler {
void xgetbv();
void xorl(Register dst, int32_t imm32);
+ void exorl(Register dst, Register src, int32_t imm32, bool no_flags);
void xorl(Address dst, int32_t imm32);
+ void exorl(Register dst, Address src, int32_t imm32, bool no_flags);
void xorl(Register dst, Address src);
+ void exorl(Register dst, Register src1, Address src2, bool no_flags);
void xorl(Register dst, Register src);
+ void exorl(Register dst, Register src1, Register src2, bool no_flags);
void xorl(Address dst, Register src);
+ void exorl(Register dst, Address src1, Register src2, bool no_flags);
void xorb(Address dst, Register src);
+ void exorb(Register dst, Address src1, Register src2, bool no_flags);
void xorb(Register dst, Address src);
- void xorw(Register dst, Register src);
+ void exorb(Register dst, Register src1, Address src2, bool no_flags);
void xorw(Register dst, Address src);
+ void exorw(Register dst, Register src1, Address src2, bool no_flags);
void xorq(Register dst, Address src);
+ void exorq(Register dst, Register src1, Address src2, bool no_flags);
void xorq(Address dst, int32_t imm32);
+ void exorq(Register dst, Address src, int32_t imm32, bool no_flags);
void xorq(Register dst, Register src);
+ void exorq(Register dst, Register src1, Register src2, bool no_flags);
void xorq(Register dst, int32_t imm32);
+ void exorq(Register dst, Register src, int32_t imm32, bool no_flags);
void xorq(Address dst, Register src);
+ void exorq(Register dst, Address src1, Register src2, bool no_flags);
// AVX 3-operands scalar instructions (encoded with VEX prefix)
@@ -2464,6 +2639,7 @@ class Assembler : public AbstractAssembler {
// Bitwise Logical AND of Packed Floating-Point Values
void andpd(XMMRegister dst, XMMRegister src);
+ void andnpd(XMMRegister dst, XMMRegister src);
void andps(XMMRegister dst, XMMRegister src);
void vandpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
void vandps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
@@ -2818,6 +2994,7 @@ class Assembler : public AbstractAssembler {
void vinserti32x4(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8);
void vinserti32x4(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8);
void vinserti64x4(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8);
+ void evinserti64x2(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8, int vector_len);
// vinsertf forms
void vinsertf128(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8);
@@ -2860,6 +3037,7 @@ class Assembler : public AbstractAssembler {
void evbroadcasti32x4(XMMRegister dst, Address src, int vector_len);
void evbroadcasti64x2(XMMRegister dst, XMMRegister src, int vector_len);
void evbroadcasti64x2(XMMRegister dst, Address src, int vector_len);
+ void vbroadcasti128(XMMRegister dst, Address src, int vector_len);
// scalar single/double/128bit precision replicate
void vbroadcastss(XMMRegister dst, XMMRegister src, int vector_len);
@@ -2867,6 +3045,7 @@ class Assembler : public AbstractAssembler {
void vbroadcastsd(XMMRegister dst, XMMRegister src, int vector_len);
void vbroadcastsd(XMMRegister dst, Address src, int vector_len);
void vbroadcastf128(XMMRegister dst, Address src, int vector_len);
+ void evbroadcastf64x2(XMMRegister dst, Address src, int vector_len);
// gpr sourced byte/word/dword/qword replicate
void evpbroadcastb(XMMRegister dst, Register src, int vector_len);
diff --git a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp
index 7d89b148ba2..71ca9351f86 100644
--- a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp
+++ b/src/hotspot/cpu/x86/c1_CodeStubs_x86.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
@@ -110,7 +110,7 @@ void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
Metadata *m = _method->as_constant_ptr()->as_metadata();
ce->store_parameter(m, 1);
ce->store_parameter(_bci, 0);
- __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::counter_overflow_id)));
+ __ call(RuntimeAddress(Runtime1::entry_for(C1StubId::counter_overflow_id)));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
__ jmp(_continuation);
@@ -119,7 +119,7 @@ void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
void RangeCheckStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
if (_info->deoptimize_on_exception()) {
- address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ address a = Runtime1::entry_for(C1StubId::predicate_failed_trap_id);
__ call(RuntimeAddress(a));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
@@ -133,11 +133,11 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
} else {
ce->store_parameter(_index->as_jint(), 0);
}
- Runtime1::StubID stub_id;
+ C1StubId stub_id;
if (_throw_index_out_of_bounds_exception) {
- stub_id = Runtime1::throw_index_exception_id;
+ stub_id = C1StubId::throw_index_exception_id;
} else {
- stub_id = Runtime1::throw_range_check_failed_id;
+ stub_id = C1StubId::throw_range_check_failed_id;
ce->store_parameter(_array->as_pointer_register(), 1);
}
__ call(RuntimeAddress(Runtime1::entry_for(stub_id)));
@@ -152,7 +152,7 @@ PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ address a = Runtime1::entry_for(C1StubId::predicate_failed_trap_id);
__ call(RuntimeAddress(a));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
@@ -164,7 +164,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) {
ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
}
__ bind(_entry);
- __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::throw_div0_exception_id)));
+ __ call(RuntimeAddress(Runtime1::entry_for(C1StubId::throw_div0_exception_id)));
ce->add_call_info_here(_info);
debug_only(__ should_not_reach_here());
}
@@ -172,14 +172,14 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) {
// Implementation of NewInstanceStub
-NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) {
+NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, C1StubId stub_id) {
_result = result;
_klass = klass;
_klass_reg = klass_reg;
_info = new CodeEmitInfo(info);
- assert(stub_id == Runtime1::new_instance_id ||
- stub_id == Runtime1::fast_new_instance_id ||
- stub_id == Runtime1::fast_new_instance_init_check_id,
+ assert(stub_id == C1StubId::new_instance_id ||
+ stub_id == C1StubId::fast_new_instance_id ||
+ stub_id == C1StubId::fast_new_instance_init_check_id,
"need new_instance id");
_stub_id = stub_id;
}
@@ -212,7 +212,7 @@ void NewTypeArrayStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
assert(_length->as_register() == rbx, "length must in rbx,");
assert(_klass_reg->as_register() == rdx, "klass_reg must in rdx");
- __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_type_array_id)));
+ __ call(RuntimeAddress(Runtime1::entry_for(C1StubId::new_type_array_id)));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
assert(_result->as_register() == rax, "result must in rax,");
@@ -235,7 +235,7 @@ void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
assert(_length->as_register() == rbx, "length must in rbx,");
assert(_klass_reg->as_register() == rdx, "klass_reg must in rdx");
- __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_object_array_id)));
+ __ call(RuntimeAddress(Runtime1::entry_for(C1StubId::new_object_array_id)));
ce->add_call_info_here(_info);
ce->verify_oop_map(_info);
assert(_result->as_register() == rax, "result must in rax,");
@@ -247,11 +247,11 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
ce->store_parameter(_obj_reg->as_register(), 1);
ce->store_parameter(_lock_reg->as_register(), 0);
- Runtime1::StubID enter_id;
+ C1StubId enter_id;
if (ce->compilation()->has_fpu_code()) {
- enter_id = Runtime1::monitorenter_id;
+ enter_id = C1StubId::monitorenter_id;
} else {
- enter_id = Runtime1::monitorenter_nofpu_id;
+ enter_id = C1StubId::monitorenter_nofpu_id;
}
__ call(RuntimeAddress(Runtime1::entry_for(enter_id)));
ce->add_call_info_here(_info);
@@ -268,11 +268,11 @@ void MonitorExitStub::emit_code(LIR_Assembler* ce) {
}
ce->store_parameter(_lock_reg->as_register(), 0);
// note: non-blocking leaf routine => no call info needed
- Runtime1::StubID exit_id;
+ C1StubId exit_id;
if (ce->compilation()->has_fpu_code()) {
- exit_id = Runtime1::monitorexit_id;
+ exit_id = C1StubId::monitorexit_id;
} else {
- exit_id = Runtime1::monitorexit_nofpu_id;
+ exit_id = C1StubId::monitorexit_nofpu_id;
}
__ call(RuntimeAddress(Runtime1::entry_for(exit_id)));
__ jmp(_continuation);
@@ -407,10 +407,10 @@ void PatchingStub::emit_code(LIR_Assembler* ce) {
address target = nullptr;
relocInfo::relocType reloc_type = relocInfo::none;
switch (_id) {
- case access_field_id: target = Runtime1::entry_for(Runtime1::access_field_patching_id); break;
- case load_klass_id: target = Runtime1::entry_for(Runtime1::load_klass_patching_id); reloc_type = relocInfo::metadata_type; break;
- case load_mirror_id: target = Runtime1::entry_for(Runtime1::load_mirror_patching_id); reloc_type = relocInfo::oop_type; break;
- case load_appendix_id: target = Runtime1::entry_for(Runtime1::load_appendix_patching_id); reloc_type = relocInfo::oop_type; break;
+ case access_field_id: target = Runtime1::entry_for(C1StubId::access_field_patching_id); break;
+ case load_klass_id: target = Runtime1::entry_for(C1StubId::load_klass_patching_id); reloc_type = relocInfo::metadata_type; break;
+ case load_mirror_id: target = Runtime1::entry_for(C1StubId::load_mirror_patching_id); reloc_type = relocInfo::oop_type; break;
+ case load_appendix_id: target = Runtime1::entry_for(C1StubId::load_appendix_patching_id); reloc_type = relocInfo::oop_type; break;
default: ShouldNotReachHere();
}
__ bind(call_patch);
@@ -440,7 +440,7 @@ void PatchingStub::emit_code(LIR_Assembler* ce) {
void DeoptimizeStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
ce->store_parameter(_trap_request, 0);
- __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::deoptimize_id)));
+ __ call(RuntimeAddress(Runtime1::entry_for(C1StubId::deoptimize_id)));
ce->add_call_info_here(_info);
DEBUG_ONLY(__ should_not_reach_here());
}
@@ -450,9 +450,9 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
address a;
if (_info->deoptimize_on_exception()) {
// Deoptimize, do not throw the exception, because it is probably wrong to do it here.
- a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ a = Runtime1::entry_for(C1StubId::predicate_failed_trap_id);
} else {
- a = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id);
+ a = Runtime1::entry_for(C1StubId::throw_null_pointer_exception_id);
}
ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
index e2fde10b98d..6d9812c11ae 100644
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
@@ -399,7 +399,7 @@ int LIR_Assembler::emit_exception_handler() {
__ verify_not_null_oop(rax);
// search an exception handler (rax: exception oop, rdx: throwing pc)
- __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id)));
+ __ call(RuntimeAddress(Runtime1::entry_for(C1StubId::handle_exception_from_callee_id)));
__ should_not_reach_here();
guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
__ end_a_stub();
@@ -463,7 +463,7 @@ int LIR_Assembler::emit_unwind_handler() {
// remove the activation and dispatch to the unwind handler
__ remove_frame(initial_frame_size_in_bytes());
- __ jump(RuntimeAddress(Runtime1::entry_for(Runtime1::unwind_exception_id)));
+ __ jump(RuntimeAddress(Runtime1::entry_for(C1StubId::unwind_exception_id)));
// Emit the slow path assembly
if (stub != nullptr) {
@@ -1566,7 +1566,7 @@ void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) {
// instruction sequence too long to inline it here
{
- __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::fpu2long_stub_id)));
+ __ call(RuntimeAddress(Runtime1::entry_for(C1StubId::fpu2long_stub_id)));
}
break;
#endif // _LP64
@@ -1578,6 +1578,7 @@ void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) {
void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) {
if (op->init_check()) {
add_debug_info_for_null_check_here(op->stub()->info());
+ // init_state needs acquire, but x86 is TSO, and so we are already good.
__ cmpb(Address(op->klass()->as_register(),
InstanceKlass::init_state_offset()),
InstanceKlass::fully_initialized);
@@ -1781,7 +1782,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L
#else
__ pushklass(k->constant_encoding(), noreg);
#endif // _LP64
- __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
+ __ call(RuntimeAddress(Runtime1::entry_for(C1StubId::slow_subtype_check_id)));
__ pop(klass_RInfo);
__ pop(klass_RInfo);
// result is a boolean
@@ -1795,7 +1796,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L
// call out-of-line instance of __ check_klass_subtype_slow_path(...):
__ push(klass_RInfo);
__ push(k_RInfo);
- __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
+ __ call(RuntimeAddress(Runtime1::entry_for(C1StubId::slow_subtype_check_id)));
__ pop(klass_RInfo);
__ pop(k_RInfo);
// result is a boolean
@@ -1874,7 +1875,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
// call out-of-line instance of __ check_klass_subtype_slow_path(...):
__ push(klass_RInfo);
__ push(k_RInfo);
- __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
+ __ call(RuntimeAddress(Runtime1::entry_for(C1StubId::slow_subtype_check_id)));
__ pop(klass_RInfo);
__ pop(k_RInfo);
// result is a boolean
@@ -2893,7 +2894,7 @@ void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmit
// exception object is not added to oop map by LinearScan
// (LinearScan assumes that no oops are in fixed registers)
info->add_register_oop(exceptionOop);
- Runtime1::StubID unwind_id;
+ C1StubId unwind_id;
// get current pc information
// pc is only needed if the method has an exception handler, the unwind code does not need it.
@@ -2905,9 +2906,9 @@ void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmit
__ verify_not_null_oop(rax);
// search an exception handler (rax: exception oop, rdx: throwing pc)
if (compilation()->has_fpu_code()) {
- unwind_id = Runtime1::handle_exception_id;
+ unwind_id = C1StubId::handle_exception_id;
} else {
- unwind_id = Runtime1::handle_exception_nofpu_id;
+ unwind_id = C1StubId::handle_exception_nofpu_id;
}
__ call(RuntimeAddress(Runtime1::entry_for(unwind_id)));
@@ -3262,7 +3263,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
__ push(src);
__ push(dst);
- __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
+ __ call(RuntimeAddress(Runtime1::entry_for(C1StubId::slow_subtype_check_id)));
__ pop(dst);
__ pop(src);
diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp
index d3add6975b4..36e2021138f 100644
--- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp
+++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp
@@ -807,7 +807,11 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) {
if (x->id() == vmIntrinsics::_dexp || x->id() == vmIntrinsics::_dlog ||
x->id() == vmIntrinsics::_dpow || x->id() == vmIntrinsics::_dcos ||
x->id() == vmIntrinsics::_dsin || x->id() == vmIntrinsics::_dtan ||
- x->id() == vmIntrinsics::_dlog10) {
+ x->id() == vmIntrinsics::_dlog10
+#ifdef _LP64
+ || x->id() == vmIntrinsics::_dtanh
+#endif
+ ) {
do_LibmIntrinsic(x);
return;
}
@@ -989,11 +993,17 @@ void LIRGenerator::do_LibmIntrinsic(Intrinsic* x) {
break;
case vmIntrinsics::_dtan:
if (StubRoutines::dtan() != nullptr) {
- __ call_runtime_leaf(StubRoutines::dtan(), getThreadTemp(), result_reg, cc->args());
+ __ call_runtime_leaf(StubRoutines::dtan(), getThreadTemp(), result_reg, cc->args());
} else {
__ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtan), getThreadTemp(), result_reg, cc->args());
}
break;
+ case vmIntrinsics::_dtanh:
+ assert(StubRoutines::dtanh() != nullptr, "tanh intrinsic not found");
+ if (StubRoutines::dtanh() != nullptr) {
+ __ call_runtime_leaf(StubRoutines::dtanh(), getThreadTemp(), result_reg, cc->args());
+ }
+ break;
default: ShouldNotReachHere();
}
#endif // _LP64
@@ -1430,7 +1440,7 @@ void LIRGenerator::do_NewMultiArray(NewMultiArray* x) {
args->append(rank);
args->append(varargs);
LIR_Opr reg = result_register_for(x->type());
- __ call_runtime(Runtime1::entry_for(Runtime1::new_multi_array_id),
+ __ call_runtime(Runtime1::entry_for(C1StubId::new_multi_array_id),
LIR_OprFact::illegalOpr,
reg, args, info);
@@ -1463,12 +1473,12 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
CodeStub* stub;
if (x->is_incompatible_class_change_check()) {
assert(patching_info == nullptr, "can't patch this");
- stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception);
+ stub = new SimpleExceptionStub(C1StubId::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception);
} else if (x->is_invokespecial_receiver_check()) {
assert(patching_info == nullptr, "can't patch this");
stub = new DeoptimizeStub(info_for_exception, Deoptimization::Reason_class_check, Deoptimization::Action_none);
} else {
- stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception);
+ stub = new SimpleExceptionStub(C1StubId::throw_class_cast_exception_id, obj.result(), info_for_exception);
}
LIR_Opr reg = rlock_result(x);
LIR_Opr tmp3 = LIR_OprFact::illegalOpr;
diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp
index 2374324ca7c..bf5b90db5fc 100644
--- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp
@@ -58,19 +58,20 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(hdr, obj, rscratch1);
- movl(hdr, Address(hdr, Klass::access_flags_offset()));
- testl(hdr, JVM_ACC_IS_VALUE_BASED_CLASS);
+ testb(Address(hdr, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class);
jcc(Assembler::notZero, slow_case);
}
if (LockingMode == LM_LIGHTWEIGHT) {
#ifdef _LP64
const Register thread = r15_thread;
+ lightweight_lock(disp_hdr, obj, hdr, thread, tmp, slow_case);
#else
- const Register thread = disp_hdr;
- get_thread(thread);
+ // Implicit null check.
+ movptr(hdr, Address(obj, oopDesc::mark_offset_in_bytes()));
+ // Lacking registers and thread on x86_32. Always take slow path.
+ jmp(slow_case);
#endif
- lightweight_lock(obj, hdr, thread, tmp, slow_case);
} else if (LockingMode == LM_LEGACY) {
Label done;
// Load object header
@@ -139,10 +140,8 @@ void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_
#ifdef _LP64
lightweight_unlock(obj, disp_hdr, r15_thread, hdr, slow_case);
#else
- // This relies on the implementation of lightweight_unlock being able to handle
- // that the reg_rax and thread Register parameters may alias each other.
- get_thread(disp_hdr);
- lightweight_unlock(obj, disp_hdr, disp_hdr, hdr, slow_case);
+ // Lacking registers and thread on x86_32. Always take slow path.
+ jmp(slow_case);
#endif
} else if (LockingMode == LM_LEGACY) {
// test if object header is pointing to the displaced header, and if so, restore
@@ -272,7 +271,7 @@ void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register
if (CURRENT_ENV->dtrace_alloc_probes()) {
assert(obj == rax, "must be");
- call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)));
+ call(RuntimeAddress(Runtime1::entry_for(C1StubId::dtrace_object_alloc_id)));
}
verify_oop(obj);
@@ -310,7 +309,7 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1,
if (CURRENT_ENV->dtrace_alloc_probes()) {
assert(obj == rax, "must be");
- call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)));
+ call(RuntimeAddress(Runtime1::entry_for(C1StubId::dtrace_object_alloc_id)));
}
verify_oop(obj);
diff --git a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp
index dc051127fea..1ccb06df489 100644
--- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp
+++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.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
@@ -60,7 +60,7 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre
#ifdef _LP64
// At a method handle call, the stack may not be properly aligned
// when returning with an exception.
- align_stack = (stub_id() == Runtime1::handle_exception_from_callee_id);
+ align_stack = (stub_id() == (int)C1StubId::handle_exception_from_callee_id);
#endif
#ifdef _LP64
@@ -124,10 +124,10 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre
if (frame_size() == no_frame_size) {
leave();
jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
- } else if (_stub_id == Runtime1::forward_exception_id) {
+ } else if (_stub_id == (int)C1StubId::forward_exception_id) {
should_not_reach_here();
} else {
- jump(RuntimeAddress(Runtime1::entry_for(Runtime1::forward_exception_id)));
+ jump(RuntimeAddress(Runtime1::entry_for(C1StubId::forward_exception_id)));
}
bind(L);
}
@@ -671,7 +671,7 @@ OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address targe
}
-OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
+OopMapSet* Runtime1::generate_handle_exception(C1StubId id, StubAssembler *sasm) {
__ block_comment("generate_handle_exception");
// incoming parameters
@@ -684,7 +684,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
OopMapSet* oop_maps = new OopMapSet();
OopMap* oop_map = nullptr;
switch (id) {
- case forward_exception_id:
+ case C1StubId::forward_exception_id:
// We're handling an exception in the context of a compiled frame.
// The registers have been saved in the standard places. Perform
// an exception lookup in the caller and dispatch to the handler
@@ -703,12 +703,12 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
__ movptr(Address(thread, JavaThread::vm_result_offset()), NULL_WORD);
__ movptr(Address(thread, JavaThread::vm_result_2_offset()), NULL_WORD);
break;
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
// At this point all registers MAY be live.
- oop_map = save_live_registers(sasm, 1 /*thread*/, id != handle_exception_nofpu_id);
+ oop_map = save_live_registers(sasm, 1 /*thread*/, id != C1StubId::handle_exception_nofpu_id);
break;
- case handle_exception_from_callee_id: {
+ case C1StubId::handle_exception_from_callee_id: {
// At this point all registers except exception oop (RAX) and
// exception pc (RDX) are dead.
const int frame_size = 2 /*BP, return address*/ NOT_LP64(+ 1 /*thread*/) WIN64_ONLY(+ frame::arg_reg_save_area_bytes / BytesPerWord);
@@ -775,13 +775,13 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
__ movptr(Address(rbp, 1*BytesPerWord), rax);
switch (id) {
- case forward_exception_id:
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::forward_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
// Restore the registers that were saved at the beginning.
- restore_live_registers(sasm, id != handle_exception_nofpu_id);
+ restore_live_registers(sasm, id != C1StubId::handle_exception_nofpu_id);
break;
- case handle_exception_from_callee_id:
+ case C1StubId::handle_exception_from_callee_id:
// WIN64_ONLY: No need to add frame::arg_reg_save_area_bytes to SP
// since we do a leave anyway.
@@ -935,7 +935,7 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
__ testptr(rax, rax); // have we deoptimized?
__ jump_cc(Assembler::equal,
- RuntimeAddress(Runtime1::entry_for(Runtime1::forward_exception_id)));
+ RuntimeAddress(Runtime1::entry_for(C1StubId::forward_exception_id)));
// the deopt blob expects exceptions in the special fields of
// JavaThread, so copy and clear pending exception.
@@ -1007,7 +1007,7 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
}
-OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
+OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) {
// for better readability
const bool must_gc_arguments = true;
@@ -1019,7 +1019,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
// stub code & info for the different stubs
OopMapSet* oop_maps = nullptr;
switch (id) {
- case forward_exception_id:
+ case C1StubId::forward_exception_id:
{
oop_maps = generate_handle_exception(id, sasm);
__ leave();
@@ -1027,19 +1027,19 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case new_instance_id:
- case fast_new_instance_id:
- case fast_new_instance_init_check_id:
+ case C1StubId::new_instance_id:
+ case C1StubId::fast_new_instance_id:
+ case C1StubId::fast_new_instance_init_check_id:
{
Register klass = rdx; // Incoming
Register obj = rax; // Result
- if (id == new_instance_id) {
+ if (id == C1StubId::new_instance_id) {
__ set_info("new_instance", dont_gc_arguments);
- } else if (id == fast_new_instance_id) {
+ } else if (id == C1StubId::fast_new_instance_id) {
__ set_info("fast new_instance", dont_gc_arguments);
} else {
- assert(id == fast_new_instance_init_check_id, "bad StubID");
+ assert(id == C1StubId::fast_new_instance_init_check_id, "bad C1StubId");
__ set_info("fast new_instance init check", dont_gc_arguments);
}
@@ -1058,7 +1058,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
break;
- case counter_overflow_id:
+ case C1StubId::counter_overflow_id:
{
Register bci = rax, method = rbx;
__ enter();
@@ -1076,14 +1076,14 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case new_type_array_id:
- case new_object_array_id:
+ case C1StubId::new_type_array_id:
+ case C1StubId::new_object_array_id:
{
Register length = rbx; // Incoming
Register klass = rdx; // Incoming
Register obj = rax; // Result
- if (id == new_type_array_id) {
+ if (id == C1StubId::new_type_array_id) {
__ set_info("new_type_array", dont_gc_arguments);
} else {
__ set_info("new_object_array", dont_gc_arguments);
@@ -1096,7 +1096,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
Register t0 = obj;
__ movl(t0, Address(klass, Klass::layout_helper_offset()));
__ sarl(t0, Klass::_lh_array_tag_shift);
- int tag = ((id == new_type_array_id)
+ int tag = ((id == C1StubId::new_type_array_id)
? Klass::_lh_array_tag_type_value
: Klass::_lh_array_tag_obj_value);
__ cmpl(t0, tag);
@@ -1110,7 +1110,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
__ enter();
OopMap* map = save_live_registers(sasm, 3);
int call_offset;
- if (id == new_type_array_id) {
+ if (id == C1StubId::new_type_array_id) {
call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_type_array), klass, length);
} else {
call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length);
@@ -1128,7 +1128,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case new_multi_array_id:
+ case C1StubId::new_multi_array_id:
{ StubFrame f(sasm, "new_multi_array", dont_gc_arguments);
// rax,: klass
// rbx,: rank
@@ -1145,7 +1145,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case register_finalizer_id:
+ case C1StubId::register_finalizer_id:
{
__ set_info("register_finalizer", dont_gc_arguments);
@@ -1166,8 +1166,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
Label register_finalizer;
Register t = rsi;
__ load_klass(t, rax, rscratch1);
- __ movl(t, Address(t, Klass::access_flags_offset()));
- __ testl(t, JVM_ACC_HAS_FINALIZER);
+ __ testb(Address(t, Klass::misc_flags_offset()), KlassFlags::_misc_has_finalizer);
__ jcc(Assembler::notZero, register_finalizer);
__ ret(0);
@@ -1186,44 +1185,44 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case throw_range_check_failed_id:
+ case C1StubId::throw_range_check_failed_id:
{ StubFrame f(sasm, "range_check_failed", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), true);
}
break;
- case throw_index_exception_id:
+ case C1StubId::throw_index_exception_id:
{ StubFrame f(sasm, "index_range_check_failed", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true);
}
break;
- case throw_div0_exception_id:
+ case C1StubId::throw_div0_exception_id:
{ StubFrame f(sasm, "throw_div0_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false);
}
break;
- case throw_null_pointer_exception_id:
+ case C1StubId::throw_null_pointer_exception_id:
{ StubFrame f(sasm, "throw_null_pointer_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false);
}
break;
- case handle_exception_nofpu_id:
- case handle_exception_id:
+ case C1StubId::handle_exception_nofpu_id:
+ case C1StubId::handle_exception_id:
{ StubFrame f(sasm, "handle_exception", dont_gc_arguments);
oop_maps = generate_handle_exception(id, sasm);
}
break;
- case handle_exception_from_callee_id:
+ case C1StubId::handle_exception_from_callee_id:
{ StubFrame f(sasm, "handle_exception_from_callee", dont_gc_arguments);
oop_maps = generate_handle_exception(id, sasm);
}
break;
- case unwind_exception_id:
+ case C1StubId::unwind_exception_id:
{ __ set_info("unwind_exception", dont_gc_arguments);
// note: no stubframe since we are about to leave the current
// activation and we are calling a leaf VM function only.
@@ -1231,7 +1230,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case throw_array_store_exception_id:
+ case C1StubId::throw_array_store_exception_id:
{ StubFrame f(sasm, "throw_array_store_exception", dont_gc_arguments);
// tos + 0: link
// + 1: return address
@@ -1239,19 +1238,19 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case throw_class_cast_exception_id:
+ case C1StubId::throw_class_cast_exception_id:
{ StubFrame f(sasm, "throw_class_cast_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true);
}
break;
- case throw_incompatible_class_change_error_id:
+ case C1StubId::throw_incompatible_class_change_error_id:
{ StubFrame f(sasm, "throw_incompatible_class_cast_exception", dont_gc_arguments);
oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false);
}
break;
- case slow_subtype_check_id:
+ case C1StubId::slow_subtype_check_id:
{
// Typical calling sequence:
// __ push(klass_RInfo); // object klass or other subclass
@@ -1304,10 +1303,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case monitorenter_nofpu_id:
+ case C1StubId::monitorenter_nofpu_id:
save_fpu_registers = false;
// fall through
- case monitorenter_id:
+ case C1StubId::monitorenter_id:
{
StubFrame f(sasm, "monitorenter", dont_gc_arguments);
OopMap* map = save_live_registers(sasm, 3, save_fpu_registers);
@@ -1325,10 +1324,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case monitorexit_nofpu_id:
+ case C1StubId::monitorexit_nofpu_id:
save_fpu_registers = false;
// fall through
- case monitorexit_id:
+ case C1StubId::monitorexit_id:
{
StubFrame f(sasm, "monitorexit", dont_gc_arguments);
OopMap* map = save_live_registers(sasm, 2, save_fpu_registers);
@@ -1348,7 +1347,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case deoptimize_id:
+ case C1StubId::deoptimize_id:
{
StubFrame f(sasm, "deoptimize", dont_gc_arguments);
const int num_rt_args = 2; // thread, trap_request
@@ -1365,35 +1364,35 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case access_field_patching_id:
+ case C1StubId::access_field_patching_id:
{ StubFrame f(sasm, "access_field_patching", dont_gc_arguments);
// we should set up register map
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching));
}
break;
- case load_klass_patching_id:
+ case C1StubId::load_klass_patching_id:
{ StubFrame f(sasm, "load_klass_patching", dont_gc_arguments);
// we should set up register map
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching));
}
break;
- case load_mirror_patching_id:
+ case C1StubId::load_mirror_patching_id:
{ StubFrame f(sasm, "load_mirror_patching", dont_gc_arguments);
// we should set up register map
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_mirror_patching));
}
break;
- case load_appendix_patching_id:
+ case C1StubId::load_appendix_patching_id:
{ StubFrame f(sasm, "load_appendix_patching", dont_gc_arguments);
// we should set up register map
oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching));
}
break;
- case dtrace_object_alloc_id:
+ case C1StubId::dtrace_object_alloc_id:
{ // rax,: object
StubFrame f(sasm, "dtrace_object_alloc", dont_gc_arguments);
// we can't gc here so skip the oopmap but make sure that all
@@ -1408,7 +1407,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case fpu2long_stub_id:
+ case C1StubId::fpu2long_stub_id:
{
#ifdef _LP64
Label done;
@@ -1497,7 +1496,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
- case predicate_failed_trap_id:
+ case C1StubId::predicate_failed_trap_id:
{
StubFrame f(sasm, "predicate_failed_trap", dont_gc_arguments);
diff --git a/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp
index 6dc8d14064a..44f897529e7 100644
--- a/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp
+++ b/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp
@@ -80,8 +80,6 @@ int C2FastUnlockLightweightStub::max_size() const {
void C2FastUnlockLightweightStub::emit(C2_MacroAssembler& masm) {
assert(_t == rax, "must be");
- Label restore_held_monitor_count_and_slow_path;
-
{ // Restore lock-stack and handle the unlock in runtime.
__ bind(_push_and_slow_path);
@@ -91,56 +89,9 @@ void C2FastUnlockLightweightStub::emit(C2_MacroAssembler& masm) {
__ movptr(Address(_thread, _t), _obj);
#endif
__ addl(Address(_thread, JavaThread::lock_stack_top_offset()), oopSize);
- }
-
- { // Restore held monitor count and slow path.
-
- __ bind(restore_held_monitor_count_and_slow_path);
- // Restore held monitor count.
- __ increment(Address(_thread, JavaThread::held_monitor_count_offset()));
- // increment will always result in ZF = 0 (no overflows).
+ // addl will always result in ZF = 0 (no overflows).
__ jmp(slow_path_continuation());
}
-
- { // Handle monitor medium path.
-
- __ bind(_check_successor);
-
- Label fix_zf_and_unlocked;
- const Register monitor = _mark;
-
-#ifndef _LP64
- __ jmpb(restore_held_monitor_count_and_slow_path);
-#else // _LP64
- // successor null check.
- __ cmpptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), NULL_WORD);
- __ jccb(Assembler::equal, restore_held_monitor_count_and_slow_path);
-
- // Release lock.
- __ movptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD);
-
- // Fence.
- // Instead of MFENCE we use a dummy locked add of 0 to the top-of-stack.
- __ lock(); __ addl(Address(rsp, 0), 0);
-
- // Recheck successor.
- __ cmpptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), NULL_WORD);
- // Observed a successor after the release -> fence we have handed off the monitor
- __ jccb(Assembler::notEqual, fix_zf_and_unlocked);
-
- // Try to relock, if it fails the monitor has been handed over
- // TODO: Caveat, this may fail due to deflation, which does
- // not handle the monitor handoff. Currently only works
- // due to the responsible thread.
- __ xorptr(rax, rax);
- __ lock(); __ cmpxchgptr(_thread, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
- __ jccb (Assembler::equal, restore_held_monitor_count_and_slow_path);
-#endif
-
- __ bind(fix_zf_and_unlocked);
- __ xorl(rax, rax);
- __ jmp(unlocked_continuation());
- }
}
#undef __
diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
index 66a782ba9c6..879f33ede2d 100644
--- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
@@ -277,8 +277,7 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmpReg, objReg, scrReg);
- movl(tmpReg, Address(tmpReg, Klass::access_flags_offset()));
- testl(tmpReg, JVM_ACC_IS_VALUE_BASED_CLASS);
+ testb(Address(tmpReg, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class);
jcc(Assembler::notZero, DONE_LABEL);
}
@@ -460,87 +459,43 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t
// IA32's memory-model is SPO, so STs are ordered with respect to
// each other and there's no need for an explicit barrier (fence).
// See also http://gee.cs.oswego.edu/dl/jmm/cookbook.html.
-#ifndef _LP64
- // Note that we could employ various encoding schemes to reduce
- // the number of loads below (currently 4) to just 2 or 3.
- // Refer to the comments in synchronizer.cpp.
- // In practice the chain of fetches doesn't seem to impact performance, however.
- xorptr(boxReg, boxReg);
- orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)));
- jccb (Assembler::notZero, DONE_LABEL);
- movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)));
- orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)));
- jccb (Assembler::notZero, DONE_LABEL);
- movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD);
- jmpb (DONE_LABEL);
-#else // _LP64
- // It's inflated
- Label CheckSucc, LNotRecursive, LSuccess, LGoSlowPath;
+ Label LSuccess, LNotRecursive;
cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 0);
jccb(Assembler::equal, LNotRecursive);
// Recursive inflated unlock
- decq(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)));
+ decrement(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)));
jmpb(LSuccess);
bind(LNotRecursive);
- movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)));
- orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)));
- jccb (Assembler::notZero, CheckSucc);
- // Without cast to int32_t this style of movptr will destroy r10 which is typically obj.
+
+ // Set owner to null.
+ // Release to satisfy the JMM
movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD);
- jmpb (DONE_LABEL);
+ // We need a full fence after clearing owner to avoid stranding.
+ // StoreLoad achieves this.
+ membar(StoreLoad);
- // Try to avoid passing control into the slow_path ...
- bind (CheckSucc);
+ // Check if the entry lists are empty.
+ movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)));
+ orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)));
+ jccb(Assembler::zero, LSuccess); // If so we are done.
- // The following optional optimization can be elided if necessary
- // Effectively: if (succ == null) goto slow path
- // The code reduces the window for a race, however,
- // and thus benefits performance.
+ // Check if there is a successor.
cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), NULL_WORD);
- jccb (Assembler::zero, LGoSlowPath);
+ jccb(Assembler::notZero, LSuccess); // If so we are done.
- xorptr(boxReg, boxReg);
- // Without cast to int32_t this style of movptr will destroy r10 which is typically obj.
- movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD);
-
- // Memory barrier/fence
- // Dekker pivot point -- fulcrum : ST Owner; MEMBAR; LD Succ
- // Instead of MFENCE we use a dummy locked add of 0 to the top-of-stack.
- // This is faster on Nehalem and AMD Shanghai/Barcelona.
- // See https://blogs.oracle.com/dave/entry/instruction_selection_for_volatile_fences
- // We might also restructure (ST Owner=0;barrier;LD _Succ) to
- // (mov box,0; xchgq box, &m->Owner; LD _succ) .
- lock(); addl(Address(rsp, 0), 0);
+ // Save the monitor pointer in the current thread, so we can try to
+ // reacquire the lock in SharedRuntime::monitor_exit_helper().
+ andptr(tmpReg, ~(int32_t)markWord::monitor_value);
+#ifndef _LP64
+ get_thread(boxReg);
+ movptr(Address(boxReg, JavaThread::unlocked_inflated_monitor_offset()), tmpReg);
+#else // _LP64
+ movptr(Address(r15_thread, JavaThread::unlocked_inflated_monitor_offset()), tmpReg);
+#endif
- cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), NULL_WORD);
- jccb (Assembler::notZero, LSuccess);
-
- // Rare inopportune interleaving - race.
- // The successor vanished in the small window above.
- // The lock is contended -- (cxq|EntryList) != null -- and there's no apparent successor.
- // We need to ensure progress and succession.
- // Try to reacquire the lock.
- // If that fails then the new owner is responsible for succession and this
- // thread needs to take no further action and can exit via the fast path (success).
- // If the re-acquire succeeds then pass control into the slow path.
- // As implemented, this latter mode is horrible because we generated more
- // coherence traffic on the lock *and* artificially extended the critical section
- // length while by virtue of passing control into the slow path.
-
- // box is really RAX -- the following CMPXCHG depends on that binding
- // cmpxchg R,[M] is equivalent to rax = CAS(M,rax,R)
- lock();
- cmpxchgptr(r15_thread, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
- // There's no successor so we tried to regrab the lock.
- // If that didn't work, then another thread grabbed the
- // lock so we're done (and exit was a success).
- jccb (Assembler::notEqual, LSuccess);
- // Intentional fall-through into slow path
-
- bind (LGoSlowPath);
orl (boxReg, 1); // set ICC.ZF=0 to indicate failure
jmpb (DONE_LABEL);
@@ -548,7 +503,6 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t
testl (boxReg, 0); // set ICC.ZF=1 to indicate success
jmpb (DONE_LABEL);
-#endif
if (LockingMode == LM_LEGACY) {
bind (Stacked);
movptr(tmpReg, Address (boxReg, 0)); // re-fetch
@@ -590,10 +544,14 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist
// Finish fast lock unsuccessfully. MUST jump with ZF == 0
Label slow_path;
+ if (UseObjectMonitorTable) {
+ // Clear cache in case fast locking succeeds.
+ movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0);
+ }
+
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(rax_reg, obj, t);
- movl(rax_reg, Address(rax_reg, Klass::access_flags_offset()));
- testl(rax_reg, JVM_ACC_IS_VALUE_BASED_CLASS);
+ testb(Address(rax_reg, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class);
jcc(Assembler::notZero, slow_path);
}
@@ -603,7 +561,7 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist
Label push;
- const Register top = box;
+ const Register top = UseObjectMonitorTable ? rax_reg : box;
// Load the mark.
movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
@@ -630,6 +588,10 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist
lock(); cmpxchgptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
jcc(Assembler::notEqual, slow_path);
+ if (UseObjectMonitorTable) {
+ // Need to reload top, clobbered by CAS.
+ movl(top, Address(thread, JavaThread::lock_stack_top_offset()));
+ }
bind(push);
// After successful lock, push object on lock-stack.
movptr(Address(thread, top), obj);
@@ -640,19 +602,68 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist
{ // Handle inflated monitor.
bind(inflated);
- const Register tagged_monitor = mark;
+ const Register monitor = t;
+
+ if (!UseObjectMonitorTable) {
+ assert(mark == monitor, "should be the same here");
+ } else {
+ // Uses ObjectMonitorTable. Look for the monitor in the om_cache.
+ // Fetch ObjectMonitor* from the cache or take the slow-path.
+ Label monitor_found;
+
+ // Load cache address
+ lea(t, Address(thread, JavaThread::om_cache_oops_offset()));
+
+ const int num_unrolled = 2;
+ for (int i = 0; i < num_unrolled; i++) {
+ cmpptr(obj, Address(t));
+ jccb(Assembler::equal, monitor_found);
+ increment(t, in_bytes(OMCache::oop_to_oop_difference()));
+ }
+
+ Label loop;
+
+ // Search for obj in cache.
+ bind(loop);
+
+ // Check for match.
+ cmpptr(obj, Address(t));
+ jccb(Assembler::equal, monitor_found);
+
+ // Search until null encountered, guaranteed _null_sentinel at end.
+ cmpptr(Address(t), 1);
+ jcc(Assembler::below, slow_path); // 0 check, but with ZF=0 when *t == 0
+ increment(t, in_bytes(OMCache::oop_to_oop_difference()));
+ jmpb(loop);
+
+ // Cache hit.
+ bind(monitor_found);
+ movptr(monitor, Address(t, OMCache::oop_to_monitor_difference()));
+ }
+ const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value));
+ const Address recursions_address(monitor, ObjectMonitor::recursions_offset() - monitor_tag);
+ const Address owner_address(monitor, ObjectMonitor::owner_offset() - monitor_tag);
+
+ Label monitor_locked;
+ // Lock the monitor.
// CAS owner (null => current thread).
xorptr(rax_reg, rax_reg);
- lock(); cmpxchgptr(thread, Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
- jccb(Assembler::equal, locked);
+ lock(); cmpxchgptr(thread, owner_address);
+ jccb(Assembler::equal, monitor_locked);
// Check if recursive.
cmpptr(thread, rax_reg);
jccb(Assembler::notEqual, slow_path);
// Recursive.
- increment(Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)));
+ increment(recursions_address);
+
+ bind(monitor_locked);
+ if (UseObjectMonitorTable) {
+ // Cache the monitor for unlock
+ movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), monitor);
+ }
}
bind(locked);
@@ -688,13 +699,12 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax,
// Handle inflated monitor.
Label inflated, inflated_check_lock_stack;
// Finish fast unlock successfully. MUST jump with ZF == 1
- Label unlocked;
-
- // Assume success.
- decrement(Address(thread, JavaThread::held_monitor_count_offset()));
+ Label unlocked, slow_path;
const Register mark = t;
- const Register top = reg_rax;
+ const Register monitor = t;
+ const Register top = UseObjectMonitorTable ? t : reg_rax;
+ const Register box = reg_rax;
Label dummy;
C2FastUnlockLightweightStub* stub = nullptr;
@@ -705,15 +715,16 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax,
}
Label& push_and_slow_path = stub == nullptr ? dummy : stub->push_and_slow_path();
- Label& check_successor = stub == nullptr ? dummy : stub->check_successor();
{ // Lightweight Unlock
// Load top.
movl(top, Address(thread, JavaThread::lock_stack_top_offset()));
- // Prefetch mark.
- movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
+ if (!UseObjectMonitorTable) {
+ // Prefetch mark.
+ movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
+ }
// Check if obj is top of lock-stack.
cmpptr(obj, Address(thread, top, Address::times_1, -oopSize));
@@ -730,6 +741,11 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax,
// We elide the monitor check, let the CAS fail instead.
+ if (UseObjectMonitorTable) {
+ // Load mark.
+ movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
+ }
+
// Try to unlock. Transition lock bits 0b00 => 0b01
movptr(reg_rax, mark);
andptr(reg_rax, ~(int32_t)markWord::lock_mask);
@@ -751,6 +767,9 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax,
jccb(Assembler::notEqual, inflated_check_lock_stack);
stop("Fast Unlock lock on stack");
bind(check_done);
+ if (UseObjectMonitorTable) {
+ movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes()));
+ }
testptr(mark, markWord::monitor_value);
jccb(Assembler::notZero, inflated);
stop("Fast Unlock not monitor");
@@ -758,64 +777,81 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax,
bind(inflated);
- // mark contains the tagged ObjectMonitor*.
- const Register monitor = mark;
-
-#ifndef _LP64
- // Check if recursive.
- xorptr(reg_rax, reg_rax);
- orptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)));
- jcc(Assembler::notZero, check_successor);
-
- // Check if the entry lists are empty.
- movptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)));
- orptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)));
- jcc(Assembler::notZero, check_successor);
+ if (!UseObjectMonitorTable) {
+ assert(mark == monitor, "should be the same here");
+ } else {
+ // Uses ObjectMonitorTable. Look for the monitor in our BasicLock on the stack.
+ movptr(monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes()));
+ // null check with ZF == 0, no valid pointer below alignof(ObjectMonitor*)
+ cmpptr(monitor, alignof(ObjectMonitor*));
+ jcc(Assembler::below, slow_path);
+ }
+ const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value));
+ const Address recursions_address{monitor, ObjectMonitor::recursions_offset() - monitor_tag};
+ const Address cxq_address{monitor, ObjectMonitor::cxq_offset() - monitor_tag};
+ const Address succ_address{monitor, ObjectMonitor::succ_offset() - monitor_tag};
+ const Address EntryList_address{monitor, ObjectMonitor::EntryList_offset() - monitor_tag};
+ const Address owner_address{monitor, ObjectMonitor::owner_offset() - monitor_tag};
- // Release lock.
- movptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD);
-#else // _LP64
Label recursive;
// Check if recursive.
- cmpptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 0);
- jccb(Assembler::notEqual, recursive);
+ cmpptr(recursions_address, 0);
+ jccb(Assembler::notZero, recursive);
+
+ // Set owner to null.
+ // Release to satisfy the JMM
+ movptr(owner_address, NULL_WORD);
+ // We need a full fence after clearing owner to avoid stranding.
+ // StoreLoad achieves this.
+ membar(StoreLoad);
// Check if the entry lists are empty.
- movptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)));
- orptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)));
- jcc(Assembler::notZero, check_successor);
+ movptr(reg_rax, cxq_address);
+ orptr(reg_rax, EntryList_address);
+ jccb(Assembler::zero, unlocked); // If so we are done.
+
+ // Check if there is a successor.
+ cmpptr(succ_address, NULL_WORD);
+ jccb(Assembler::notZero, unlocked); // If so we are done.
+
+ // Save the monitor pointer in the current thread, so we can try to
+ // reacquire the lock in SharedRuntime::monitor_exit_helper().
+ if (!UseObjectMonitorTable) {
+ andptr(monitor, ~(int32_t)markWord::monitor_value);
+ }
+ movptr(Address(thread, JavaThread::unlocked_inflated_monitor_offset()), monitor);
- // Release lock.
- movptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD);
- jmpb(unlocked);
+ orl(t, 1); // Fast Unlock ZF = 0
+ jmpb(slow_path);
// Recursive unlock.
bind(recursive);
- decrement(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)));
- xorl(t, t);
-#endif
+ decrement(recursions_address);
}
bind(unlocked);
- if (stub != nullptr) {
- bind(stub->unlocked_continuation());
- }
+ decrement(Address(thread, JavaThread::held_monitor_count_offset()));
+ xorl(t, t); // Fast Unlock ZF = 1
#ifdef ASSERT
// Check that unlocked label is reached with ZF set.
Label zf_correct;
+ Label zf_bad_zero;
jcc(Assembler::zero, zf_correct);
- stop("Fast Unlock ZF != 1");
+ jmp(zf_bad_zero);
#endif
+ bind(slow_path);
if (stub != nullptr) {
bind(stub->slow_path_continuation());
}
#ifdef ASSERT
// Check that stub->continuation() label is reached with ZF not set.
- jccb(Assembler::notZero, zf_correct);
+ jcc(Assembler::notZero, zf_correct);
stop("Fast Unlock ZF != 0");
+ bind(zf_bad_zero);
+ stop("Fast Unlock ZF != 1");
bind(zf_correct);
#endif
// C2 uses the value of ZF to determine the continuation.
@@ -1786,6 +1822,16 @@ void C2_MacroAssembler::reduce_operation_128(BasicType typ, int opcode, XMMRegis
}
}
+void C2_MacroAssembler::unordered_reduce_operation_128(BasicType typ, int opcode, XMMRegister dst, XMMRegister src) {
+ switch (opcode) {
+ case Op_AddReductionVF: addps(dst, src); break;
+ case Op_AddReductionVD: addpd(dst, src); break;
+ case Op_MulReductionVF: mulps(dst, src); break;
+ case Op_MulReductionVD: mulpd(dst, src); break;
+ default: assert(false, "%s", NodeClassNames[opcode]);
+ }
+}
+
void C2_MacroAssembler::reduce_operation_256(BasicType typ, int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2) {
int vector_len = Assembler::AVX_256bit;
@@ -1834,6 +1880,18 @@ void C2_MacroAssembler::reduce_operation_256(BasicType typ, int opcode, XMMRegis
}
}
+void C2_MacroAssembler::unordered_reduce_operation_256(BasicType typ, int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+ int vector_len = Assembler::AVX_256bit;
+
+ switch (opcode) {
+ case Op_AddReductionVF: vaddps(dst, src1, src2, vector_len); break;
+ case Op_AddReductionVD: vaddpd(dst, src1, src2, vector_len); break;
+ case Op_MulReductionVF: vmulps(dst, src1, src2, vector_len); break;
+ case Op_MulReductionVD: vmulpd(dst, src1, src2, vector_len); break;
+ default: assert(false, "%s", NodeClassNames[opcode]);
+ }
+}
+
void C2_MacroAssembler::reduce_fp(int opcode, int vlen,
XMMRegister dst, XMMRegister src,
XMMRegister vtmp1, XMMRegister vtmp2) {
@@ -1852,6 +1910,24 @@ void C2_MacroAssembler::reduce_fp(int opcode, int vlen,
}
}
+void C2_MacroAssembler::unordered_reduce_fp(int opcode, int vlen,
+ XMMRegister dst, XMMRegister src,
+ XMMRegister vtmp1, XMMRegister vtmp2) {
+ switch (opcode) {
+ case Op_AddReductionVF:
+ case Op_MulReductionVF:
+ unorderedReduceF(opcode, vlen, dst, src, vtmp1, vtmp2);
+ break;
+
+ case Op_AddReductionVD:
+ case Op_MulReductionVD:
+ unorderedReduceD(opcode, vlen, dst, src, vtmp1, vtmp2);
+ break;
+
+ default: assert(false, "%s", NodeClassNames[opcode]);
+ }
+}
+
void C2_MacroAssembler::reduceB(int opcode, int vlen,
Register dst, Register src1, XMMRegister src2,
XMMRegister vtmp1, XMMRegister vtmp2) {
@@ -1954,6 +2030,45 @@ void C2_MacroAssembler::reduceD(int opcode, int vlen, XMMRegister dst, XMMRegist
}
}
+void C2_MacroAssembler::unorderedReduceF(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2) {
+ switch (vlen) {
+ case 2:
+ assert(vtmp1 == xnoreg, "");
+ assert(vtmp2 == xnoreg, "");
+ unorderedReduce2F(opcode, dst, src);
+ break;
+ case 4:
+ assert(vtmp2 == xnoreg, "");
+ unorderedReduce4F(opcode, dst, src, vtmp1);
+ break;
+ case 8:
+ unorderedReduce8F(opcode, dst, src, vtmp1, vtmp2);
+ break;
+ case 16:
+ unorderedReduce16F(opcode, dst, src, vtmp1, vtmp2);
+ break;
+ default: assert(false, "wrong vector length");
+ }
+}
+
+void C2_MacroAssembler::unorderedReduceD(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2) {
+ switch (vlen) {
+ case 2:
+ assert(vtmp1 == xnoreg, "");
+ assert(vtmp2 == xnoreg, "");
+ unorderedReduce2D(opcode, dst, src);
+ break;
+ case 4:
+ assert(vtmp2 == xnoreg, "");
+ unorderedReduce4D(opcode, dst, src, vtmp1);
+ break;
+ case 8:
+ unorderedReduce8D(opcode, dst, src, vtmp1, vtmp2);
+ break;
+ default: assert(false, "wrong vector length");
+ }
+}
+
void C2_MacroAssembler::reduce2I(int opcode, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2) {
if (opcode == Op_AddReductionVI) {
if (vtmp1 != src2) {
@@ -2181,6 +2296,29 @@ void C2_MacroAssembler::reduce16F(int opcode, XMMRegister dst, XMMRegister src,
reduce8F(opcode, dst, vtmp1, vtmp1, vtmp2);
}
+void C2_MacroAssembler::unorderedReduce2F(int opcode, XMMRegister dst, XMMRegister src) {
+ pshufd(dst, src, 0x1);
+ reduce_operation_128(T_FLOAT, opcode, dst, src);
+}
+
+void C2_MacroAssembler::unorderedReduce4F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp) {
+ pshufd(vtmp, src, 0xE);
+ unordered_reduce_operation_128(T_FLOAT, opcode, vtmp, src);
+ unorderedReduce2F(opcode, dst, vtmp);
+}
+
+void C2_MacroAssembler::unorderedReduce8F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2) {
+ vextractf128_high(vtmp1, src);
+ unordered_reduce_operation_128(T_FLOAT, opcode, vtmp1, src);
+ unorderedReduce4F(opcode, dst, vtmp1, vtmp2);
+}
+
+void C2_MacroAssembler::unorderedReduce16F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2) {
+ vextractf64x4_high(vtmp2, src);
+ unordered_reduce_operation_256(T_FLOAT, opcode, vtmp2, vtmp2, src);
+ unorderedReduce8F(opcode, dst, vtmp2, vtmp1, vtmp2);
+}
+
void C2_MacroAssembler::reduce2D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp) {
reduce_operation_128(T_DOUBLE, opcode, dst, src);
pshufd(vtmp, src, 0xE);
@@ -2199,6 +2337,23 @@ void C2_MacroAssembler::reduce8D(int opcode, XMMRegister dst, XMMRegister src, X
reduce4D(opcode, dst, vtmp1, vtmp1, vtmp2);
}
+void C2_MacroAssembler::unorderedReduce2D(int opcode, XMMRegister dst, XMMRegister src) {
+ pshufd(dst, src, 0xE);
+ reduce_operation_128(T_DOUBLE, opcode, dst, src);
+}
+
+void C2_MacroAssembler::unorderedReduce4D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp) {
+ vextractf128_high(vtmp, src);
+ unordered_reduce_operation_128(T_DOUBLE, opcode, vtmp, src);
+ unorderedReduce2D(opcode, dst, vtmp);
+}
+
+void C2_MacroAssembler::unorderedReduce8D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2) {
+ vextractf64x4_high(vtmp2, src);
+ unordered_reduce_operation_256(T_DOUBLE, opcode, vtmp2, vtmp2, src);
+ unorderedReduce4D(opcode, dst, vtmp2, vtmp1);
+}
+
void C2_MacroAssembler::evmovdqu(BasicType type, KRegister kmask, XMMRegister dst, Address src, bool merge, int vector_len) {
MacroAssembler::evmovdqu(type, kmask, dst, src, merge, vector_len);
}
@@ -6323,3 +6478,30 @@ void C2_MacroAssembler::vector_rearrange_int_float(BasicType bt, XMMRegister dst
vpermps(dst, shuffle, src, vlen_enc);
}
}
+
+void C2_MacroAssembler::select_from_two_vectors_evex(BasicType elem_bt, XMMRegister dst, XMMRegister src1,
+ XMMRegister src2, int vlen_enc) {
+ switch(elem_bt) {
+ case T_BYTE:
+ evpermi2b(dst, src1, src2, vlen_enc);
+ break;
+ case T_SHORT:
+ evpermi2w(dst, src1, src2, vlen_enc);
+ break;
+ case T_INT:
+ evpermi2d(dst, src1, src2, vlen_enc);
+ break;
+ case T_LONG:
+ evpermi2q(dst, src1, src2, vlen_enc);
+ break;
+ case T_FLOAT:
+ evpermi2ps(dst, src1, src2, vlen_enc);
+ break;
+ case T_DOUBLE:
+ evpermi2pd(dst, src1, src2, vlen_enc);
+ break;
+ default:
+ fatal("Unsupported type %s", type2name(elem_bt));
+ break;
+ }
+}
diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp
index e268ed3dd7a..5744fedcc64 100644
--- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp
+++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp
@@ -149,6 +149,9 @@
void reduce_fp(int opcode, int vlen,
XMMRegister dst, XMMRegister src,
XMMRegister vtmp1, XMMRegister vtmp2 = xnoreg);
+ void unordered_reduce_fp(int opcode, int vlen,
+ XMMRegister dst, XMMRegister src,
+ XMMRegister vtmp1 = xnoreg, XMMRegister vtmp2 = xnoreg);
void reduceB(int opcode, int vlen, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2);
void mulreduceB(int opcode, int vlen, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2);
void reduceS(int opcode, int vlen, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2);
@@ -161,6 +164,8 @@
private:
void reduceF(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2);
void reduceD(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2);
+ void unorderedReduceF(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2);
+ void unorderedReduceD(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2);
// Int Reduction
void reduce2I (int opcode, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2);
@@ -197,14 +202,27 @@
void reduce8F (int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2);
void reduce16F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2);
+ // Unordered Float Reduction
+ void unorderedReduce2F(int opcode, XMMRegister dst, XMMRegister src);
+ void unorderedReduce4F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp);
+ void unorderedReduce8F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2);
+ void unorderedReduce16F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2);
+
// Double Reduction
void reduce2D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp);
void reduce4D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2);
void reduce8D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2);
+ // Unordered Double Reduction
+ void unorderedReduce2D(int opcode, XMMRegister dst, XMMRegister src);
+ void unorderedReduce4D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp);
+ void unorderedReduce8D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2);
+
// Base reduction instruction
void reduce_operation_128(BasicType typ, int opcode, XMMRegister dst, XMMRegister src);
void reduce_operation_256(BasicType typ, int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2);
+ void unordered_reduce_operation_128(BasicType typ, int opcode, XMMRegister dst, XMMRegister src);
+ void unordered_reduce_operation_256(BasicType typ, int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2);
public:
#ifdef _LP64
@@ -487,4 +505,6 @@
void vgather8b_offset(BasicType elem_bt, XMMRegister dst, Register base, Register idx_base,
Register offset, Register rtmp, int vlen_enc);
+ void select_from_two_vectors_evex(BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, int vlen_enc);
+
#endif // CPU_X86_C2_MACROASSEMBLER_X86_HPP
diff --git a/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp
index 41039e0cfd8..e4b25ce00d6 100644
--- a/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp
+++ b/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp
@@ -34,8 +34,8 @@
#define __ _masm->
-static const int native_invoker_code_base_size = 512;
-static const int native_invoker_size_per_arg = 8;
+static const int native_invoker_code_base_size = 256;
+static const int native_invoker_size_per_arg = 16;
RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature,
int num_args,
diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp
index 2366d31992d..aeb77763e7f 100644
--- a/src/hotspot/cpu/x86/frame_x86.cpp
+++ b/src/hotspot/cpu/x86/frame_x86.cpp
@@ -279,7 +279,7 @@ void frame::patch_pc(Thread* thread, address pc) {
assert(!Continuation::is_return_barrier_entry(*pc_addr), "return barrier");
- assert(_pc == *pc_addr || pc == *pc_addr || *pc_addr == 0, "");
+ assert(_pc == *pc_addr || pc == *pc_addr || *pc_addr == nullptr, "");
DEBUG_ONLY(address old_pc = _pc;)
*pc_addr = pc;
_pc = pc; // must be set before call to get_deopt_original_pc
@@ -483,10 +483,10 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
assert(is_interpreted_frame(), "Not an interpreted frame");
// These are reasonable sanity checks
- if (fp() == 0 || (intptr_t(fp()) & (wordSize-1)) != 0) {
+ if (fp() == nullptr || (intptr_t(fp()) & (wordSize-1)) != 0) {
return false;
}
- if (sp() == 0 || (intptr_t(sp()) & (wordSize-1)) != 0) {
+ if (sp() == nullptr || (intptr_t(sp()) & (wordSize-1)) != 0) {
return false;
}
if (fp() + interpreter_frame_initial_sp_offset < sp()) {
diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp
index b52be627776..b6be4012519 100644
--- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp
@@ -38,7 +38,10 @@
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "gc/g1/c1/g1BarrierSetC1.hpp"
-#endif
+#endif // COMPILER1
+#ifdef COMPILER2
+#include "gc/g1/c2/g1BarrierSetC2.hpp"
+#endif // COMPILER2
#define __ masm->
@@ -160,6 +163,56 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator
}
}
+static void generate_queue_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime,
+ const Register thread, const Register value, const Register temp) {
+ // This code assumes that buffer index is pointer sized.
+ STATIC_ASSERT(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t));
+ // Can we store a value in the given thread's buffer?
+ // (The index field is typed as size_t.)
+ __ movptr(temp, Address(thread, in_bytes(index_offset))); // temp := *(index address)
+ __ testptr(temp, temp); // index == 0?
+ __ jcc(Assembler::zero, runtime); // jump to runtime if index == 0 (full buffer)
+ // The buffer is not full, store value into it.
+ __ subptr(temp, wordSize); // temp := next index
+ __ movptr(Address(thread, in_bytes(index_offset)), temp); // *(index address) := next index
+ __ addptr(temp, Address(thread, in_bytes(buffer_offset))); // temp := buffer address + next index
+ __ movptr(Address(temp, 0), value); // *(buffer address + next index) := value
+}
+
+static void generate_pre_barrier_fast_path(MacroAssembler* masm,
+ const Register thread) {
+ Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
+ // Is marking active?
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ cmpl(in_progress, 0);
+ } else {
+ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ cmpb(in_progress, 0);
+ }
+}
+
+static void generate_pre_barrier_slow_path(MacroAssembler* masm,
+ const Register obj,
+ const Register pre_val,
+ const Register thread,
+ const Register tmp,
+ Label& done,
+ Label& runtime) {
+ // Do we need to load the previous value?
+ if (obj != noreg) {
+ __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);
+ }
+ // Is the previous value null?
+ __ cmpptr(pre_val, NULL_WORD);
+ __ jcc(Assembler::equal, done);
+ generate_queue_insertion(masm,
+ G1ThreadLocalData::satb_mark_queue_index_offset(),
+ G1ThreadLocalData::satb_mark_queue_buffer_offset(),
+ runtime,
+ thread, pre_val, tmp);
+ __ jmp(done);
+}
+
void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
Register obj,
Register pre_val,
@@ -185,43 +238,10 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
assert(pre_val != rax, "check this code");
}
- Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
- Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
- Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
-
- // Is marking active?
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- __ cmpl(in_progress, 0);
- } else {
- assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- __ cmpb(in_progress, 0);
- }
- __ jcc(Assembler::equal, done);
-
- // Do we need to load the previous value?
- if (obj != noreg) {
- __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);
- }
-
- // Is the previous value null?
- __ cmpptr(pre_val, NULL_WORD);
+ generate_pre_barrier_fast_path(masm, thread);
+ // If marking is not active (*(mark queue active address) == 0), jump to done
__ jcc(Assembler::equal, done);
-
- // Can we store original value in the thread's buffer?
- // Is index == 0?
- // (The index field is typed as size_t.)
-
- __ movptr(tmp, index); // tmp := *index_adr
- __ cmpptr(tmp, 0); // tmp == 0?
- __ jcc(Assembler::equal, runtime); // If yes, goto runtime
-
- __ subptr(tmp, wordSize); // tmp := tmp - wordSize
- __ movptr(index, tmp); // *index_adr := tmp
- __ addptr(tmp, buffer); // tmp := tmp + *buffer_adr
-
- // Record the previous value
- __ movptr(Address(tmp, 0), pre_val);
- __ jmp(done);
+ generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, done, runtime);
__ bind(runtime);
@@ -263,6 +283,54 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
__ bind(done);
}
+static void generate_post_barrier_fast_path(MacroAssembler* masm,
+ const Register store_addr,
+ const Register new_val,
+ const Register tmp,
+ const Register tmp2,
+ Label& done,
+ bool new_val_may_be_null) {
+ CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set());
+ // Does store cross heap regions?
+ __ movptr(tmp, store_addr); // tmp := store address
+ __ xorptr(tmp, new_val); // tmp := store address ^ new value
+ __ shrptr(tmp, G1HeapRegion::LogOfHRGrainBytes); // ((store address ^ new value) >> LogOfHRGrainBytes) == 0?
+ __ jcc(Assembler::equal, done);
+ // Crosses regions, storing null?
+ if (new_val_may_be_null) {
+ __ cmpptr(new_val, NULL_WORD); // new value == null?
+ __ jcc(Assembler::equal, done);
+ }
+ // Storing region crossing non-null, is card young?
+ __ movptr(tmp, store_addr); // tmp := store address
+ __ shrptr(tmp, CardTable::card_shift()); // tmp := card address relative to card table base
+ // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT
+ // a valid address and therefore is not properly handled by the relocation code.
+ __ movptr(tmp2, (intptr_t)ct->card_table()->byte_map_base()); // tmp2 := card table base address
+ __ addptr(tmp, tmp2); // tmp := card address
+ __ cmpb(Address(tmp, 0), G1CardTable::g1_young_card_val()); // *(card address) == young_card_val?
+}
+
+static void generate_post_barrier_slow_path(MacroAssembler* masm,
+ const Register thread,
+ const Register tmp,
+ const Register tmp2,
+ Label& done,
+ Label& runtime) {
+ __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); // StoreLoad membar
+ __ cmpb(Address(tmp, 0), G1CardTable::dirty_card_val()); // *(card address) == dirty_card_val?
+ __ jcc(Assembler::equal, done);
+ // Storing a region crossing, non-null oop, card is clean.
+ // Dirty card and log.
+ __ movb(Address(tmp, 0), G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val
+ generate_queue_insertion(masm,
+ G1ThreadLocalData::dirty_card_queue_index_offset(),
+ G1ThreadLocalData::dirty_card_queue_buffer_offset(),
+ runtime,
+ thread, tmp, tmp2);
+ __ jmp(done);
+}
+
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
Register store_addr,
Register new_val,
@@ -273,74 +341,125 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
assert(thread == r15_thread, "must be");
#endif // _LP64
- Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
- Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
-
- CardTableBarrierSet* ct =
- barrier_set_cast(BarrierSet::barrier_set());
-
Label done;
Label runtime;
- // Does store cross heap regions?
-
- __ movptr(tmp, store_addr);
- __ xorptr(tmp, new_val);
- __ shrptr(tmp, G1HeapRegion::LogOfHRGrainBytes);
+ generate_post_barrier_fast_path(masm, store_addr, new_val, tmp, tmp2, done, true /* new_val_may_be_null */);
+ // If card is young, jump to done
__ jcc(Assembler::equal, done);
+ generate_post_barrier_slow_path(masm, thread, tmp, tmp2, done, runtime);
- // crosses regions, storing null?
+ __ bind(runtime);
+ // save the live input values
+ RegSet saved = RegSet::of(store_addr NOT_LP64(COMMA thread));
+ __ push_set(saved);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp, thread);
+ __ pop_set(saved);
- __ cmpptr(new_val, NULL_WORD);
- __ jcc(Assembler::equal, done);
+ __ bind(done);
+}
- // storing region crossing non-null, is card already dirty?
+#if defined(COMPILER2)
- const Register card_addr = tmp;
- const Register cardtable = tmp2;
+static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) {
+#ifdef _LP64
+ SaveLiveRegisters save_registers(masm, stub);
+ if (c_rarg0 != arg) {
+ __ mov(c_rarg0, arg);
+ }
+ __ mov(c_rarg1, r15_thread);
+ // rax is a caller-saved, non-argument-passing register, so it does not
+ // interfere with c_rarg0 or c_rarg1. If it contained any live value before
+ // entering this stub, it is saved at this point, and restored after the
+ // call. If it did not contain any live value, it is free to be used. In
+ // either case, it is safe to use it here as a call scratch register.
+ __ call(RuntimeAddress(runtime_path), rax);
+#else
+ Unimplemented();
+#endif // _LP64
+}
- __ movptr(card_addr, store_addr);
- __ shrptr(card_addr, CardTable::card_shift());
- // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT
- // a valid address and therefore is not properly handled by the relocation code.
- __ movptr(cardtable, (intptr_t)ct->card_table()->byte_map_base());
- __ addptr(card_addr, cardtable);
+void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp,
+ G1PreBarrierStubC2* stub) {
+#ifdef _LP64
+ assert(thread == r15_thread, "must be");
+#endif // _LP64
+ assert(pre_val != noreg, "check this code");
+ if (obj != noreg) {
+ assert_different_registers(obj, pre_val, tmp);
+ }
- __ cmpb(Address(card_addr, 0), G1CardTable::g1_young_card_val());
- __ jcc(Assembler::equal, done);
+ stub->initialize_registers(obj, pre_val, thread, tmp);
- __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
- __ cmpb(Address(card_addr, 0), G1CardTable::dirty_card_val());
- __ jcc(Assembler::equal, done);
+ generate_pre_barrier_fast_path(masm, thread);
+ // If marking is active (*(mark queue active address) != 0), jump to stub (slow path)
+ __ jcc(Assembler::notEqual, *stub->entry());
+ __ bind(*stub->continuation());
+}
- // storing a region crossing, non-null oop, card is clean.
- // dirty card and log.
+void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm,
+ G1PreBarrierStubC2* stub) const {
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ Label runtime;
+ Register obj = stub->obj();
+ Register pre_val = stub->pre_val();
+ Register thread = stub->thread();
+ Register tmp = stub->tmp1();
+ assert(stub->tmp2() == noreg, "not needed in this platform");
- __ movb(Address(card_addr, 0), G1CardTable::dirty_card_val());
+ __ bind(*stub->entry());
+ generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, *stub->continuation(), runtime);
- // The code below assumes that buffer index is pointer sized.
- STATIC_ASSERT(in_bytes(G1DirtyCardQueue::byte_width_of_index()) == sizeof(intptr_t));
+ __ bind(runtime);
+ generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry));
+ __ jmp(*stub->continuation());
+}
- __ movptr(tmp2, queue_index);
- __ testptr(tmp2, tmp2);
- __ jcc(Assembler::zero, runtime);
- __ subptr(tmp2, wordSize);
- __ movptr(queue_index, tmp2);
- __ addptr(tmp2, buffer);
- __ movptr(Address(tmp2, 0), card_addr);
- __ jmp(done);
+void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp,
+ Register tmp2,
+ G1PostBarrierStubC2* stub) {
+#ifdef _LP64
+ assert(thread == r15_thread, "must be");
+#endif // _LP64
- __ bind(runtime);
- // save the live input values
- RegSet saved = RegSet::of(store_addr NOT_LP64(COMMA thread));
- __ push_set(saved);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread);
- __ pop_set(saved);
+ stub->initialize_registers(thread, tmp, tmp2);
- __ bind(done);
+ bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0;
+ generate_post_barrier_fast_path(masm, store_addr, new_val, tmp, tmp2, *stub->continuation(), new_val_may_be_null);
+ // If card is not young, jump to stub (slow path)
+ __ jcc(Assembler::notEqual, *stub->entry());
+
+ __ bind(*stub->continuation());
+}
+
+void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm,
+ G1PostBarrierStubC2* stub) const {
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ Label runtime;
+ Register thread = stub->thread();
+ Register tmp = stub->tmp1(); // tmp holds the card address.
+ Register tmp2 = stub->tmp2();
+ assert(stub->tmp3() == noreg, "not needed in this platform");
+
+ __ bind(*stub->entry());
+ generate_post_barrier_slow_path(masm, thread, tmp, tmp2, *stub->continuation(), runtime);
+
+ __ bind(runtime);
+ generate_c2_barrier_runtime_call(masm, stub, tmp, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry));
+ __ jmp(*stub->continuation());
}
+#endif // COMPILER2
+
void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
bool in_heap = (decorators & IN_HEAP) != 0;
diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp
index a5695f5657a..4dbb1efd885 100644
--- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp
+++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp
@@ -32,6 +32,9 @@ class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
class G1PostBarrierStub;
+class G1BarrierStubC2;
+class G1PreBarrierStubC2;
+class G1PostBarrierStubC2;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@@ -65,6 +68,26 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Address src, Register tmp1, Register tmp_thread);
+
+#ifdef COMPILER2
+ void g1_write_barrier_pre_c2(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp,
+ G1PreBarrierStubC2* c2_stub);
+ void generate_c2_pre_barrier_stub(MacroAssembler* masm,
+ G1PreBarrierStubC2* stub) const;
+ void g1_write_barrier_post_c2(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp,
+ Register tmp2,
+ G1PostBarrierStubC2* c2_stub);
+ void generate_c2_post_barrier_stub(MacroAssembler* masm,
+ G1PostBarrierStubC2* stub) const;
+#endif // COMPILER2
};
#endif // CPU_X86_GC_G1_G1BARRIERSETASSEMBLER_X86_HPP
diff --git a/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad b/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad
new file mode 100644
index 00000000000..8c1559f90f4
--- /dev/null
+++ b/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad
@@ -0,0 +1,371 @@
+//
+// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+//
+// This code is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 2 only, as
+// published by the Free Software Foundation.
+//
+// This code is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// version 2 for more details (a copy is included in the LICENSE file that
+// accompanied this code).
+//
+// You should have received a copy of the GNU General Public License version
+// 2 along with this work; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+// or visit www.oracle.com if you need additional information or have any
+// questions.
+//
+
+source_hpp %{
+
+#include "gc/g1/c2/g1BarrierSetC2.hpp"
+#include "gc/shared/gc_globals.hpp"
+
+%}
+
+source %{
+
+#include "gc/g1/g1BarrierSetAssembler_x86.hpp"
+#include "gc/g1/g1BarrierSetRuntime.hpp"
+
+static void write_barrier_pre(MacroAssembler* masm,
+ const MachNode* node,
+ Register obj,
+ Register pre_val,
+ Register tmp,
+ RegSet preserve = RegSet(),
+ RegSet no_preserve = RegSet()) {
+ if (!G1PreBarrierStubC2::needs_barrier(node)) {
+ return;
+ }
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
+ G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node);
+ for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) {
+ stub->preserve(*reg);
+ }
+ for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) {
+ stub->dont_preserve(*reg);
+ }
+ g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, r15_thread, tmp, stub);
+}
+
+static void write_barrier_post(MacroAssembler* masm,
+ const MachNode* node,
+ Register store_addr,
+ Register new_val,
+ Register tmp1,
+ Register tmp2) {
+ if (!G1PostBarrierStubC2::needs_barrier(node)) {
+ return;
+ }
+ Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
+ G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler());
+ G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
+ g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, r15_thread, tmp1, tmp2, stub);
+}
+
+%}
+
+instruct g1StoreP(memory mem, any_RegP src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreP mem src));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(125); // XXX
+ format %{ "movq $mem, $src\t# ptr" %}
+ ins_encode %{
+ // Materialize the store address internally (as opposed to defining 'mem' as
+ // an indirect memory operand) to reduce the overhead of LCM when processing
+ // large basic blocks with many stores. Such basic blocks arise, for
+ // instance, from static initializations of large String arrays.
+ // The same holds for g1StoreN and g1EncodePAndStoreN.
+ __ lea($tmp1$$Register, $mem$$Address);
+ write_barrier_pre(masm, this,
+ $tmp1$$Register /* obj */,
+ $tmp2$$Register /* pre_val */,
+ $tmp3$$Register /* tmp */,
+ RegSet::of($tmp1$$Register, $src$$Register) /* preserve */);
+ __ movq(Address($tmp1$$Register, 0), $src$$Register);
+ write_barrier_post(masm, this,
+ $tmp1$$Register /* store_addr */,
+ $src$$Register /* new_val */,
+ $tmp3$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(ialu_mem_reg);
+%}
+
+instruct g1StoreN(memory mem, rRegN src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreN mem src));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(125); // XXX
+ format %{ "movl $mem, $src\t# ptr" %}
+ ins_encode %{
+ __ lea($tmp1$$Register, $mem$$Address);
+ write_barrier_pre(masm, this,
+ $tmp1$$Register /* obj */,
+ $tmp2$$Register /* pre_val */,
+ $tmp3$$Register /* tmp */,
+ RegSet::of($tmp1$$Register, $src$$Register) /* preserve */);
+ __ movl(Address($tmp1$$Register, 0), $src$$Register);
+ if ((barrier_data() & G1C2BarrierPost) != 0) {
+ __ movl($tmp2$$Register, $src$$Register);
+ if ((barrier_data() & G1C2BarrierPostNotNull) == 0) {
+ __ decode_heap_oop($tmp2$$Register);
+ } else {
+ __ decode_heap_oop_not_null($tmp2$$Register);
+ }
+ }
+ write_barrier_post(masm, this,
+ $tmp1$$Register /* store_addr */,
+ $tmp2$$Register /* new_val */,
+ $tmp3$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(ialu_mem_reg);
+%}
+
+instruct g1EncodePAndStoreN(memory mem, any_RegP src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_Store()->barrier_data() != 0);
+ match(Set mem (StoreN mem (EncodeP src)));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ ins_cost(125); // XXX
+ format %{ "encode_heap_oop $src\n\t"
+ "movl $mem, $src\t# ptr" %}
+ ins_encode %{
+ __ lea($tmp1$$Register, $mem$$Address);
+ write_barrier_pre(masm, this,
+ $tmp1$$Register /* obj */,
+ $tmp2$$Register /* pre_val */,
+ $tmp3$$Register /* tmp */,
+ RegSet::of($tmp1$$Register, $src$$Register) /* preserve */);
+ __ movq($tmp2$$Register, $src$$Register);
+ if ((barrier_data() & G1C2BarrierPostNotNull) == 0) {
+ __ encode_heap_oop($tmp2$$Register);
+ } else {
+ __ encode_heap_oop_not_null($tmp2$$Register);
+ }
+ __ movl(Address($tmp1$$Register, 0), $tmp2$$Register);
+ write_barrier_post(masm, this,
+ $tmp1$$Register /* store_addr */,
+ $src$$Register /* new_val */,
+ $tmp3$$Register /* tmp1 */,
+ $tmp2$$Register /* tmp2 */);
+ %}
+ ins_pipe(ialu_mem_reg);
+%}
+
+instruct g1CompareAndExchangeP(indirect mem, rRegP newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegP oldval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set oldval (CompareAndExchangeP mem (Binary oldval newval)));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ format %{ "lock\n\t"
+ "cmpxchgq $newval, $mem" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ // Pass $oldval to the pre-barrier (instead of loading from $mem), because
+ // $oldval is the only value that can be overwritten.
+ // The same holds for g1CompareAndSwapP.
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $oldval$$Register /* pre_val */,
+ $tmp3$$Register /* tmp */,
+ RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */);
+ __ movq($tmp1$$Register, $newval$$Register);
+ __ lock();
+ __ cmpxchgq($tmp1$$Register, Address($mem$$Register, 0));
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_cmpxchg);
+%}
+
+instruct g1CompareAndExchangeN(indirect mem, rRegN newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegN oldval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set oldval (CompareAndExchangeN mem (Binary oldval newval)));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ format %{ "lock\n\t"
+ "cmpxchgq $newval, $mem" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp2$$Register /* pre_val */,
+ $tmp3$$Register /* tmp */,
+ RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */);
+ __ movl($tmp1$$Register, $newval$$Register);
+ __ lock();
+ __ cmpxchgl($tmp1$$Register, Address($mem$$Register, 0));
+ __ decode_heap_oop($tmp1$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_cmpxchg);
+%}
+
+instruct g1CompareAndSwapP(rRegI res, indirect mem, rRegP newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegP oldval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapP mem (Binary oldval newval)));
+ match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL oldval, KILL cr);
+ format %{ "lock\n\t"
+ "cmpxchgq $newval, $mem\n\t"
+ "sete $res\n\t"
+ "movzbl $res, $res" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $oldval$$Register /* pre_val */,
+ $tmp3$$Register /* tmp */,
+ RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ movq($tmp1$$Register, $newval$$Register);
+ __ lock();
+ __ cmpxchgq($tmp1$$Register, Address($mem$$Register, 0));
+ __ setb(Assembler::equal, $res$$Register);
+ __ movzbl($res$$Register, $res$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_cmpxchg);
+%}
+
+instruct g1CompareAndSwapN(rRegI res, indirect mem, rRegN newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegN oldval, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set res (CompareAndSwapN mem (Binary oldval newval)));
+ match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
+ effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL oldval, KILL cr);
+ format %{ "lock\n\t"
+ "cmpxchgq $newval, $mem\n\t"
+ "sete $res\n\t"
+ "movzbl $res, $res" %}
+ ins_encode %{
+ assert_different_registers($oldval$$Register, $mem$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp2$$Register /* pre_val */,
+ $tmp3$$Register /* tmp */,
+ RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */,
+ RegSet::of($res$$Register) /* no_preserve */);
+ __ movl($tmp1$$Register, $newval$$Register);
+ __ lock();
+ __ cmpxchgl($tmp1$$Register, Address($mem$$Register, 0));
+ __ setb(Assembler::equal, $res$$Register);
+ __ movzbl($res$$Register, $res$$Register);
+ __ decode_heap_oop($tmp1$$Register);
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_cmpxchg);
+%}
+
+instruct g1GetAndSetP(indirect mem, rRegP newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set newval (GetAndSetP mem newval));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ format %{ "xchgq $newval, $mem" %}
+ ins_encode %{
+ assert_different_registers($mem$$Register, $newval$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp2$$Register /* pre_val */,
+ $tmp3$$Register /* tmp */,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */);
+ __ movq($tmp1$$Register, $newval$$Register);
+ __ xchgq($newval$$Register, Address($mem$$Register, 0));
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_cmpxchg);
+%}
+
+instruct g1GetAndSetN(indirect mem, rRegN newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0);
+ match(Set newval (GetAndSetN mem newval));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
+ format %{ "xchgq $newval, $mem" %}
+ ins_encode %{
+ assert_different_registers($mem$$Register, $newval$$Register);
+ write_barrier_pre(masm, this,
+ $mem$$Register /* obj */,
+ $tmp2$$Register /* pre_val */,
+ $tmp3$$Register /* tmp */,
+ RegSet::of($mem$$Register, $newval$$Register) /* preserve */);
+ __ movl($tmp1$$Register, $newval$$Register);
+ __ decode_heap_oop($tmp1$$Register);
+ __ xchgl($newval$$Register, Address($mem$$Register, 0));
+ write_barrier_post(masm, this,
+ $mem$$Register /* store_addr */,
+ $tmp1$$Register /* new_val */,
+ $tmp2$$Register /* tmp1 */,
+ $tmp3$$Register /* tmp2 */);
+ %}
+ ins_pipe(pipe_cmpxchg);
+%}
+
+instruct g1LoadP(rRegP dst, memory mem, rRegP tmp, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_Load()->barrier_data() != 0);
+ match(Set dst (LoadP mem));
+ effect(TEMP dst, TEMP tmp, KILL cr);
+ ins_cost(125); // XXX
+ format %{ "movq $dst, $mem\t# ptr" %}
+ ins_encode %{
+ __ movq($dst$$Register, $mem$$Address);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $dst$$Register /* pre_val */,
+ $tmp$$Register /* tmp */);
+ %}
+ ins_pipe(ialu_reg_mem); // XXX
+%}
+
+instruct g1LoadN(rRegN dst, memory mem, rRegP tmp1, rRegP tmp2, rFlagsReg cr)
+%{
+ predicate(UseG1GC && n->as_Load()->barrier_data() != 0);
+ match(Set dst (LoadN mem));
+ effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr);
+ ins_cost(125); // XXX
+ format %{ "movl $dst, $mem\t# compressed ptr" %}
+ ins_encode %{
+ __ movl($dst$$Register, $mem$$Address);
+ __ movl($tmp1$$Register, $dst$$Register);
+ __ decode_heap_oop($tmp1$$Register);
+ write_barrier_pre(masm, this,
+ noreg /* obj */,
+ $tmp1$$Register /* pre_val */,
+ $tmp2$$Register /* tmp */);
+ %}
+ ins_pipe(ialu_reg_mem); // XXX
+%}
diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp
index 64ad7430674..cd0e43b68bf 100644
--- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -423,7 +423,7 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) {
__ load_method_holder_cld(tmp1, rbx);
// Is it a strong CLD?
- __ cmpl(Address(tmp1, ClassLoaderData::keep_alive_offset()), 0);
+ __ cmpl(Address(tmp1, ClassLoaderData::keep_alive_ref_count_offset()), 0);
__ jcc(Assembler::greater, method_live);
// Is it a weak but alive CLD?
diff --git a/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp
index 9995a87f5cf..032b33f40e0 100644
--- a/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp
+++ b/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp
@@ -46,9 +46,6 @@ void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler* masm) {
assert(cmpval != addr, "cmp and addr must be in different registers");
assert(newval != addr, "new value and addr must be in different registers");
- // Apply IU barrier to newval.
- ShenandoahBarrierSet::assembler()->iu_barrier(masm->masm(), newval, tmp1);
-
#ifdef _LP64
if (UseCompressedOops) {
__ encode_heap_oop(cmpval);
@@ -101,10 +98,6 @@ LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRIt
value.load_item();
LIR_Opr value_opr = value.result();
- if (access.is_oop()) {
- value_opr = iu_barrier(access.gen(), value_opr, access.access_emit_info(), access.decorators());
- }
-
// Because we want a 2-arg form of xchg and xadd
__ move(value_opr, result);
diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp
index 25a2b931468..a7682fe0c38 100644
--- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp
@@ -121,7 +121,7 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec
if (is_reference_type(type)) {
- if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahIUBarrier || ShenandoahLoadRefBarrier) {
+ if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) {
#ifdef _LP64
Register thread = r15_thread;
#else
@@ -163,12 +163,12 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec
assert(dst == rsi, "expected");
assert(count == rdx, "expected");
if (UseCompressedOops) {
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry),
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop),
src, dst, count);
} else
#endif
{
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry),
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop),
src, dst, count);
}
@@ -296,9 +296,9 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
__ push(thread);
__ push(pre_val);
#endif
- __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), 2);
+ __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), 2);
} else {
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), LP64_ONLY(c_rarg0) NOT_LP64(pre_val), thread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), LP64_ONLY(c_rarg0) NOT_LP64(pre_val), thread);
}
NOT_LP64( __ pop(thread); )
@@ -472,40 +472,6 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
#endif
}
-void ShenandoahBarrierSetAssembler::iu_barrier(MacroAssembler* masm, Register dst, Register tmp) {
- if (ShenandoahIUBarrier) {
- iu_barrier_impl(masm, dst, tmp);
- }
-}
-
-void ShenandoahBarrierSetAssembler::iu_barrier_impl(MacroAssembler* masm, Register dst, Register tmp) {
- assert(ShenandoahIUBarrier, "should be enabled");
-
- if (dst == noreg) return;
-
- if (ShenandoahIUBarrier) {
- save_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ true);
-
-#ifdef _LP64
- Register thread = r15_thread;
-#else
- Register thread = rcx;
- if (thread == dst || thread == tmp) {
- thread = rdi;
- }
- if (thread == dst || thread == tmp) {
- thread = rbx;
- }
- __ get_thread(thread);
-#endif
- assert_different_registers(dst, tmp, thread);
-
- satb_write_barrier_pre(masm, noreg, dst, thread, tmp, true, false);
-
- restore_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ true);
- }
-}
-
//
// Arguments:
//
@@ -626,12 +592,7 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet
val != noreg /* tosca_live */,
false /* expand_call */);
}
- if (val == noreg) {
- BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg);
- } else {
- iu_barrier(masm, val, tmp3);
- BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg);
- }
+ BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg);
NOT_LP64(imasm->restore_bcp());
} else {
BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
@@ -964,7 +925,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss
// load the pre-value
__ load_parameter(0, rcx);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), rcx, thread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), rcx, thread);
__ restore_live_registers(true);
diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp
index 47dfe144928..c8140f4a76a 100644
--- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp
+++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp
@@ -56,10 +56,7 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler {
bool tosca_live,
bool expand_call);
- void iu_barrier_impl(MacroAssembler* masm, Register dst, Register tmp);
-
public:
- void iu_barrier(MacroAssembler* masm, Register dst, Register tmp);
#ifdef COMPILER1
void gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub);
void gen_load_reference_barrier_stub(LIR_Assembler* ce, ShenandoahLoadReferenceBarrierStub* stub);
diff --git a/src/hotspot/cpu/x86/gc/x/x_x86_64.ad b/src/hotspot/cpu/x86/gc/x/x_x86_64.ad
index 116fb3cbc6d..ba4b3cb6df0 100644
--- a/src/hotspot/cpu/x86/gc/x/x_x86_64.ad
+++ b/src/hotspot/cpu/x86/gc/x/x_x86_64.ad
@@ -126,8 +126,7 @@ instruct xCompareAndSwapP(rRegI res, indirect mem, rRegP newval, rRegP tmp, rFla
format %{ "lock\n\t"
"cmpxchgq $newval, $mem\n\t"
- "sete $res\n\t"
- "movzbl $res, $res" %}
+ "setcc $res \t# emits sete + movzbl or setzue for APX" %}
ins_encode %{
precond($oldval$$Register == rax);
@@ -135,8 +134,7 @@ instruct xCompareAndSwapP(rRegI res, indirect mem, rRegP newval, rRegP tmp, rFla
if (barrier_data() != XLoadBarrierElided) {
__ cmpptr($tmp$$Register, rax);
}
- __ setb(Assembler::equal, $res$$Register);
- __ movzbl($res$$Register, $res$$Register);
+ __ setcc(Assembler::equal, $res$$Register);
%}
ins_pipe(pipe_cmpxchg);
diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp
index f5f0d6c8841..bc51a2b4468 100644
--- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp
@@ -636,7 +636,7 @@ void ZBarrierSetAssembler::copy_load_at(MacroAssembler* masm,
// Remove metadata bits so that the store side (vectorized or non-vectorized) can
// inject the store-good color with an or instruction.
- __ andq(dst, _zpointer_address_mask);
+ __ andq(dst, ZPointerAddressMask);
if ((decorators & ARRAYCOPY_CHECKCAST) != 0) {
// The checkcast arraycopy needs to be able to dereference the oops in order to perform a typechecks.
@@ -1260,6 +1260,8 @@ void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm,
__ call(RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr()));
} else if (stub->is_atomic()) {
__ call(RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr()));
+ } else if (stub->is_nokeepalive()) {
+ __ call(RuntimeAddress(ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr()));
} else {
__ call(RuntimeAddress(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr()));
}
diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp
index 7c3716ba0da..5fbc7ea1be1 100644
--- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp
+++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp
@@ -64,7 +64,7 @@ class ZBarrierSetAssembler : public ZBarrierSetAssemblerBase {
GrowableArrayCHeap _store_good_relocations;
public:
- static const int32_t _zpointer_address_mask = 0xFFFF0000;
+ static const int32_t ZPointerAddressMask = 0xFFFF0000;
ZBarrierSetAssembler();
diff --git a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad
index 1a4499c3d44..f55ad70e861 100644
--- a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad
+++ b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad
@@ -91,7 +91,8 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address
}
} else {
bool is_native = (node->barrier_data() & ZBarrierNative) != 0;
- ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic);
+ bool is_nokeepalive = (node->barrier_data() & ZBarrierNoKeepalive) != 0;
+ ZStoreBarrierStubC2* const stub = ZStoreBarrierStubC2::create(node, ref_addr, rnew_zaddress, rnew_zpointer, is_native, is_atomic, is_nokeepalive);
ZBarrierSetAssembler* bs_asm = ZBarrierSet::assembler();
bs_asm->store_barrier_fast(masm, ref_addr, rnew_zaddress, rnew_zpointer, true /* in_nmethod */, is_atomic, *stub->entry(), *stub->continuation());
}
@@ -141,7 +142,7 @@ instruct zLoadPNullCheck(rFlagsReg cr, memory op, immP0 zero)
ins_encode %{
// A null pointer will have all address bits 0. This mask sign extends
// all address bits, so we can test if the address is 0.
- __ testq($op$$Address, ZBarrierSetAssembler::_zpointer_address_mask);
+ __ testq($op$$Address, ZBarrierSetAssembler::ZPointerAddressMask);
%}
ins_pipe(ialu_cr_reg_imm);
%}
@@ -212,8 +213,7 @@ instruct zCompareAndSwapP(rRegI res, indirect mem, rRegP newval, rRegP tmp, rax_
format %{ "lock\n\t"
"cmpxchgq $newval, $mem\n\t"
- "sete $res\n\t"
- "movzbl $res, $res" %}
+ "setcc $res \t# emits sete + movzbl or setzue for APX" %}
ins_encode %{
assert_different_registers($oldval$$Register, $mem$$Register);
@@ -222,8 +222,7 @@ instruct zCompareAndSwapP(rRegI res, indirect mem, rRegP newval, rRegP tmp, rax_
z_color(masm, this, $oldval$$Register);
__ lock();
__ cmpxchgptr($tmp$$Register, mem_addr);
- __ setb(Assembler::equal, $res$$Register);
- __ movzbl($res$$Register, $res$$Register);
+ __ setcc(Assembler::equal, $res$$Register);
%}
ins_pipe(pipe_cmpxchg);
diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp
index 57d77bafd4b..f4b95d846c6 100644
--- a/src/hotspot/cpu/x86/interp_masm_x86.cpp
+++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp
@@ -1175,19 +1175,18 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) {
if (DiagnoseSyncOnValueBasedClasses != 0) {
load_klass(tmp_reg, obj_reg, rklass_decode_tmp);
- movl(tmp_reg, Address(tmp_reg, Klass::access_flags_offset()));
- testl(tmp_reg, JVM_ACC_IS_VALUE_BASED_CLASS);
+ testb(Address(tmp_reg, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class);
jcc(Assembler::notZero, slow_case);
}
if (LockingMode == LM_LIGHTWEIGHT) {
#ifdef _LP64
const Register thread = r15_thread;
+ lightweight_lock(lock_reg, obj_reg, swap_reg, thread, tmp_reg, slow_case);
#else
- const Register thread = lock_reg;
- get_thread(thread);
+ // Lacking registers and thread on x86_32. Always take slow path.
+ jmp(slow_case);
#endif
- 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);
@@ -1249,15 +1248,9 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) {
bind(slow_case);
// Call the runtime routine for slow case
- if (LockingMode == LM_LIGHTWEIGHT) {
- call_VM(noreg,
- CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj),
- obj_reg);
- } else {
- call_VM(noreg,
- CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter),
- lock_reg);
- }
+ call_VM(noreg,
+ CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter),
+ lock_reg);
bind(done);
}
}
@@ -1306,10 +1299,8 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) {
#ifdef _LP64
lightweight_unlock(obj_reg, swap_reg, r15_thread, header_reg, slow_case);
#else
- // This relies on the implementation of lightweight_unlock being able to handle
- // that the reg_rax and thread Register parameters may alias each other.
- get_thread(swap_reg);
- lightweight_unlock(obj_reg, swap_reg, swap_reg, header_reg, slow_case);
+ // Lacking registers and thread on x86_32. Always take slow path.
+ jmp(slow_case);
#endif
} else if (LockingMode == LM_LEGACY) {
// Load the old header from BasicLock structure
diff --git a/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp b/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp
index 34be2a61b5a..52e4388c5d2 100644
--- a/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp
+++ b/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -138,7 +138,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
default: ShouldNotReachHere();
}
// tail call
- __ jump (ExternalAddress(slow_case_addr));
+ __ jump (RuntimeAddress(slow_case_addr));
__ flush ();
@@ -251,7 +251,7 @@ address JNI_FastGetField::generate_fast_get_long_field() {
__ pop (rsi);
address slow_case_addr = jni_GetLongField_addr();;
// tail call
- __ jump (ExternalAddress(slow_case_addr));
+ __ jump (RuntimeAddress(slow_case_addr));
__ flush ();
@@ -350,7 +350,7 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
default: ShouldNotReachHere();
}
// tail call
- __ jump (ExternalAddress(slow_case_addr));
+ __ jump (RuntimeAddress(slow_case_addr));
__ flush ();
diff --git a/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp b/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp
index 4506205c259..e94b7d12b0b 100644
--- a/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp
+++ b/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -118,7 +118,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
default: break;
}
// tail call
- __ jump (ExternalAddress(slow_case_addr), rscratch1);
+ __ jump (RuntimeAddress(slow_case_addr), rscratch1);
__ flush ();
@@ -206,7 +206,7 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
default: break;
}
// tail call
- __ jump (ExternalAddress(slow_case_addr), rscratch1);
+ __ jump (RuntimeAddress(slow_case_addr), rscratch1);
__ flush ();
diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp
index affd18f937c..1a69b4c1ad7 100644
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp
@@ -1303,7 +1303,7 @@ void MacroAssembler::reserved_stack_check() {
jcc(Assembler::below, no_reserved_zone_enabling);
call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), thread);
- jump(RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry()));
+ jump(RuntimeAddress(SharedRuntime::throw_delayed_StackOverflowError_entry()));
should_not_reach_here();
bind(no_reserved_zone_enabling);
@@ -2329,7 +2329,7 @@ void MacroAssembler::incrementl(Address dst, int value) {
void MacroAssembler::jump(AddressLiteral dst, Register rscratch) {
assert(rscratch != noreg || always_reachable(dst), "missing");
-
+ assert(!dst.rspec().reloc()->is_data(), "should not use ExternalAddress for jump");
if (reachable(dst)) {
jmp_literal(dst.target(), dst.rspec());
} else {
@@ -2340,7 +2340,7 @@ void MacroAssembler::jump(AddressLiteral dst, Register rscratch) {
void MacroAssembler::jump_cc(Condition cc, AddressLiteral dst, Register rscratch) {
assert(rscratch != noreg || always_reachable(dst), "missing");
-
+ assert(!dst.rspec().reloc()->is_data(), "should not use ExternalAddress for jump_cc");
if (reachable(dst)) {
InstructionMark im(this);
relocate(dst.reloc());
@@ -3482,6 +3482,17 @@ void MacroAssembler::vpbroadcastd(XMMRegister dst, AddressLiteral src, int vecto
}
}
+void MacroAssembler::vbroadcasti128(XMMRegister dst, AddressLiteral src, int vector_len, Register rscratch) {
+ assert(rscratch != noreg || always_reachable(src), "missing");
+
+ if (reachable(src)) {
+ Assembler::vbroadcasti128(dst, as_Address(src), vector_len);
+ } else {
+ lea(rscratch, src);
+ Assembler::vbroadcasti128(dst, Address(rscratch, 0), vector_len);
+ }
+}
+
void MacroAssembler::vpbroadcastq(XMMRegister dst, AddressLiteral src, int vector_len, Register rscratch) {
assert(rscratch != noreg || always_reachable(src), "missing");
@@ -4945,9 +4956,8 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl
// The bitmap is full to bursting.
// Implicit invariant: BITMAP_FULL implies (length > 0)
- assert(Klass::SECONDARY_SUPERS_BITMAP_FULL == ~uintx(0), "");
- cmpq(r_bitmap, (int32_t)-1); // sign-extends immediate to 64-bit value
- jcc(Assembler::equal, L_huge);
+ cmpl(r_array_length, (int32_t)Klass::SECONDARY_SUPERS_TABLE_SIZE - 2);
+ jcc(Assembler::greater, L_huge);
// NB! Our caller has checked bits 0 and 1 in the bitmap. The
// current slot (at secondary_supers[r_array_index]) has not yet
@@ -5085,7 +5095,8 @@ void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fa
L_slow_path = &L_fallthrough;
}
- // Fast path check: class is fully initialized
+ // Fast path check: class is fully initialized.
+ // init_state needs acquire, but x86 is TSO, and so we are already good.
cmpb(Address(klass, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized);
jcc(Assembler::equal, *L_fast_path);
@@ -5757,7 +5768,7 @@ void MacroAssembler::verify_heapbase(const char* msg) {
assert (Universe::heap() != nullptr, "java heap should be initialized");
if (CheckCompressedOops) {
Label ok;
- ExternalAddress src2(CompressedOops::ptrs_base_addr());
+ ExternalAddress src2(CompressedOops::base_addr());
const bool is_src2_reachable = reachable(src2);
if (!is_src2_reachable) {
push(rscratch1); // cmpptr trashes rscratch1
@@ -6048,10 +6059,10 @@ void MacroAssembler::reinit_heapbase() {
if (CompressedOops::base() == nullptr) {
MacroAssembler::xorptr(r12_heapbase, r12_heapbase);
} else {
- mov64(r12_heapbase, (int64_t)CompressedOops::ptrs_base());
+ mov64(r12_heapbase, (int64_t)CompressedOops::base());
}
} else {
- movptr(r12_heapbase, ExternalAddress(CompressedOops::ptrs_base_addr()));
+ movptr(r12_heapbase, ExternalAddress(CompressedOops::base_addr()));
}
}
}
@@ -10276,9 +10287,9 @@ void MacroAssembler::check_stack_alignment(Register sp, const char* msg, unsigne
// reg_rax: rax
// thread: the thread which attempts to lock obj
// tmp: a temporary register
-void MacroAssembler::lightweight_lock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow) {
+void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Register reg_rax, Register thread, Register tmp, Label& slow) {
assert(reg_rax == rax, "");
- assert_different_registers(obj, reg_rax, thread, tmp);
+ assert_different_registers(basic_lock, obj, reg_rax, thread, tmp);
Label push;
const Register top = tmp;
@@ -10287,6 +10298,11 @@ void MacroAssembler::lightweight_lock(Register obj, Register reg_rax, Register t
// instruction emitted as it is part of C1's null check semantics.
movptr(reg_rax, Address(obj, oopDesc::mark_offset_in_bytes()));
+ if (UseObjectMonitorTable) {
+ // Clear cache in case fast locking succeeds.
+ movptr(Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))), 0);
+ }
+
// Load top.
movl(top, Address(thread, JavaThread::lock_stack_top_offset()));
@@ -10325,13 +10341,9 @@ void MacroAssembler::lightweight_lock(Register obj, Register reg_rax, Register t
// reg_rax: rax
// thread: the thread
// tmp: a temporary register
-//
-// x86_32 Note: reg_rax and thread may alias each other due to limited register
-// availiability.
void MacroAssembler::lightweight_unlock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow) {
assert(reg_rax == rax, "");
- assert_different_registers(obj, reg_rax, tmp);
- LP64_ONLY(assert_different_registers(obj, reg_rax, thread, tmp);)
+ assert_different_registers(obj, reg_rax, thread, tmp);
Label unlocked, push_and_slow;
const Register top = tmp;
@@ -10371,10 +10383,6 @@ void MacroAssembler::lightweight_unlock(Register obj, Register reg_rax, Register
bind(push_and_slow);
// Restore lock-stack and handle the unlock in runtime.
- if (thread == reg_rax) {
- // On x86_32 we may lose the thread.
- get_thread(thread);
- }
#ifdef ASSERT
movl(top, Address(thread, JavaThread::lock_stack_top_offset()));
movptr(Address(thread, top), obj);
@@ -10425,4 +10433,13 @@ void MacroAssembler::restore_legacy_gprs() {
movq(rax, Address(rsp, 15 * wordSize));
addq(rsp, 16 * wordSize);
}
+
+void MacroAssembler::setcc(Assembler::Condition comparison, Register dst) {
+ if (VM_Version::supports_apx_f()) {
+ esetzucc(comparison, dst);
+ } else {
+ setb(comparison, dst);
+ movzbl(dst, dst);
+ }
+}
#endif
diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp
index 2ecd2bbe96d..e6de99eb207 100644
--- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp
@@ -1118,6 +1118,7 @@ class MacroAssembler: public Assembler {
XMMRegister msgtmp1, XMMRegister msgtmp2, XMMRegister msgtmp3, XMMRegister msgtmp4,
Register buf, Register state, Register ofs, Register limit, Register rsp, bool multi_block,
XMMRegister shuf_mask);
+ void sha512_update_ni_x1(Register arg_hash, Register arg_msg, Register ofs, Register limit, bool multi_block);
#endif // _LP64
void fast_md5(Register buf, Address state, Address ofs, Address limit,
@@ -1216,6 +1217,9 @@ class MacroAssembler: public Assembler {
void addpd(XMMRegister dst, Address src) { Assembler::addpd(dst, src); }
void addpd(XMMRegister dst, AddressLiteral src, Register rscratch = noreg);
+ using Assembler::vbroadcasti128;
+ void vbroadcasti128(XMMRegister dst, AddressLiteral src, int vector_len, Register rscratch = noreg);
+
using Assembler::vbroadcastsd;
void vbroadcastsd(XMMRegister dst, AddressLiteral src, int vector_len, Register rscratch = noreg);
@@ -2148,12 +2152,13 @@ class MacroAssembler: public Assembler {
void check_stack_alignment(Register sp, const char* msg, unsigned bias = 0, Register tmp = noreg);
- void lightweight_lock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow);
+ void lightweight_lock(Register basic_lock, Register obj, Register reg_rax, Register thread, Register tmp, Label& slow);
void lightweight_unlock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow);
#ifdef _LP64
void save_legacy_gprs();
void restore_legacy_gprs();
+ void setcc(Assembler::Condition comparison, Register dst);
#endif
};
diff --git a/src/hotspot/cpu/x86/macroAssembler_x86_md5.cpp b/src/hotspot/cpu/x86/macroAssembler_x86_md5.cpp
index 439c17b10d3..09d379a4296 100644
--- a/src/hotspot/cpu/x86/macroAssembler_x86_md5.cpp
+++ b/src/hotspot/cpu/x86/macroAssembler_x86_md5.cpp
@@ -81,8 +81,8 @@ void MacroAssembler::fast_md5(Register buf, Address state, Address ofs, Address
notl(rsi); \
andl(rdi, r2); \
andl(rsi, r3); \
- orl(rsi, rdi); \
addl(r1, rsi); \
+ addl(r1, rdi); \
roll(r1, s); \
addl(r1, r2);
diff --git a/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp b/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp
index c4e9e836fd3..e7d728c2e96 100644
--- a/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp
+++ b/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2016, 2021, Intel Corporation. All rights reserved.
+* Copyright (c) 2016, 2024, Intel Corporation. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -689,7 +689,7 @@ void MacroAssembler::sha256_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste
address K256_W = StubRoutines::x86::k256_W_addr();
address pshuffle_byte_flip_mask = StubRoutines::x86::pshuffle_byte_flip_mask_addr();
- address pshuffle_byte_flip_mask_addr = 0;
+ address pshuffle_byte_flip_mask_addr = nullptr;
const XMMRegister& SHUF_00BA = xmm10; // ymm10: shuffle xBxA -> 00BA
const XMMRegister& SHUF_DC00 = xmm12; // ymm12: shuffle xDxC -> DC00
@@ -1247,7 +1247,7 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste
address K512_W = StubRoutines::x86::k512_W_addr();
address pshuffle_byte_flip_mask_sha512 = StubRoutines::x86::pshuffle_byte_flip_mask_addr_sha512();
- address pshuffle_byte_flip_mask_addr = 0;
+ address pshuffle_byte_flip_mask_addr = nullptr;
const XMMRegister& XFER = xmm0; // YTMP0
const XMMRegister& BYTE_FLIP_MASK = xmm9; // ymm9
@@ -1519,5 +1519,184 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste
}
}
+//Implemented using Intel IpSec implementation (intel-ipsec-mb on github)
+void MacroAssembler::sha512_update_ni_x1(Register arg_hash, Register arg_msg, Register ofs, Register limit, bool multi_block) {
+ Label done_hash, block_loop;
+ address K512_W = StubRoutines::x86::k512_W_addr();
+
+ vbroadcasti128(xmm15, ExternalAddress(StubRoutines::x86::pshuffle_byte_flip_mask_addr_sha512()), Assembler::AVX_256bit, r10);
+
+ //load current hash value and transform
+ vmovdqu(xmm0, Address(arg_hash));
+ vmovdqu(xmm1, Address(arg_hash, 32));
+ //ymm0 = D C B A, ymm1 = H G F E
+ vperm2i128(xmm2, xmm0, xmm1, 0x20);
+ vperm2i128(xmm3, xmm0, xmm1, 0x31);
+ //ymm2 = F E B A, ymm3 = H G D C
+ vpermq(xmm13, xmm2, 0x1b, Assembler::AVX_256bit);
+ vpermq(xmm14, xmm3, 0x1b, Assembler::AVX_256bit);
+ //ymm13 = A B E F, ymm14 = C D G H
+
+ lea(rax, ExternalAddress(K512_W));
+ align(32);
+ bind(block_loop);
+ vmovdqu(xmm11, xmm13);//ABEF
+ vmovdqu(xmm12, xmm14);//CDGH
+
+ //R0 - R3
+ vmovdqu(xmm0, Address(arg_msg, 0 * 32));
+ vpshufb(xmm3, xmm0, xmm15, Assembler::AVX_256bit);//ymm0 / ymm3 = W[0..3]
+ vpaddq(xmm0, xmm3, Address(rax, 0 * 32), Assembler::AVX_256bit);
+ sha512rnds2(xmm12, xmm11, xmm0);
+ vperm2i128(xmm0, xmm0, xmm0, 0x01);
+ sha512rnds2(xmm11, xmm12, xmm0);
+
+ //R4 - R7
+ vmovdqu(xmm0, Address(arg_msg, 1 * 32));
+ vpshufb(xmm4, xmm0, xmm15, Assembler::AVX_256bit);//ymm0 / ymm4 = W[4..7]
+ vpaddq(xmm0, xmm4, Address(rax, 1 * 32), Assembler::AVX_256bit);
+ sha512rnds2(xmm12, xmm11, xmm0);
+ vperm2i128(xmm0, xmm0, xmm0, 0x01);
+ sha512rnds2(xmm11, xmm12, xmm0);
+ sha512msg1(xmm3, xmm4); //ymm3 = W[0..3] + S0(W[1..4])
+
+ //R8 - R11
+ vmovdqu(xmm0, Address(arg_msg, 2 * 32));
+ vpshufb(xmm5, xmm0, xmm15, Assembler::AVX_256bit);//ymm0 / ymm5 = W[8..11]
+ vpaddq(xmm0, xmm5, Address(rax, 2 * 32), Assembler::AVX_256bit);
+ sha512rnds2(xmm12, xmm11, xmm0);
+ vperm2i128(xmm0, xmm0, xmm0, 0x01);
+ sha512rnds2(xmm11, xmm12, xmm0);
+ sha512msg1(xmm4, xmm5);//ymm4 = W[4..7] + S0(W[5..8])
+
+ //R12 - R15
+ vmovdqu(xmm0, Address(arg_msg, 3 * 32));
+ vpshufb(xmm6, xmm0, xmm15, Assembler::AVX_256bit); //ymm0 / ymm6 = W[12..15]
+ vpaddq(xmm0, xmm6, Address(rax, 3 * 32), Assembler::AVX_256bit);
+ vpermq(xmm8, xmm6, 0x1b, Assembler::AVX_256bit); //ymm8 = W[12] W[13] W[14] W[15]
+ vpermq(xmm9, xmm5, 0x39, Assembler::AVX_256bit); //ymm9 = W[8] W[11] W[10] W[9]
+ vpblendd(xmm8, xmm8, xmm9, 0x3f, Assembler::AVX_256bit); //ymm8 = W[12] W[11] W[10] W[9]
+ vpaddq(xmm3, xmm3, xmm8, Assembler::AVX_256bit);
+ sha512msg2(xmm3, xmm6);//W[16..19] = xmm3 + W[9..12] + S1(W[14..17])
+ sha512rnds2(xmm12, xmm11, xmm0);
+ vperm2i128(xmm0, xmm0, xmm0, 0x01);
+ sha512rnds2(xmm11, xmm12, xmm0);
+ sha512msg1(xmm5, xmm6); //ymm5 = W[8..11] + S0(W[9..12])
+
+ //R16 - R19, R32 - R35, R48 - R51
+ for (int i = 4, j = 3; j > 0; j--) {
+ vpaddq(xmm0, xmm3, Address(rax, i * 32), Assembler::AVX_256bit);
+ vpermq(xmm8, xmm3, 0x1b, Assembler::AVX_256bit);//ymm8 = W[16] W[17] W[18] W[19]
+ vpermq(xmm9, xmm6, 0x39, Assembler::AVX_256bit);//ymm9 = W[12] W[15] W[14] W[13]
+ vpblendd(xmm7, xmm8, xmm9, 0x3f, Assembler::AVX_256bit);//xmm7 = W[16] W[15] W[14] W[13]
+ vpaddq(xmm4, xmm4, xmm7, Assembler::AVX_256bit);//ymm4 = W[4..7] + S0(W[5..8]) + W[13..16]
+ sha512msg2(xmm4, xmm3);//ymm4 += S1(W[14..17])
+ sha512rnds2(xmm12, xmm11, xmm0);
+ vperm2i128(xmm0, xmm0, xmm0, 0x01);
+ sha512rnds2(xmm11, xmm12, xmm0);
+ sha512msg1(xmm6, xmm3); //ymm6 = W[12..15] + S0(W[13..16])
+ i += 1;
+ //R20 - R23, R36 - R39, R52 - R55
+ vpaddq(xmm0, xmm4, Address(rax, i * 32), Assembler::AVX_256bit);
+ vpermq(xmm8, xmm4, 0x1b, Assembler::AVX_256bit);//ymm8 = W[20] W[21] W[22] W[23]
+ vpermq(xmm9, xmm3, 0x39, Assembler::AVX_256bit);//ymm9 = W[16] W[19] W[18] W[17]
+ vpblendd(xmm7, xmm8, xmm9, 0x3f, Assembler::AVX_256bit);//ymm7 = W[20] W[19] W[18] W[17]
+ vpaddq(xmm5, xmm5, xmm7, Assembler::AVX_256bit);//ymm5 = W[8..11] + S0(W[9..12]) + W[17..20]
+ sha512msg2(xmm5, xmm4);//ymm5 += S1(W[18..21])
+ sha512rnds2(xmm12, xmm11, xmm0);
+ vperm2i128(xmm0, xmm0, xmm0, 0x01);
+ sha512rnds2(xmm11, xmm12, xmm0);
+ sha512msg1(xmm3, xmm4); //ymm3 = W[16..19] + S0(W[17..20])
+ i += 1;
+ //R24 - R27, R40 - R43, R56 - R59
+ vpaddq(xmm0, xmm5, Address(rax, i * 32), Assembler::AVX_256bit);
+ vpermq(xmm8, xmm5, 0x1b, Assembler::AVX_256bit);//ymm8 = W[24] W[25] W[26] W[27]
+ vpermq(xmm9, xmm4, 0x39, Assembler::AVX_256bit);//ymm9 = W[20] W[23] W[22] W[21]
+ vpblendd(xmm7, xmm8, xmm9, 0x3f, Assembler::AVX_256bit);//ymm7 = W[24] W[23] W[22] W[21]
+ vpaddq(xmm6, xmm6, xmm7, Assembler::AVX_256bit);//ymm6 = W[12..15] + S0(W[13..16]) + W[21..24]
+ sha512msg2(xmm6, xmm5);//ymm6 += S1(W[22..25])
+ sha512rnds2(xmm12, xmm11, xmm0);
+ vperm2i128(xmm0, xmm0, xmm0, 0x01);
+ sha512rnds2(xmm11, xmm12, xmm0);
+ sha512msg1(xmm4, xmm5);//ymm4 = W[20..23] + S0(W[21..24])
+ i += 1;
+ //R28 - R31, R44 - R47, R60 - R63
+ vpaddq(xmm0, xmm6, Address(rax, i * 32), Assembler::AVX_256bit);
+ vpermq(xmm8, xmm6, 0x1b, Assembler::AVX_256bit);//ymm8 = W[28] W[29] W[30] W[31]
+ vpermq(xmm9, xmm5, 0x39, Assembler::AVX_256bit);//ymm9 = W[24] W[27] W[26] W[25]
+ vpblendd(xmm7, xmm8, xmm9, 0x3f, Assembler::AVX_256bit);//ymm7 = W[28] W[27] W[26] W[25]
+ vpaddq(xmm3, xmm3, xmm7, Assembler::AVX_256bit);//ymm3 = W[16..19] + S0(W[17..20]) + W[25..28]
+ sha512msg2(xmm3, xmm6); //ymm3 += S1(W[26..29])
+ sha512rnds2(xmm12, xmm11, xmm0);
+ vperm2i128(xmm0, xmm0, xmm0, 0x01);
+ sha512rnds2(xmm11, xmm12, xmm0);
+ sha512msg1(xmm5, xmm6);//ymm5 = W[24..27] + S0(W[25..28])
+ i += 1;
+ }
+ //R64 - R67
+ vpaddq(xmm0, xmm3, Address(rax, 16 * 32), Assembler::AVX_256bit);
+ vpermq(xmm8, xmm3, 0x1b, Assembler::AVX_256bit);//ymm8 = W[64] W[65] W[66] W[67]
+ vpermq(xmm9, xmm6, 0x39, Assembler::AVX_256bit);//ymm9 = W[60] W[63] W[62] W[61]
+ vpblendd(xmm7, xmm8, xmm9, 0x3f, Assembler::AVX_256bit);//ymm7 = W[64] W[63] W[62] W[61]
+ vpaddq(xmm4, xmm4, xmm7, Assembler::AVX_256bit);//ymm4 = W[52..55] + S0(W[53..56]) + W[61..64]
+ sha512msg2(xmm4, xmm3);//ymm4 += S1(W[62..65])
+ sha512rnds2(xmm12, xmm11, xmm0);
+ vperm2i128(xmm0, xmm0, xmm0, 0x01);
+ sha512rnds2(xmm11, xmm12, xmm0);
+ sha512msg1(xmm6, xmm3);//ymm6 = W[60..63] + S0(W[61..64])
+
+ //R68 - R71
+ vpaddq(xmm0, xmm4, Address(rax, 17 * 32), Assembler::AVX_256bit);
+ vpermq(xmm8, xmm4, 0x1b, Assembler::AVX_256bit);//ymm8 = W[68] W[69] W[70] W[71]
+ vpermq(xmm9, xmm3, 0x39, Assembler::AVX_256bit);//ymm9 = W[64] W[67] W[66] W[65]
+ vpblendd(xmm7, xmm8, xmm9, 0x3f, Assembler::AVX_256bit);//ymm7 = W[68] W[67] W[66] W[65]
+ vpaddq(xmm5, xmm5, xmm7, Assembler::AVX_256bit);//ymm5 = W[56..59] + S0(W[57..60]) + W[65..68]
+ sha512msg2(xmm5, xmm4);//ymm5 += S1(W[66..69])
+ sha512rnds2(xmm12, xmm11, xmm0);
+ vperm2i128(xmm0, xmm0, xmm0, 0x01);
+ sha512rnds2(xmm11, xmm12, xmm0);
+
+ //R72 - R75
+ vpaddq(xmm0, xmm5, Address(rax, 18 * 32), Assembler::AVX_256bit);
+ vpermq(xmm8, xmm5, 0x1b, Assembler::AVX_256bit);//ymm8 = W[72] W[73] W[74] W[75]
+ vpermq(xmm9, xmm4, 0x39, Assembler::AVX_256bit);//ymm9 = W[68] W[71] W[70] W[69]
+ vpblendd(xmm7, xmm8, xmm9, 0x3f, Assembler::AVX_256bit);//ymm7 = W[72] W[71] W[70] W[69]
+ vpaddq(xmm6, xmm6, xmm7, Assembler::AVX_256bit);//ymm6 = W[60..63] + S0(W[61..64]) + W[69..72]
+ sha512msg2(xmm6, xmm5);//ymm6 += S1(W[70..73])
+ sha512rnds2(xmm12, xmm11, xmm0);
+ vperm2i128(xmm0, xmm0, xmm0, 0x01);
+ sha512rnds2(xmm11, xmm12, xmm0);
+
+ //R76 - R79
+ vpaddq(xmm0, xmm6, Address(rax, 19 * 32), Assembler::AVX_256bit);
+ sha512rnds2(xmm12, xmm11, xmm0);
+ vperm2i128(xmm0, xmm0, xmm0, 0x01);
+ sha512rnds2(xmm11, xmm12, xmm0);
+
+ //update hash value
+ vpaddq(xmm14, xmm14, xmm12, Assembler::AVX_256bit);
+ vpaddq(xmm13, xmm13, xmm11, Assembler::AVX_256bit);
+
+ if (multi_block) {
+ addptr(arg_msg, 4 * 32);
+ addptr(ofs, 128);
+ cmpptr(ofs, limit);
+ jcc(Assembler::belowEqual, block_loop);
+ movptr(rax, ofs); //return ofs
+ }
+
+ //store the hash value back in memory
+ //xmm13 = ABEF
+ //xmm14 = CDGH
+ vperm2i128(xmm1, xmm13, xmm14, 0x31);
+ vperm2i128(xmm2, xmm13, xmm14, 0x20);
+ vpermq(xmm1, xmm1, 0xb1, Assembler::AVX_256bit);//ymm1 = D C B A
+ vpermq(xmm2, xmm2, 0xb1, Assembler::AVX_256bit);//ymm2 = H G F E
+ vmovdqu(Address(arg_hash, 0 * 32), xmm1);
+ vmovdqu(Address(arg_hash, 1 * 32), xmm2);
+
+ bind(done_hash);
+}
+
#endif //#ifdef _LP64
diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp
index de897d71fac..fd738b7333e 100644
--- a/src/hotspot/cpu/x86/methodHandles_x86.cpp
+++ b/src/hotspot/cpu/x86/methodHandles_x86.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
@@ -159,7 +159,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth
__ jmp(Address(method, entry_offset));
__ bind(L_no_such_method);
- __ jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry()));
+ __ jump(RuntimeAddress(SharedRuntime::throw_AbstractMethodError_entry()));
}
void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm,
@@ -510,7 +510,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
if (iid == vmIntrinsics::_linkToInterface) {
__ bind(L_incompatible_class_change_error);
- __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
+ __ jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry()));
}
}
}
@@ -572,7 +572,7 @@ void trace_method_handle_stub(const char* adaptername,
frame cur_frame = os::current_frame();
- if (cur_frame.fp() != 0) { // not walkable
+ if (cur_frame.fp() != nullptr) { // not walkable
// Robust search of trace_calling_frame (independent of inlining).
// Assumes saved_regs comes from a pusha in the trace_calling_frame.
diff --git a/src/hotspot/cpu/x86/nativeInst_x86.cpp b/src/hotspot/cpu/x86/nativeInst_x86.cpp
index 395c3219809..d5021c29ed6 100644
--- a/src/hotspot/cpu/x86/nativeInst_x86.cpp
+++ b/src/hotspot/cpu/x86/nativeInst_x86.cpp
@@ -81,7 +81,7 @@ void NativeCall::insert(address code_pos, address entry) {
// (spinlock). Then patches the last byte, and then atomically replaces
// the jmp's with the first 4 byte of the new instruction.
void NativeCall::replace_mt_safe(address instr_addr, address code_buffer) {
- assert(Patching_lock->is_locked() ||
+ assert(CodeCache_lock->is_locked() ||
SafepointSynchronize::is_at_safepoint(), "concurrent code patching");
assert (instr_addr != nullptr, "illegal address for code patching");
@@ -144,7 +144,7 @@ void NativeCall::set_destination_mt_safe(address dest) {
debug_only(verify());
// Make sure patching code is locked. No two threads can patch at the same
// time but one may be executing this code.
- assert(Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint() ||
+ assert(CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint() ||
CompiledICLocker::is_safe(instruction_address()), "concurrent code patching");
// Both C1 and C2 should now be generating code which aligns the patched address
// to be within a single cache line.
diff --git a/src/hotspot/cpu/x86/runtime_x86_32.cpp b/src/hotspot/cpu/x86/runtime_x86_32.cpp
index d38fa3c60bd..2a21c42a5e6 100644
--- a/src/hotspot/cpu/x86/runtime_x86_32.cpp
+++ b/src/hotspot/cpu/x86/runtime_x86_32.cpp
@@ -41,6 +41,180 @@
#define __ masm->
+//------------------------------generate_uncommon_trap_blob--------------------
+void OptoRuntime::generate_uncommon_trap_blob() {
+ // allocate space for the code
+ ResourceMark rm;
+ // setup code generation tools
+ CodeBuffer buffer("uncommon_trap_blob", 512, 512);
+ MacroAssembler* masm = new MacroAssembler(&buffer);
+
+ enum frame_layout {
+ arg0_off, // thread sp + 0 // Arg location for
+ arg1_off, // unloaded_class_index sp + 1 // calling C
+ arg2_off, // exec_mode sp + 2
+ // The frame sender code expects that rbp will be in the "natural" place and
+ // will override any oopMap setting for it. We must therefore force the layout
+ // so that it agrees with the frame sender code.
+ rbp_off, // callee saved register sp + 3
+ return_off, // slot for return address sp + 4
+ framesize
+ };
+
+ address start = __ pc();
+
+ // Push self-frame.
+ __ subptr(rsp, return_off*wordSize); // Epilog!
+
+ // rbp, is an implicitly saved callee saved register (i.e. the calling
+ // convention will save restore it in prolog/epilog) Other than that
+ // there are no callee save registers no that adapter frames are gone.
+ __ movptr(Address(rsp, rbp_off*wordSize), rbp);
+
+ // Clear the floating point exception stack
+ __ empty_FPU_stack();
+
+ // set last_Java_sp
+ __ get_thread(rdx);
+ __ set_last_Java_frame(rdx, noreg, noreg, nullptr, noreg);
+
+ // Call C code. Need thread but NOT official VM entry
+ // crud. We cannot block on this call, no GC can happen. Call should
+ // capture callee-saved registers as well as return values.
+ __ movptr(Address(rsp, arg0_off*wordSize), rdx);
+ // argument already in ECX
+ __ movl(Address(rsp, arg1_off*wordSize),rcx);
+ __ movl(Address(rsp, arg2_off*wordSize), Deoptimization::Unpack_uncommon_trap);
+ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)));
+
+ // Set an oopmap for the call site
+ OopMapSet *oop_maps = new OopMapSet();
+ OopMap* map = new OopMap( framesize, 0 );
+ // No oopMap for rbp, it is known implicitly
+
+ oop_maps->add_gc_map( __ pc()-start, map);
+
+ __ get_thread(rcx);
+
+ __ reset_last_Java_frame(rcx, false);
+
+ // Load UnrollBlock into EDI
+ __ movptr(rdi, rax);
+
+#ifdef ASSERT
+ { Label L;
+ __ cmpptr(Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset()),
+ (int32_t)Deoptimization::Unpack_uncommon_trap);
+ __ jcc(Assembler::equal, L);
+ __ stop("OptoRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap");
+ __ bind(L);
+ }
+#endif
+
+ // Pop all the frames we must move/replace.
+ //
+ // Frame picture (youngest to oldest)
+ // 1: self-frame (no frame link)
+ // 2: deopting frame (no frame link)
+ // 3: caller of deopting frame (could be compiled/interpreted).
+
+ // Pop self-frame. We have no frame, and must rely only on EAX and ESP.
+ __ addptr(rsp,(framesize-1)*wordSize); // Epilog!
+
+ // Pop deoptimized frame
+ __ movl2ptr(rcx, Address(rdi,Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset()));
+ __ addptr(rsp, rcx);
+
+ // sp should be pointing at the return address to the caller (3)
+
+ // Pick up the initial fp we should save
+ // restore rbp before stack bang because if stack overflow is thrown it needs to be pushed (and preserved)
+ __ movptr(rbp, Address(rdi, Deoptimization::UnrollBlock::initial_info_offset()));
+
+#ifdef ASSERT
+ // Compilers generate code that bang the stack by as much as the
+ // interpreter would need. So this stack banging should never
+ // trigger a fault. Verify that it does not on non product builds.
+ __ movl(rbx, Address(rdi ,Deoptimization::UnrollBlock::total_frame_sizes_offset()));
+ __ bang_stack_size(rbx, rcx);
+#endif
+
+ // Load array of frame pcs into ECX
+ __ movl(rcx,Address(rdi,Deoptimization::UnrollBlock::frame_pcs_offset()));
+
+ __ pop(rsi); // trash the pc
+
+ // Load array of frame sizes into ESI
+ __ movptr(rsi,Address(rdi,Deoptimization::UnrollBlock::frame_sizes_offset()));
+
+ Address counter(rdi, Deoptimization::UnrollBlock::counter_temp_offset());
+
+ __ movl(rbx, Address(rdi, Deoptimization::UnrollBlock::number_of_frames_offset()));
+ __ movl(counter, rbx);
+
+ // Now adjust the caller's stack to make up for the extra locals
+ // but record the original sp so that we can save it in the skeletal interpreter
+ // frame and the stack walking of interpreter_sender will get the unextended sp
+ // value and not the "real" sp value.
+
+ Address sp_temp(rdi, Deoptimization::UnrollBlock::sender_sp_temp_offset());
+ __ movptr(sp_temp, rsp);
+ __ movl(rbx, Address(rdi, Deoptimization::UnrollBlock::caller_adjustment_offset()));
+ __ subptr(rsp, rbx);
+
+ // Push interpreter frames in a loop
+ Label loop;
+ __ bind(loop);
+ __ movptr(rbx, Address(rsi, 0)); // Load frame size
+ __ subptr(rbx, 2*wordSize); // we'll push pc and rbp, by hand
+ __ pushptr(Address(rcx, 0)); // save return address
+ __ enter(); // save old & set new rbp,
+ __ subptr(rsp, rbx); // Prolog!
+ __ movptr(rbx, sp_temp); // sender's sp
+ // This value is corrected by layout_activation_impl
+ __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD );
+ __ movptr(Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize), rbx); // Make it walkable
+ __ movptr(sp_temp, rsp); // pass to next frame
+ __ addptr(rsi, wordSize); // Bump array pointer (sizes)
+ __ addptr(rcx, wordSize); // Bump array pointer (pcs)
+ __ decrementl(counter); // decrement counter
+ __ jcc(Assembler::notZero, loop);
+ __ pushptr(Address(rcx, 0)); // save final return address
+
+ // Re-push self-frame
+ __ enter(); // save old & set new rbp,
+ __ subptr(rsp, (framesize-2) * wordSize); // Prolog!
+
+
+ // set last_Java_sp, last_Java_fp
+ __ get_thread(rdi);
+ __ set_last_Java_frame(rdi, noreg, rbp, nullptr, noreg);
+
+ // Call C code. Need thread but NOT official VM entry
+ // crud. We cannot block on this call, no GC can happen. Call should
+ // restore return values to their stack-slots with the new SP.
+ __ movptr(Address(rsp,arg0_off*wordSize),rdi);
+ __ movl(Address(rsp,arg1_off*wordSize), Deoptimization::Unpack_uncommon_trap);
+ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)));
+ // Set an oopmap for the call site
+ oop_maps->add_gc_map( __ pc()-start, new OopMap( framesize, 0 ) );
+
+ __ get_thread(rdi);
+ __ reset_last_Java_frame(rdi, true);
+
+ // Pop self-frame.
+ __ leave(); // Epilog!
+
+ // Jump to interpreter
+ __ ret(0);
+
+ // -------------
+ // make sure all code is generated
+ masm->flush();
+
+ _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps, framesize);
+}
+
//------------------------------generate_exception_blob---------------------------
// creates exception blob at the end
// Using exception blob, this code is jumped from a compiled method.
diff --git a/src/hotspot/cpu/x86/runtime_x86_64.cpp b/src/hotspot/cpu/x86/runtime_x86_64.cpp
index e08550715b4..eb3bab36b88 100644
--- a/src/hotspot/cpu/x86/runtime_x86_64.cpp
+++ b/src/hotspot/cpu/x86/runtime_x86_64.cpp
@@ -34,11 +34,328 @@
#include "runtime/vframeArray.hpp"
#include "utilities/globalDefinitions.hpp"
#include "vmreg_x86.inline.hpp"
+
+class SimpleRuntimeFrame {
+
+ public:
+
+ // Most of the runtime stubs have this simple frame layout.
+ // This class exists to make the layout shared in one place.
+ // Offsets are for compiler stack slots, which are jints.
+ enum layout {
+ // The frame sender code expects that rbp will be in the "natural" place and
+ // will override any oopMap setting for it. We must therefore force the layout
+ // so that it agrees with the frame sender code.
+ rbp_off = frame::arg_reg_save_area_bytes/BytesPerInt,
+ rbp_off2,
+ return_off, return_off2,
+ framesize
+ };
+};
+
+#define __ masm->
+
+//------------------------------generate_uncommon_trap_blob--------------------
+void OptoRuntime::generate_uncommon_trap_blob() {
+ // Allocate space for the code
+ ResourceMark rm;
+ // Setup code generation tools
+ CodeBuffer buffer("uncommon_trap_blob", 2048, 1024);
+ MacroAssembler* masm = new MacroAssembler(&buffer);
+
+ assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
+
+ address start = __ pc();
+
+ // Push self-frame. We get here with a return address on the
+ // stack, so rsp is 8-byte aligned until we allocate our frame.
+ __ subptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Epilog!
+
+ // No callee saved registers. rbp is assumed implicitly saved
+ __ movptr(Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt), rbp);
+
+ // compiler left unloaded_class_index in j_rarg0 move to where the
+ // runtime expects it.
+ __ movl(c_rarg1, j_rarg0);
+
+ __ set_last_Java_frame(noreg, noreg, nullptr, rscratch1);
+
+ // Call C code. Need thread but NOT official VM entry
+ // crud. We cannot block on this call, no GC can happen. Call should
+ // capture callee-saved registers as well as return values.
+ // Thread is in rdi already.
+ //
+ // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index);
+
+ __ mov(c_rarg0, r15_thread);
+ __ movl(c_rarg2, Deoptimization::Unpack_uncommon_trap);
+ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)));
+
+ // Set an oopmap for the call site
+ OopMapSet* oop_maps = new OopMapSet();
+ OopMap* map = new OopMap(SimpleRuntimeFrame::framesize, 0);
+
+ // location of rbp is known implicitly by the frame sender code
+
+ oop_maps->add_gc_map(__ pc() - start, map);
+
+ __ reset_last_Java_frame(false);
+
+ // Load UnrollBlock* into rdi
+ __ mov(rdi, rax);
+
+#ifdef ASSERT
+ { Label L;
+ __ cmpptr(Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset()),
+ Deoptimization::Unpack_uncommon_trap);
+ __ jcc(Assembler::equal, L);
+ __ stop("OptoRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap");
+ __ bind(L);
+ }
#endif
+ // Pop all the frames we must move/replace.
+ //
+ // Frame picture (youngest to oldest)
+ // 1: self-frame (no frame link)
+ // 2: deopting frame (no frame link)
+ // 3: caller of deopting frame (could be compiled/interpreted).
+
+ // Pop self-frame. We have no frame, and must rely only on rax and rsp.
+ __ addptr(rsp, (SimpleRuntimeFrame::framesize - 2) << LogBytesPerInt); // Epilog!
+
+ // Pop deoptimized frame (int)
+ __ movl(rcx, Address(rdi,
+ Deoptimization::UnrollBlock::
+ size_of_deoptimized_frame_offset()));
+ __ addptr(rsp, rcx);
+
+ // rsp should be pointing at the return address to the caller (3)
+
+ // Pick up the initial fp we should save
+ // restore rbp before stack bang because if stack overflow is thrown it needs to be pushed (and preserved)
+ __ movptr(rbp, Address(rdi, Deoptimization::UnrollBlock::initial_info_offset()));
+
+#ifdef ASSERT
+ // Compilers generate code that bang the stack by as much as the
+ // interpreter would need. So this stack banging should never
+ // trigger a fault. Verify that it does not on non product builds.
+ __ movl(rbx, Address(rdi ,Deoptimization::UnrollBlock::total_frame_sizes_offset()));
+ __ bang_stack_size(rbx, rcx);
+#endif
+
+ // Load address of array of frame pcs into rcx (address*)
+ __ movptr(rcx, Address(rdi, Deoptimization::UnrollBlock::frame_pcs_offset()));
+
+ // Trash the return pc
+ __ addptr(rsp, wordSize);
+
+ // Load address of array of frame sizes into rsi (intptr_t*)
+ __ movptr(rsi, Address(rdi, Deoptimization::UnrollBlock:: frame_sizes_offset()));
+
+ // Counter
+ __ movl(rdx, Address(rdi, Deoptimization::UnrollBlock:: number_of_frames_offset())); // (int)
+
+ // Now adjust the caller's stack to make up for the extra locals but
+ // record the original sp so that we can save it in the skeletal
+ // interpreter frame and the stack walking of interpreter_sender
+ // will get the unextended sp value and not the "real" sp value.
+
+ const Register sender_sp = r8;
+
+ __ mov(sender_sp, rsp);
+ __ movl(rbx, Address(rdi, Deoptimization::UnrollBlock:: caller_adjustment_offset())); // (int)
+ __ subptr(rsp, rbx);
+
+ // Push interpreter frames in a loop
+ Label loop;
+ __ bind(loop);
+ __ movptr(rbx, Address(rsi, 0)); // Load frame size
+ __ subptr(rbx, 2 * wordSize); // We'll push pc and rbp by hand
+ __ pushptr(Address(rcx, 0)); // Save return address
+ __ enter(); // Save old & set new rbp
+ __ subptr(rsp, rbx); // Prolog
+ __ movptr(Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize),
+ sender_sp); // Make it walkable
+ // This value is corrected by layout_activation_impl
+ __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD);
+ __ mov(sender_sp, rsp); // Pass sender_sp to next frame
+ __ addptr(rsi, wordSize); // Bump array pointer (sizes)
+ __ addptr(rcx, wordSize); // Bump array pointer (pcs)
+ __ decrementl(rdx); // Decrement counter
+ __ jcc(Assembler::notZero, loop);
+ __ pushptr(Address(rcx, 0)); // Save final return address
+
+ // Re-push self-frame
+ __ enter(); // Save old & set new rbp
+ __ subptr(rsp, (SimpleRuntimeFrame::framesize - 4) << LogBytesPerInt);
+ // Prolog
+
+ // Use rbp because the frames look interpreted now
+ // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP.
+ // Don't need the precise return PC here, just precise enough to point into this code blob.
+ address the_pc = __ pc();
+ __ set_last_Java_frame(noreg, rbp, the_pc, rscratch1);
+
+ // Call C code. Need thread but NOT official VM entry
+ // crud. We cannot block on this call, no GC can happen. Call should
+ // restore return values to their stack-slots with the new SP.
+ // Thread is in rdi already.
+ //
+ // BasicType unpack_frames(JavaThread* thread, int exec_mode);
+
+ __ andptr(rsp, -(StackAlignmentInBytes)); // Align SP as required by ABI
+ __ mov(c_rarg0, r15_thread);
+ __ movl(c_rarg1, Deoptimization::Unpack_uncommon_trap);
+ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)));
+
+ // Set an oopmap for the call site
+ // Use the same PC we used for the last java frame
+ oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0));
+
+ // Clear fp AND pc
+ __ reset_last_Java_frame(true);
+
+ // Pop self-frame.
+ __ leave(); // Epilog
+
+ // Jump to interpreter
+ __ ret(0);
+
+ // Make sure all code is generated
+ masm->flush();
+
+ _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps,
+ SimpleRuntimeFrame::framesize >> 1);
+}
+
+//------------------------------generate_exception_blob---------------------------
+// creates exception blob at the end
+// Using exception blob, this code is jumped from a compiled method.
+// (see emit_exception_handler in x86_64.ad file)
+//
+// Given an exception pc at a call we call into the runtime for the
+// handler in this method. This handler might merely restore state
+// (i.e. callee save registers) unwind the frame and jump to the
+// exception handler for the nmethod if there is no Java level handler
+// for the nmethod.
+//
+// This code is entered with a jmp.
+//
+// Arguments:
+// rax: exception oop
+// rdx: exception pc
+//
+// Results:
+// rax: exception oop
+// rdx: exception pc in caller or ???
+// destination: exception handler of caller
+//
+// Note: the exception pc MUST be at a call (precise debug information)
+// Registers rax, rdx, rcx, rsi, rdi, r8-r11 are not callee saved.
+//
+
+void OptoRuntime::generate_exception_blob() {
+ assert(!OptoRuntime::is_callee_saved_register(RDX_num), "");
+ assert(!OptoRuntime::is_callee_saved_register(RAX_num), "");
+ assert(!OptoRuntime::is_callee_saved_register(RCX_num), "");
+
+ assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
+
+ // Allocate space for the code
+ ResourceMark rm;
+ // Setup code generation tools
+ CodeBuffer buffer("exception_blob", 2048, 1024);
+ MacroAssembler* masm = new MacroAssembler(&buffer);
+
+
+ address start = __ pc();
+
+ // Exception pc is 'return address' for stack walker
+ __ push(rdx);
+ __ subptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Prolog
+
+ // Save callee-saved registers. See x86_64.ad.
+
+ // rbp is an implicitly saved callee saved register (i.e., the calling
+ // convention will save/restore it in the prolog/epilog). Other than that
+ // there are no callee save registers now that adapter frames are gone.
+
+ __ movptr(Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt), rbp);
+
+ // Store exception in Thread object. We cannot pass any arguments to the
+ // handle_exception call, since we do not want to make any assumption
+ // about the size of the frame where the exception happened in.
+ // c_rarg0 is either rdi (Linux) or rcx (Windows).
+ __ movptr(Address(r15_thread, JavaThread::exception_oop_offset()),rax);
+ __ movptr(Address(r15_thread, JavaThread::exception_pc_offset()), rdx);
+
+ // This call does all the hard work. It checks if an exception handler
+ // exists in the method.
+ // If so, it returns the handler address.
+ // If not, it prepares for stack-unwinding, restoring the callee-save
+ // registers of the frame being removed.
+ //
+ // address OptoRuntime::handle_exception_C(JavaThread* thread)
+
+ // At a method handle call, the stack may not be properly aligned
+ // when returning with an exception.
+ address the_pc = __ pc();
+ __ set_last_Java_frame(noreg, noreg, the_pc, rscratch1);
+ __ mov(c_rarg0, r15_thread);
+ __ andptr(rsp, -(StackAlignmentInBytes)); // Align stack
+ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C)));
+
+ // Set an oopmap for the call site. This oopmap will only be used if we
+ // are unwinding the stack. Hence, all locations will be dead.
+ // Callee-saved registers will be the same as the frame above (i.e.,
+ // handle_exception_stub), since they were restored when we got the
+ // exception.
+
+ OopMapSet* oop_maps = new OopMapSet();
+
+ oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0));
+
+ __ reset_last_Java_frame(false);
+
+ // Restore callee-saved registers
+
+ // rbp is an implicitly saved callee-saved register (i.e., the calling
+ // convention will save restore it in prolog/epilog) Other than that
+ // there are no callee save registers now that adapter frames are gone.
+
+ __ movptr(rbp, Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt));
+
+ __ addptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Epilog
+ __ pop(rdx); // No need for exception pc anymore
+
+ // rax: exception handler
+
+ // We have a handler in rax (could be deopt blob).
+ __ mov(r8, rax);
+
+ // Get the exception oop
+ __ movptr(rax, Address(r15_thread, JavaThread::exception_oop_offset()));
+ // Get the exception pc in case we are deoptimized
+ __ movptr(rdx, Address(r15_thread, JavaThread::exception_pc_offset()));
+#ifdef ASSERT
+ __ movptr(Address(r15_thread, JavaThread::exception_handler_pc_offset()), NULL_WORD);
+ __ movptr(Address(r15_thread, JavaThread::exception_pc_offset()), NULL_WORD);
+#endif
+ // Clear the exception oop so GC no longer processes it as a root.
+ __ movptr(Address(r15_thread, JavaThread::exception_oop_offset()), NULL_WORD);
+
+ // rax: exception oop
+ // r8: exception handler
+ // rdx: exception pc
+ // Jump to handler
+
+ __ jmp(r8);
+
+ // Make sure all code is generated
+ masm->flush();
-// This file should really contain the code for generating the OptoRuntime
-// exception_blob. However that code uses SimpleRuntimeFrame which only
-// exists in sharedRuntime_x86_64.cpp. When there is a sharedRuntime_.hpp
-// file and SimpleRuntimeFrame is able to move there then the exception_blob
-// code will move here where it belongs.
+ // Set exception blob
+ _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1);
+}
+#endif // COMPILER2
diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp
index 3ecbb43f7f5..78330962d1a 100644
--- a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp
@@ -62,9 +62,11 @@ void SharedRuntime::inline_check_hashcode_from_object_header(MacroAssembler* mas
if (LockingMode == LM_LIGHTWEIGHT) {
- // check if monitor
- __ testptr(result, markWord::monitor_value);
- __ jcc(Assembler::notZero, slowCase);
+ if (!UseObjectMonitorTable) {
+ // check if monitor
+ __ testptr(result, markWord::monitor_value);
+ __ jcc(Assembler::notZero, slowCase);
+ }
} else {
// check if locked
__ testptr(result, markWord::unlocked_value);
diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp
index 6303c279195..c6ab00cc9ee 100644
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp
@@ -43,6 +43,7 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/signature.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/timerTrace.hpp"
#include "runtime/vframeArray.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/align.hpp"
@@ -56,6 +57,12 @@
#define __ masm->
+#ifdef PRODUCT
+#define BLOCK_COMMENT(str) /* nothing */
+#else
+#define BLOCK_COMMENT(str) __ block_comment(str)
+#endif // PRODUCT
+
const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size;
class RegisterSaver {
@@ -704,10 +711,10 @@ static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg
address code_start, address code_end,
Label& L_ok) {
Label L_fail;
- __ lea(temp_reg, ExternalAddress(code_start));
+ __ lea(temp_reg, AddressLiteral(code_start, relocInfo::none));
__ cmpptr(pc_reg, temp_reg);
__ jcc(Assembler::belowEqual, L_fail);
- __ lea(temp_reg, ExternalAddress(code_end));
+ __ lea(temp_reg, AddressLiteral(code_end, relocInfo::none));
__ cmpptr(pc_reg, temp_reg);
__ jcc(Assembler::below, L_ok);
__ bind(L_fail);
@@ -1686,7 +1693,8 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
__ jcc(Assembler::notEqual, slow_path_lock);
} else {
assert(LockingMode == LM_LIGHTWEIGHT, "must be");
- __ lightweight_lock(obj_reg, swap_reg, thread, lock_reg, slow_path_lock);
+ // Lacking registers and thread on x86_32. Always take slow path.
+ __ jmp(slow_path_lock);
}
__ bind(count_mon);
__ inc_held_monitor_count();
@@ -2054,7 +2062,8 @@ void SharedRuntime::generate_deopt_blob() {
ResourceMark rm;
// setup code generation tools
// note: the buffer code size must account for StackShadowPages=50
- CodeBuffer buffer("deopt_blob", 1536, 1024);
+ const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id);
+ CodeBuffer buffer(name, 1536, 1024);
MacroAssembler* masm = new MacroAssembler(&buffer);
int frame_size_in_words;
OopMap* map = nullptr;
@@ -2389,196 +2398,20 @@ void SharedRuntime::generate_deopt_blob() {
_deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
}
-
-#ifdef COMPILER2
-//------------------------------generate_uncommon_trap_blob--------------------
-void SharedRuntime::generate_uncommon_trap_blob() {
- // allocate space for the code
- ResourceMark rm;
- // setup code generation tools
- CodeBuffer buffer("uncommon_trap_blob", 512, 512);
- MacroAssembler* masm = new MacroAssembler(&buffer);
-
- enum frame_layout {
- arg0_off, // thread sp + 0 // Arg location for
- arg1_off, // unloaded_class_index sp + 1 // calling C
- arg2_off, // exec_mode sp + 2
- // The frame sender code expects that rbp will be in the "natural" place and
- // will override any oopMap setting for it. We must therefore force the layout
- // so that it agrees with the frame sender code.
- rbp_off, // callee saved register sp + 3
- return_off, // slot for return address sp + 4
- framesize
- };
-
- address start = __ pc();
-
- // Push self-frame.
- __ subptr(rsp, return_off*wordSize); // Epilog!
-
- // rbp, is an implicitly saved callee saved register (i.e. the calling
- // convention will save restore it in prolog/epilog) Other than that
- // there are no callee save registers no that adapter frames are gone.
- __ movptr(Address(rsp, rbp_off*wordSize), rbp);
-
- // Clear the floating point exception stack
- __ empty_FPU_stack();
-
- // set last_Java_sp
- __ get_thread(rdx);
- __ set_last_Java_frame(rdx, noreg, noreg, nullptr, noreg);
-
- // Call C code. Need thread but NOT official VM entry
- // crud. We cannot block on this call, no GC can happen. Call should
- // capture callee-saved registers as well as return values.
- __ movptr(Address(rsp, arg0_off*wordSize), rdx);
- // argument already in ECX
- __ movl(Address(rsp, arg1_off*wordSize),rcx);
- __ movl(Address(rsp, arg2_off*wordSize), Deoptimization::Unpack_uncommon_trap);
- __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)));
-
- // Set an oopmap for the call site
- OopMapSet *oop_maps = new OopMapSet();
- OopMap* map = new OopMap( framesize, 0 );
- // No oopMap for rbp, it is known implicitly
-
- oop_maps->add_gc_map( __ pc()-start, map);
-
- __ get_thread(rcx);
-
- __ reset_last_Java_frame(rcx, false);
-
- // Load UnrollBlock into EDI
- __ movptr(rdi, rax);
-
-#ifdef ASSERT
- { Label L;
- __ cmpptr(Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset()),
- (int32_t)Deoptimization::Unpack_uncommon_trap);
- __ jcc(Assembler::equal, L);
- __ stop("SharedRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap");
- __ bind(L);
- }
-#endif
-
- // Pop all the frames we must move/replace.
- //
- // Frame picture (youngest to oldest)
- // 1: self-frame (no frame link)
- // 2: deopting frame (no frame link)
- // 3: caller of deopting frame (could be compiled/interpreted).
-
- // Pop self-frame. We have no frame, and must rely only on EAX and ESP.
- __ addptr(rsp,(framesize-1)*wordSize); // Epilog!
-
- // Pop deoptimized frame
- __ movl2ptr(rcx, Address(rdi,Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset()));
- __ addptr(rsp, rcx);
-
- // sp should be pointing at the return address to the caller (3)
-
- // Pick up the initial fp we should save
- // restore rbp before stack bang because if stack overflow is thrown it needs to be pushed (and preserved)
- __ movptr(rbp, Address(rdi, Deoptimization::UnrollBlock::initial_info_offset()));
-
-#ifdef ASSERT
- // Compilers generate code that bang the stack by as much as the
- // interpreter would need. So this stack banging should never
- // trigger a fault. Verify that it does not on non product builds.
- __ movl(rbx, Address(rdi ,Deoptimization::UnrollBlock::total_frame_sizes_offset()));
- __ bang_stack_size(rbx, rcx);
-#endif
-
- // Load array of frame pcs into ECX
- __ movl(rcx,Address(rdi,Deoptimization::UnrollBlock::frame_pcs_offset()));
-
- __ pop(rsi); // trash the pc
-
- // Load array of frame sizes into ESI
- __ movptr(rsi,Address(rdi,Deoptimization::UnrollBlock::frame_sizes_offset()));
-
- Address counter(rdi, Deoptimization::UnrollBlock::counter_temp_offset());
-
- __ movl(rbx, Address(rdi, Deoptimization::UnrollBlock::number_of_frames_offset()));
- __ movl(counter, rbx);
-
- // Now adjust the caller's stack to make up for the extra locals
- // but record the original sp so that we can save it in the skeletal interpreter
- // frame and the stack walking of interpreter_sender will get the unextended sp
- // value and not the "real" sp value.
-
- Address sp_temp(rdi, Deoptimization::UnrollBlock::sender_sp_temp_offset());
- __ movptr(sp_temp, rsp);
- __ movl(rbx, Address(rdi, Deoptimization::UnrollBlock::caller_adjustment_offset()));
- __ subptr(rsp, rbx);
-
- // Push interpreter frames in a loop
- Label loop;
- __ bind(loop);
- __ movptr(rbx, Address(rsi, 0)); // Load frame size
- __ subptr(rbx, 2*wordSize); // we'll push pc and rbp, by hand
- __ pushptr(Address(rcx, 0)); // save return address
- __ enter(); // save old & set new rbp,
- __ subptr(rsp, rbx); // Prolog!
- __ movptr(rbx, sp_temp); // sender's sp
- // This value is corrected by layout_activation_impl
- __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD );
- __ movptr(Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize), rbx); // Make it walkable
- __ movptr(sp_temp, rsp); // pass to next frame
- __ addptr(rsi, wordSize); // Bump array pointer (sizes)
- __ addptr(rcx, wordSize); // Bump array pointer (pcs)
- __ decrementl(counter); // decrement counter
- __ jcc(Assembler::notZero, loop);
- __ pushptr(Address(rcx, 0)); // save final return address
-
- // Re-push self-frame
- __ enter(); // save old & set new rbp,
- __ subptr(rsp, (framesize-2) * wordSize); // Prolog!
-
-
- // set last_Java_sp, last_Java_fp
- __ get_thread(rdi);
- __ set_last_Java_frame(rdi, noreg, rbp, nullptr, noreg);
-
- // Call C code. Need thread but NOT official VM entry
- // crud. We cannot block on this call, no GC can happen. Call should
- // restore return values to their stack-slots with the new SP.
- __ movptr(Address(rsp,arg0_off*wordSize),rdi);
- __ movl(Address(rsp,arg1_off*wordSize), Deoptimization::Unpack_uncommon_trap);
- __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)));
- // Set an oopmap for the call site
- oop_maps->add_gc_map( __ pc()-start, new OopMap( framesize, 0 ) );
-
- __ get_thread(rdi);
- __ reset_last_Java_frame(rdi, true);
-
- // Pop self-frame.
- __ leave(); // Epilog!
-
- // Jump to interpreter
- __ ret(0);
-
- // -------------
- // make sure all code is generated
- masm->flush();
-
- _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps, framesize);
-}
-#endif // COMPILER2
-
//------------------------------generate_handler_blob------
//
// Generate a special Compile2Runtime blob that saves all registers,
// setup oopmap, and calls safepoint code to stop the compiled code for
// a safepoint.
//
-SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) {
+SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) {
// Account for thread arg in our frame
const int additional_words = 1;
int frame_size_in_words;
assert (StubRoutines::forward_exception_entry() != nullptr, "must be generated before");
+ assert(is_polling_page_id(id), "expected a polling page stub id");
ResourceMark rm;
OopMapSet *oop_maps = new OopMapSet();
@@ -2586,14 +2419,15 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
// allocate space for the code
// setup code generation tools
- CodeBuffer buffer("handler_blob", 2048, 1024);
+ const char* name = SharedRuntime::stub_name(id);
+ CodeBuffer buffer(name, 2048, 1024);
MacroAssembler* masm = new MacroAssembler(&buffer);
const Register java_thread = rdi; // callee-saved for VC++
address start = __ pc();
address call_pc = nullptr;
- bool cause_return = (poll_type == POLL_AT_RETURN);
- bool save_vectors = (poll_type == POLL_AT_VECTOR_LOOP);
+ bool cause_return = (id == SharedStubId::polling_page_return_handler_id);
+ bool save_vectors = (id == SharedStubId::polling_page_vectors_safepoint_handler_id);
// If cause_return is true we are at a poll_return and there is
// the return address on the stack to the caller on the nmethod
@@ -2725,12 +2559,14 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
// but since this is generic code we don't know what they are and the caller
// must do any gc of the args.
//
-RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) {
+RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) {
assert (StubRoutines::forward_exception_entry() != nullptr, "must be generated before");
+ assert(is_resolve_id(id), "expected a resolve stub id");
// allocate space for the code
ResourceMark rm;
+ const char* name = SharedRuntime::stub_name(id);
CodeBuffer buffer(name, 1000, 512);
MacroAssembler* masm = new MacroAssembler(&buffer);
@@ -2807,3 +2643,212 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha
// frame_size_words or bytes??
return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true);
}
+
+ //------------------------------------------------------------------------------------------------------------------------
+ // Continuation point for throwing of implicit exceptions that are not handled in
+ // the current activation. Fabricates an exception oop and initiates normal
+ // exception dispatching in this frame.
+ //
+ // Previously the compiler (c2) allowed for callee save registers on Java calls.
+ // This is no longer true after adapter frames were removed but could possibly
+ // be brought back in the future if the interpreter code was reworked and it
+ // was deemed worthwhile. The comment below was left to describe what must
+ // happen here if callee saves were resurrected. As it stands now this stub
+ // could actually be a vanilla BufferBlob and have now oopMap at all.
+ // Since it doesn't make much difference we've chosen to leave it the
+ // way it was in the callee save days and keep the comment.
+
+ // If we need to preserve callee-saved values we need a callee-saved oop map and
+ // therefore have to make these stubs into RuntimeStubs rather than BufferBlobs.
+ // If the compiler needs all registers to be preserved between the fault
+ // point and the exception handler then it must assume responsibility for that in
+ // AbstractCompiler::continuation_for_implicit_null_exception or
+ // continuation_for_implicit_division_by_zero_exception. All other implicit
+ // exceptions (e.g., NullPointerException or AbstractMethodError on entry) are
+ // either at call sites or otherwise assume that stack unwinding will be initiated,
+ // so caller saved registers were assumed volatile in the compiler.
+RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) {
+ assert(is_throw_id(id), "expected a throw stub id");
+
+ const char* name = SharedRuntime::stub_name(id);
+
+ // Information about frame layout at time of blocking runtime call.
+ // Note that we only have to preserve callee-saved registers since
+ // the compilers are responsible for supplying a continuation point
+ // if they expect all registers to be preserved.
+ enum layout {
+ thread_off, // last_java_sp
+ arg1_off,
+ arg2_off,
+ rbp_off, // callee saved register
+ ret_pc,
+ framesize
+ };
+
+ int insts_size = 256;
+ int locs_size = 32;
+
+ ResourceMark rm;
+ const char* timer_msg = "SharedRuntime generate_throw_exception";
+ TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime));
+
+ CodeBuffer code(name, insts_size, locs_size);
+ OopMapSet* oop_maps = new OopMapSet();
+ MacroAssembler* masm = new MacroAssembler(&code);
+
+ address start = __ pc();
+
+ // This is an inlined and slightly modified version of call_VM
+ // which has the ability to fetch the return PC out of
+ // thread-local storage and also sets up last_Java_sp slightly
+ // differently than the real call_VM
+ Register java_thread = rbx;
+ __ get_thread(java_thread);
+
+ __ enter(); // required for proper stackwalking of RuntimeStub frame
+
+ // pc and rbp, already pushed
+ __ subptr(rsp, (framesize-2) * wordSize); // prolog
+
+ // Frame is now completed as far as size and linkage.
+
+ int frame_complete = __ pc() - start;
+
+ // push java thread (becomes first argument of C function)
+ __ movptr(Address(rsp, thread_off * wordSize), java_thread);
+ // Set up last_Java_sp and last_Java_fp
+ __ set_last_Java_frame(java_thread, rsp, rbp, nullptr, noreg);
+
+ // Call runtime
+ BLOCK_COMMENT("call runtime_entry");
+ __ call(RuntimeAddress(runtime_entry));
+ // Generate oop map
+ OopMap* map = new OopMap(framesize, 0);
+ oop_maps->add_gc_map(__ pc() - start, map);
+
+ // restore the thread (cannot use the pushed argument since arguments
+ // may be overwritten by C code generated by an optimizing compiler);
+ // however can use the register value directly if it is callee saved.
+ __ get_thread(java_thread);
+
+ __ reset_last_Java_frame(java_thread, true);
+
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+
+ // check for pending exceptions
+#ifdef ASSERT
+ Label L;
+ __ cmpptr(Address(java_thread, Thread::pending_exception_offset()), NULL_WORD);
+ __ jcc(Assembler::notEqual, L);
+ __ should_not_reach_here();
+ __ bind(L);
+#endif /* ASSERT */
+ __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
+
+
+ RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, framesize, oop_maps, false);
+ return stub;
+}
+
+#if INCLUDE_JFR
+
+static void jfr_prologue(address the_pc, MacroAssembler* masm) {
+ Register java_thread = rdi;
+ __ get_thread(java_thread);
+ __ set_last_Java_frame(java_thread, rsp, rbp, the_pc, noreg);
+ __ movptr(Address(rsp, 0), java_thread);
+}
+
+// The handle is dereferenced through a load barrier.
+static void jfr_epilogue(MacroAssembler* masm) {
+ Register java_thread = rdi;
+ __ get_thread(java_thread);
+ __ reset_last_Java_frame(java_thread, true);
+}
+
+// For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
+// It returns a jobject handle to the event writer.
+// The handle is dereferenced and the return value is the event writer oop.
+RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() {
+ enum layout {
+ FPUState_off = 0,
+ rbp_off = FPUStateSizeInWords,
+ rdi_off,
+ rsi_off,
+ rcx_off,
+ rbx_off,
+ saved_argument_off,
+ saved_argument_off2, // 2nd half of double
+ framesize
+ };
+
+ int insts_size = 1024;
+ int locs_size = 64;
+ const char* name = SharedRuntime::stub_name(SharedStubId::jfr_write_checkpoint_id);
+ CodeBuffer code(name, insts_size, locs_size);
+ OopMapSet* oop_maps = new OopMapSet();
+ MacroAssembler* masm = new MacroAssembler(&code);
+
+ address start = __ pc();
+ __ enter();
+ int frame_complete = __ pc() - start;
+ address the_pc = __ pc();
+ jfr_prologue(the_pc, masm);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1);
+ jfr_epilogue(masm);
+ __ resolve_global_jobject(rax, rdi, rdx);
+ __ leave();
+ __ ret(0);
+
+ OopMap* map = new OopMap(framesize, 1); // rbp
+ oop_maps->add_gc_map(the_pc - start, map);
+
+ RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
+ RuntimeStub::new_runtime_stub(name, &code, frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps, false);
+ return stub;
+}
+
+// For c2: call to return a leased buffer.
+RuntimeStub* SharedRuntime::generate_jfr_return_lease() {
+ enum layout {
+ FPUState_off = 0,
+ rbp_off = FPUStateSizeInWords,
+ rdi_off,
+ rsi_off,
+ rcx_off,
+ rbx_off,
+ saved_argument_off,
+ saved_argument_off2, // 2nd half of double
+ framesize
+ };
+
+ int insts_size = 1024;
+ int locs_size = 64;
+ const char* name = SharedRuntime::stub_name(SharedStubId::jfr_return_lease_id);
+ CodeBuffer code(name, insts_size, locs_size);
+ OopMapSet* oop_maps = new OopMapSet();
+ MacroAssembler* masm = new MacroAssembler(&code);
+
+ address start = __ pc();
+ __ enter();
+ int frame_complete = __ pc() - start;
+ address the_pc = __ pc();
+ jfr_prologue(the_pc, masm);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1);
+ jfr_epilogue(masm);
+ __ leave();
+ __ ret(0);
+
+ OopMap* map = new OopMap(framesize, 1); // rbp
+ oop_maps->add_gc_map(the_pc - start, map);
+
+ RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
+ RuntimeStub::new_runtime_stub(name, &code, frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps, false);
+ return stub;
+}
+
+#endif // INCLUDE_JFR
diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
index decaa9d1ee9..174e2e02779 100644
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
@@ -52,6 +52,7 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/signature.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/timerTrace.hpp"
#include "runtime/vframeArray.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/align.hpp"
@@ -70,25 +71,13 @@
#define __ masm->
-const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size;
-
-class SimpleRuntimeFrame {
-
- public:
+#ifdef PRODUCT
+#define BLOCK_COMMENT(str) /* nothing */
+#else
+#define BLOCK_COMMENT(str) __ block_comment(str)
+#endif // PRODUCT
- // Most of the runtime stubs have this simple frame layout.
- // This class exists to make the layout shared in one place.
- // Offsets are for compiler stack slots, which are jints.
- enum layout {
- // The frame sender code expects that rbp will be in the "natural" place and
- // will override any oopMap setting for it. We must therefore force the layout
- // so that it agrees with the frame sender code.
- rbp_off = frame::arg_reg_save_area_bytes/BytesPerInt,
- rbp_off2,
- return_off, return_off2,
- framesize
- };
-};
+const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size;
class RegisterSaver {
// Capture info about frame layout. Layout offsets are in jint
@@ -842,10 +831,10 @@ static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg
address code_start, address code_end,
Label& L_ok) {
Label L_fail;
- __ lea(temp_reg, ExternalAddress(code_start));
+ __ lea(temp_reg, AddressLiteral(code_start, relocInfo::none));
__ cmpptr(pc_reg, temp_reg);
__ jcc(Assembler::belowEqual, L_fail);
- __ lea(temp_reg, ExternalAddress(code_end));
+ __ lea(temp_reg, AddressLiteral(code_end, relocInfo::none));
__ cmpptr(pc_reg, temp_reg);
__ jcc(Assembler::below, L_ok);
__ bind(L_fail);
@@ -2284,7 +2273,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
__ jcc(Assembler::notEqual, slow_path_lock);
} else {
assert(LockingMode == LM_LIGHTWEIGHT, "must be");
- __ lightweight_lock(obj_reg, swap_reg, r15_thread, rscratch1, slow_path_lock);
+ __ lightweight_lock(lock_reg, obj_reg, swap_reg, r15_thread, rscratch1, slow_path_lock);
}
__ bind(count_mon);
__ inc_held_monitor_count();
@@ -2634,7 +2623,8 @@ void SharedRuntime::generate_deopt_blob() {
pad += 512; // Increase the buffer size when compiling for JVMCI
}
#endif
- CodeBuffer buffer("deopt_blob", 2560+pad, 1024);
+ const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id);
+ CodeBuffer buffer(name, 2560+pad, 1024);
MacroAssembler* masm = new MacroAssembler(&buffer);
int frame_size_in_words;
OopMap* map = nullptr;
@@ -2684,7 +2674,7 @@ void SharedRuntime::generate_deopt_blob() {
int reexecute_offset = __ pc() - start;
#if INCLUDE_JVMCI && !defined(COMPILER1)
- if (EnableJVMCI && UseJVMCICompiler) {
+ if (UseJVMCICompiler) {
// JVMCI does not use this kind of deoptimization
__ should_not_reach_here();
}
@@ -2987,204 +2977,30 @@ void SharedRuntime::generate_deopt_blob() {
#endif
}
-#ifdef COMPILER2
-//------------------------------generate_uncommon_trap_blob--------------------
-void SharedRuntime::generate_uncommon_trap_blob() {
- // Allocate space for the code
- ResourceMark rm;
- // Setup code generation tools
- CodeBuffer buffer("uncommon_trap_blob", 2048, 1024);
- MacroAssembler* masm = new MacroAssembler(&buffer);
-
- assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
-
- address start = __ pc();
-
- // Push self-frame. We get here with a return address on the
- // stack, so rsp is 8-byte aligned until we allocate our frame.
- __ subptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Epilog!
-
- // No callee saved registers. rbp is assumed implicitly saved
- __ movptr(Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt), rbp);
-
- // compiler left unloaded_class_index in j_rarg0 move to where the
- // runtime expects it.
- __ movl(c_rarg1, j_rarg0);
-
- __ set_last_Java_frame(noreg, noreg, nullptr, rscratch1);
-
- // Call C code. Need thread but NOT official VM entry
- // crud. We cannot block on this call, no GC can happen. Call should
- // capture callee-saved registers as well as return values.
- // Thread is in rdi already.
- //
- // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index);
-
- __ mov(c_rarg0, r15_thread);
- __ movl(c_rarg2, Deoptimization::Unpack_uncommon_trap);
- __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)));
-
- // Set an oopmap for the call site
- OopMapSet* oop_maps = new OopMapSet();
- OopMap* map = new OopMap(SimpleRuntimeFrame::framesize, 0);
-
- // location of rbp is known implicitly by the frame sender code
-
- oop_maps->add_gc_map(__ pc() - start, map);
-
- __ reset_last_Java_frame(false);
-
- // Load UnrollBlock* into rdi
- __ mov(rdi, rax);
-
-#ifdef ASSERT
- { Label L;
- __ cmpptr(Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset()),
- Deoptimization::Unpack_uncommon_trap);
- __ jcc(Assembler::equal, L);
- __ stop("SharedRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap");
- __ bind(L);
- }
-#endif
-
- // Pop all the frames we must move/replace.
- //
- // Frame picture (youngest to oldest)
- // 1: self-frame (no frame link)
- // 2: deopting frame (no frame link)
- // 3: caller of deopting frame (could be compiled/interpreted).
-
- // Pop self-frame. We have no frame, and must rely only on rax and rsp.
- __ addptr(rsp, (SimpleRuntimeFrame::framesize - 2) << LogBytesPerInt); // Epilog!
-
- // Pop deoptimized frame (int)
- __ movl(rcx, Address(rdi,
- Deoptimization::UnrollBlock::
- size_of_deoptimized_frame_offset()));
- __ addptr(rsp, rcx);
-
- // rsp should be pointing at the return address to the caller (3)
-
- // Pick up the initial fp we should save
- // restore rbp before stack bang because if stack overflow is thrown it needs to be pushed (and preserved)
- __ movptr(rbp, Address(rdi, Deoptimization::UnrollBlock::initial_info_offset()));
-
-#ifdef ASSERT
- // Compilers generate code that bang the stack by as much as the
- // interpreter would need. So this stack banging should never
- // trigger a fault. Verify that it does not on non product builds.
- __ movl(rbx, Address(rdi ,Deoptimization::UnrollBlock::total_frame_sizes_offset()));
- __ bang_stack_size(rbx, rcx);
-#endif
-
- // Load address of array of frame pcs into rcx (address*)
- __ movptr(rcx, Address(rdi, Deoptimization::UnrollBlock::frame_pcs_offset()));
-
- // Trash the return pc
- __ addptr(rsp, wordSize);
-
- // Load address of array of frame sizes into rsi (intptr_t*)
- __ movptr(rsi, Address(rdi, Deoptimization::UnrollBlock:: frame_sizes_offset()));
-
- // Counter
- __ movl(rdx, Address(rdi, Deoptimization::UnrollBlock:: number_of_frames_offset())); // (int)
-
- // Now adjust the caller's stack to make up for the extra locals but
- // record the original sp so that we can save it in the skeletal
- // interpreter frame and the stack walking of interpreter_sender
- // will get the unextended sp value and not the "real" sp value.
-
- const Register sender_sp = r8;
-
- __ mov(sender_sp, rsp);
- __ movl(rbx, Address(rdi, Deoptimization::UnrollBlock:: caller_adjustment_offset())); // (int)
- __ subptr(rsp, rbx);
-
- // Push interpreter frames in a loop
- Label loop;
- __ bind(loop);
- __ movptr(rbx, Address(rsi, 0)); // Load frame size
- __ subptr(rbx, 2 * wordSize); // We'll push pc and rbp by hand
- __ pushptr(Address(rcx, 0)); // Save return address
- __ enter(); // Save old & set new rbp
- __ subptr(rsp, rbx); // Prolog
- __ movptr(Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize),
- sender_sp); // Make it walkable
- // This value is corrected by layout_activation_impl
- __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD);
- __ mov(sender_sp, rsp); // Pass sender_sp to next frame
- __ addptr(rsi, wordSize); // Bump array pointer (sizes)
- __ addptr(rcx, wordSize); // Bump array pointer (pcs)
- __ decrementl(rdx); // Decrement counter
- __ jcc(Assembler::notZero, loop);
- __ pushptr(Address(rcx, 0)); // Save final return address
-
- // Re-push self-frame
- __ enter(); // Save old & set new rbp
- __ subptr(rsp, (SimpleRuntimeFrame::framesize - 4) << LogBytesPerInt);
- // Prolog
-
- // Use rbp because the frames look interpreted now
- // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP.
- // Don't need the precise return PC here, just precise enough to point into this code blob.
- address the_pc = __ pc();
- __ set_last_Java_frame(noreg, rbp, the_pc, rscratch1);
-
- // Call C code. Need thread but NOT official VM entry
- // crud. We cannot block on this call, no GC can happen. Call should
- // restore return values to their stack-slots with the new SP.
- // Thread is in rdi already.
- //
- // BasicType unpack_frames(JavaThread* thread, int exec_mode);
-
- __ andptr(rsp, -(StackAlignmentInBytes)); // Align SP as required by ABI
- __ mov(c_rarg0, r15_thread);
- __ movl(c_rarg1, Deoptimization::Unpack_uncommon_trap);
- __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)));
-
- // Set an oopmap for the call site
- // Use the same PC we used for the last java frame
- oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0));
-
- // Clear fp AND pc
- __ reset_last_Java_frame(true);
-
- // Pop self-frame.
- __ leave(); // Epilog
-
- // Jump to interpreter
- __ ret(0);
-
- // Make sure all code is generated
- masm->flush();
-
- _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps,
- SimpleRuntimeFrame::framesize >> 1);
-}
-#endif // COMPILER2
-
//------------------------------generate_handler_blob------
//
// Generate a special Compile2Runtime blob that saves all registers,
// and setup oopmap.
//
-SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) {
+SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) {
assert(StubRoutines::forward_exception_entry() != nullptr,
"must be generated before");
+ assert(is_polling_page_id(id), "expected a polling page stub id");
ResourceMark rm;
OopMapSet *oop_maps = new OopMapSet();
OopMap* map;
// Allocate space for the code. Setup code generation tools.
- CodeBuffer buffer("handler_blob", 2348, 1024);
+ const char* name = SharedRuntime::stub_name(id);
+ CodeBuffer buffer(name, 2348, 1024);
MacroAssembler* masm = new MacroAssembler(&buffer);
address start = __ pc();
address call_pc = nullptr;
int frame_size_in_words;
- bool cause_return = (poll_type == POLL_AT_RETURN);
- bool save_wide_vectors = (poll_type == POLL_AT_VECTOR_LOOP);
+ bool cause_return = (id == SharedStubId::polling_page_return_handler_id);
+ bool save_wide_vectors = (id == SharedStubId::polling_page_vectors_safepoint_handler_id);
// Make room for return address (or push it again)
if (!cause_return) {
@@ -3327,12 +3143,14 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
// but since this is generic code we don't know what they are and the caller
// must do any gc of the args.
//
-RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) {
+RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) {
assert (StubRoutines::forward_exception_entry() != nullptr, "must be generated before");
+ assert(is_resolve_id(id), "expected a resolve stub id");
// allocate space for the code
ResourceMark rm;
+ const char* name = SharedRuntime::stub_name(id);
CodeBuffer buffer(name, 1552, 512);
MacroAssembler* masm = new MacroAssembler(&buffer);
@@ -3404,6 +3222,105 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha
return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true);
}
+// Continuation point for throwing of implicit exceptions that are
+// not handled in the current activation. Fabricates an exception
+// oop and initiates normal exception dispatching in this
+// frame. Since we need to preserve callee-saved values (currently
+// only for C2, but done for C1 as well) we need a callee-saved oop
+// map and therefore have to make these stubs into RuntimeStubs
+// rather than BufferBlobs. If the compiler needs all registers to
+// be preserved between the fault point and the exception handler
+// then it must assume responsibility for that in
+// AbstractCompiler::continuation_for_implicit_null_exception or
+// continuation_for_implicit_division_by_zero_exception. All other
+// implicit exceptions (e.g., NullPointerException or
+// AbstractMethodError on entry) are either at call sites or
+// otherwise assume that stack unwinding will be initiated, so
+// caller saved registers were assumed volatile in the compiler.
+RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) {
+ assert(is_throw_id(id), "expected a throw stub id");
+
+ const char* name = SharedRuntime::stub_name(id);
+
+ // Information about frame layout at time of blocking runtime call.
+ // Note that we only have to preserve callee-saved registers since
+ // the compilers are responsible for supplying a continuation point
+ // if they expect all registers to be preserved.
+ enum layout {
+ rbp_off = frame::arg_reg_save_area_bytes/BytesPerInt,
+ rbp_off2,
+ return_off,
+ return_off2,
+ framesize // inclusive of return address
+ };
+
+ int insts_size = 512;
+ int locs_size = 64;
+
+ ResourceMark rm;
+ const char* timer_msg = "SharedRuntime generate_throw_exception";
+ TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime));
+
+ CodeBuffer code(name, insts_size, locs_size);
+ OopMapSet* oop_maps = new OopMapSet();
+ MacroAssembler* masm = new MacroAssembler(&code);
+
+ address start = __ pc();
+
+ // This is an inlined and slightly modified version of call_VM
+ // which has the ability to fetch the return PC out of
+ // thread-local storage and also sets up last_Java_sp slightly
+ // differently than the real call_VM
+
+ __ enter(); // required for proper stackwalking of RuntimeStub frame
+
+ assert(is_even(framesize/2), "sp not 16-byte aligned");
+
+ // return address and rbp are already in place
+ __ subptr(rsp, (framesize-4) << LogBytesPerInt); // prolog
+
+ int frame_complete = __ pc() - start;
+
+ // Set up last_Java_sp and last_Java_fp
+ address the_pc = __ pc();
+ __ set_last_Java_frame(rsp, rbp, the_pc, rscratch1);
+ __ andptr(rsp, -(StackAlignmentInBytes)); // Align stack
+
+ // Call runtime
+ __ movptr(c_rarg0, r15_thread);
+ BLOCK_COMMENT("call runtime_entry");
+ __ call(RuntimeAddress(runtime_entry));
+
+ // Generate oop map
+ OopMap* map = new OopMap(framesize, 0);
+
+ oop_maps->add_gc_map(the_pc - start, map);
+
+ __ reset_last_Java_frame(true);
+
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+
+ // check for pending exceptions
+#ifdef ASSERT
+ Label L;
+ __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), NULL_WORD);
+ __ jcc(Assembler::notEqual, L);
+ __ should_not_reach_here();
+ __ bind(L);
+#endif // ASSERT
+ __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
+
+
+ // codeBlob framesize is in words (not VMRegImpl::slot_size)
+ RuntimeStub* stub =
+ RuntimeStub::new_runtime_stub(name,
+ &code,
+ frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps, false);
+ return stub;
+}
+
//------------------------------Montgomery multiplication------------------------
//
@@ -3669,136 +3586,96 @@ void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints,
reverse_words(m, (julong *)m_ints, longwords);
}
-#ifdef COMPILER2
-// This is here instead of runtime_x86_64.cpp because it uses SimpleRuntimeFrame
-//
-//------------------------------generate_exception_blob---------------------------
-// creates exception blob at the end
-// Using exception blob, this code is jumped from a compiled method.
-// (see emit_exception_handler in x86_64.ad file)
-//
-// Given an exception pc at a call we call into the runtime for the
-// handler in this method. This handler might merely restore state
-// (i.e. callee save registers) unwind the frame and jump to the
-// exception handler for the nmethod if there is no Java level handler
-// for the nmethod.
-//
-// This code is entered with a jmp.
-//
-// Arguments:
-// rax: exception oop
-// rdx: exception pc
-//
-// Results:
-// rax: exception oop
-// rdx: exception pc in caller or ???
-// destination: exception handler of caller
-//
-// Note: the exception pc MUST be at a call (precise debug information)
-// Registers rax, rdx, rcx, rsi, rdi, r8-r11 are not callee saved.
-//
-
-void OptoRuntime::generate_exception_blob() {
- assert(!OptoRuntime::is_callee_saved_register(RDX_num), "");
- assert(!OptoRuntime::is_callee_saved_register(RAX_num), "");
- assert(!OptoRuntime::is_callee_saved_register(RCX_num), "");
-
- assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
-
- // Allocate space for the code
- ResourceMark rm;
- // Setup code generation tools
- CodeBuffer buffer("exception_blob", 2048, 1024);
- MacroAssembler* masm = new MacroAssembler(&buffer);
+#if INCLUDE_JFR
+// For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
+// It returns a jobject handle to the event writer.
+// The handle is dereferenced and the return value is the event writer oop.
+RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() {
+ enum layout {
+ rbp_off,
+ rbpH_off,
+ return_off,
+ return_off2,
+ framesize // inclusive of return address
+ };
+ const char* name = SharedRuntime::stub_name(SharedStubId::jfr_write_checkpoint_id);
+ CodeBuffer code(name, 1024, 64);
+ MacroAssembler* masm = new MacroAssembler(&code);
address start = __ pc();
- // Exception pc is 'return address' for stack walker
- __ push(rdx);
- __ subptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Prolog
-
- // Save callee-saved registers. See x86_64.ad.
-
- // rbp is an implicitly saved callee saved register (i.e., the calling
- // convention will save/restore it in the prolog/epilog). Other than that
- // there are no callee save registers now that adapter frames are gone.
-
- __ movptr(Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt), rbp);
+ __ enter();
+ address the_pc = __ pc();
- // Store exception in Thread object. We cannot pass any arguments to the
- // handle_exception call, since we do not want to make any assumption
- // about the size of the frame where the exception happened in.
- // c_rarg0 is either rdi (Linux) or rcx (Windows).
- __ movptr(Address(r15_thread, JavaThread::exception_oop_offset()),rax);
- __ movptr(Address(r15_thread, JavaThread::exception_pc_offset()), rdx);
+ int frame_complete = the_pc - start;
- // This call does all the hard work. It checks if an exception handler
- // exists in the method.
- // If so, it returns the handler address.
- // If not, it prepares for stack-unwinding, restoring the callee-save
- // registers of the frame being removed.
- //
- // address OptoRuntime::handle_exception_C(JavaThread* thread)
+ __ set_last_Java_frame(rsp, rbp, the_pc, rscratch1);
+ __ movptr(c_rarg0, r15_thread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1);
+ __ reset_last_Java_frame(true);
- // At a method handle call, the stack may not be properly aligned
- // when returning with an exception.
- address the_pc = __ pc();
- __ set_last_Java_frame(noreg, noreg, the_pc, rscratch1);
- __ mov(c_rarg0, r15_thread);
- __ andptr(rsp, -(StackAlignmentInBytes)); // Align stack
- __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C)));
+ // rax is jobject handle result, unpack and process it through a barrier.
+ __ resolve_global_jobject(rax, r15_thread, c_rarg0);
- // Set an oopmap for the call site. This oopmap will only be used if we
- // are unwinding the stack. Hence, all locations will be dead.
- // Callee-saved registers will be the same as the frame above (i.e.,
- // handle_exception_stub), since they were restored when we got the
- // exception.
+ __ leave();
+ __ ret(0);
OopMapSet* oop_maps = new OopMapSet();
+ OopMap* map = new OopMap(framesize, 1);
+ oop_maps->add_gc_map(frame_complete, map);
- oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0));
-
- __ reset_last_Java_frame(false);
-
- // Restore callee-saved registers
+ RuntimeStub* stub =
+ RuntimeStub::new_runtime_stub(name,
+ &code,
+ frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps,
+ false);
+ return stub;
+}
- // rbp is an implicitly saved callee-saved register (i.e., the calling
- // convention will save restore it in prolog/epilog) Other than that
- // there are no callee save registers now that adapter frames are gone.
+// For c2: call to return a leased buffer.
+RuntimeStub* SharedRuntime::generate_jfr_return_lease() {
+ enum layout {
+ rbp_off,
+ rbpH_off,
+ return_off,
+ return_off2,
+ framesize // inclusive of return address
+ };
- __ movptr(rbp, Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt));
+ const char* name = SharedRuntime::stub_name(SharedStubId::jfr_return_lease_id);
+ CodeBuffer code(name, 1024, 64);
+ MacroAssembler* masm = new MacroAssembler(&code);
+ address start = __ pc();
- __ addptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Epilog
- __ pop(rdx); // No need for exception pc anymore
+ __ enter();
+ address the_pc = __ pc();
- // rax: exception handler
+ int frame_complete = the_pc - start;
- // We have a handler in rax (could be deopt blob).
- __ mov(r8, rax);
+ __ set_last_Java_frame(rsp, rbp, the_pc, rscratch2);
+ __ movptr(c_rarg0, r15_thread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1);
+ __ reset_last_Java_frame(true);
- // Get the exception oop
- __ movptr(rax, Address(r15_thread, JavaThread::exception_oop_offset()));
- // Get the exception pc in case we are deoptimized
- __ movptr(rdx, Address(r15_thread, JavaThread::exception_pc_offset()));
-#ifdef ASSERT
- __ movptr(Address(r15_thread, JavaThread::exception_handler_pc_offset()), NULL_WORD);
- __ movptr(Address(r15_thread, JavaThread::exception_pc_offset()), NULL_WORD);
-#endif
- // Clear the exception oop so GC no longer processes it as a root.
- __ movptr(Address(r15_thread, JavaThread::exception_oop_offset()), NULL_WORD);
+ __ leave();
+ __ ret(0);
- // rax: exception oop
- // r8: exception handler
- // rdx: exception pc
- // Jump to handler
+ OopMapSet* oop_maps = new OopMapSet();
+ OopMap* map = new OopMap(framesize, 1);
+ oop_maps->add_gc_map(frame_complete, map);
- __ jmp(r8);
+ RuntimeStub* stub =
+ RuntimeStub::new_runtime_stub(name,
+ &code,
+ frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps,
+ false);
+ return stub;
+}
- // Make sure all code is generated
- masm->flush();
+#endif // INCLUDE_JFR
- // Set exception blob
- _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1);
-}
-#endif // COMPILER2
diff --git a/src/hotspot/cpu/x86/smallRegisterMap_x86.inline.hpp b/src/hotspot/cpu/x86/smallRegisterMap_x86.inline.hpp
index 5f21939a3aa..63212a686af 100644
--- a/src/hotspot/cpu/x86/smallRegisterMap_x86.inline.hpp
+++ b/src/hotspot/cpu/x86/smallRegisterMap_x86.inline.hpp
@@ -30,8 +30,16 @@
// Java frames don't have callee saved registers (except for rbp), so we can use a smaller RegisterMap
class SmallRegisterMap {
+ constexpr SmallRegisterMap() = default;
+ ~SmallRegisterMap() = default;
+ NONCOPYABLE(SmallRegisterMap);
+
public:
- static constexpr SmallRegisterMap* instance = nullptr;
+ static const SmallRegisterMap* instance() {
+ static constexpr SmallRegisterMap the_instance{};
+ return &the_instance;
+ }
+
private:
static void assert_is_rbp(VMReg r) NOT_DEBUG_RETURN
DEBUG_ONLY({ assert(r == rbp->as_VMReg() || r == rbp->as_VMReg()->next(), "Reg: %s", r->name()); })
@@ -48,17 +56,6 @@ class SmallRegisterMap {
return map;
}
- SmallRegisterMap() {}
-
- SmallRegisterMap(const RegisterMap* map) {
- #ifdef ASSERT
- for(int i = 0; i < RegisterMap::reg_count; i++) {
- VMReg r = VMRegImpl::as_VMReg(i);
- if (map->location(r, (intptr_t*)nullptr) != nullptr) assert_is_rbp(r);
- }
- #endif
- }
-
inline address location(VMReg reg, intptr_t* sp) const {
assert_is_rbp(reg);
return (address)(sp - frame::sender_sp_offset);
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp
index d8067a39177..de13772dcfb 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp
@@ -3843,121 +3843,8 @@ class StubGenerator: public StubCodeGenerator {
return start;
}
- public:
- // Information about frame layout at time of blocking runtime call.
- // Note that we only have to preserve callee-saved registers since
- // the compilers are responsible for supplying a continuation point
- // if they expect all registers to be preserved.
- enum layout {
- thread_off, // last_java_sp
- arg1_off,
- arg2_off,
- rbp_off, // callee saved register
- ret_pc,
- framesize
- };
-
private:
-#undef __
-#define __ masm->
-
- //------------------------------------------------------------------------------------------------------------------------
- // Continuation point for throwing of implicit exceptions that are not handled in
- // the current activation. Fabricates an exception oop and initiates normal
- // exception dispatching in this frame.
- //
- // Previously the compiler (c2) allowed for callee save registers on Java calls.
- // This is no longer true after adapter frames were removed but could possibly
- // be brought back in the future if the interpreter code was reworked and it
- // was deemed worthwhile. The comment below was left to describe what must
- // happen here if callee saves were resurrected. As it stands now this stub
- // could actually be a vanilla BufferBlob and have now oopMap at all.
- // Since it doesn't make much difference we've chosen to leave it the
- // way it was in the callee save days and keep the comment.
-
- // If we need to preserve callee-saved values we need a callee-saved oop map and
- // therefore have to make these stubs into RuntimeStubs rather than BufferBlobs.
- // If the compiler needs all registers to be preserved between the fault
- // point and the exception handler then it must assume responsibility for that in
- // AbstractCompiler::continuation_for_implicit_null_exception or
- // continuation_for_implicit_division_by_zero_exception. All other implicit
- // exceptions (e.g., NullPointerException or AbstractMethodError on entry) are
- // either at call sites or otherwise assume that stack unwinding will be initiated,
- // so caller saved registers were assumed volatile in the compiler.
- address generate_throw_exception(const char* name, address runtime_entry,
- Register arg1 = noreg, Register arg2 = noreg) {
-
- int insts_size = 256;
- int locs_size = 32;
-
- CodeBuffer code(name, insts_size, locs_size);
- OopMapSet* oop_maps = new OopMapSet();
- MacroAssembler* masm = new MacroAssembler(&code);
-
- address start = __ pc();
-
- // This is an inlined and slightly modified version of call_VM
- // which has the ability to fetch the return PC out of
- // thread-local storage and also sets up last_Java_sp slightly
- // differently than the real call_VM
- Register java_thread = rbx;
- __ get_thread(java_thread);
-
- __ enter(); // required for proper stackwalking of RuntimeStub frame
-
- // pc and rbp, already pushed
- __ subptr(rsp, (framesize-2) * wordSize); // prolog
-
- // Frame is now completed as far as size and linkage.
-
- int frame_complete = __ pc() - start;
-
- // push java thread (becomes first argument of C function)
- __ movptr(Address(rsp, thread_off * wordSize), java_thread);
- if (arg1 != noreg) {
- __ movptr(Address(rsp, arg1_off * wordSize), arg1);
- }
- if (arg2 != noreg) {
- assert(arg1 != noreg, "missing reg arg");
- __ movptr(Address(rsp, arg2_off * wordSize), arg2);
- }
-
- // Set up last_Java_sp and last_Java_fp
- __ set_last_Java_frame(java_thread, rsp, rbp, nullptr, noreg);
-
- // Call runtime
- BLOCK_COMMENT("call runtime_entry");
- __ call(RuntimeAddress(runtime_entry));
- // Generate oop map
- OopMap* map = new OopMap(framesize, 0);
- oop_maps->add_gc_map(__ pc() - start, map);
-
- // restore the thread (cannot use the pushed argument since arguments
- // may be overwritten by C code generated by an optimizing compiler);
- // however can use the register value directly if it is callee saved.
- __ get_thread(java_thread);
-
- __ reset_last_Java_frame(java_thread, true);
-
- __ leave(); // required for proper stackwalking of RuntimeStub frame
-
- // check for pending exceptions
-#ifdef ASSERT
- Label L;
- __ cmpptr(Address(java_thread, Thread::pending_exception_offset()), NULL_WORD);
- __ jcc(Assembler::notEqual, L);
- __ should_not_reach_here();
- __ bind(L);
-#endif /* ASSERT */
- __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
-
-
- RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, framesize, oop_maps, false);
- return stub->entry_point();
- }
-
-
void create_control_words() {
// Round to nearest, 53-bit mode, exceptions masked
StubRoutines::x86::_fpu_cntrl_wrd_std = 0x027F;
@@ -3997,109 +3884,6 @@ class StubGenerator: public StubCodeGenerator {
return nullptr;
}
-#if INCLUDE_JFR
-
- static void jfr_prologue(address the_pc, MacroAssembler* masm) {
- Register java_thread = rdi;
- __ get_thread(java_thread);
- __ set_last_Java_frame(java_thread, rsp, rbp, the_pc, noreg);
- __ movptr(Address(rsp, 0), java_thread);
- }
-
- // The handle is dereferenced through a load barrier.
- static void jfr_epilogue(MacroAssembler* masm) {
- Register java_thread = rdi;
- __ get_thread(java_thread);
- __ reset_last_Java_frame(java_thread, true);
- }
-
- // For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
- // It returns a jobject handle to the event writer.
- // The handle is dereferenced and the return value is the event writer oop.
- static RuntimeStub* generate_jfr_write_checkpoint() {
- enum layout {
- FPUState_off = 0,
- rbp_off = FPUStateSizeInWords,
- rdi_off,
- rsi_off,
- rcx_off,
- rbx_off,
- saved_argument_off,
- saved_argument_off2, // 2nd half of double
- framesize
- };
-
- int insts_size = 1024;
- int locs_size = 64;
- CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size);
- OopMapSet* oop_maps = new OopMapSet();
- MacroAssembler* masm = new MacroAssembler(&code);
- MacroAssembler* _masm = masm;
-
- address start = __ pc();
- __ enter();
- int frame_complete = __ pc() - start;
- address the_pc = __ pc();
- jfr_prologue(the_pc, _masm);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1);
- jfr_epilogue(_masm);
- __ resolve_global_jobject(rax, rdi, rdx);
- __ leave();
- __ ret(0);
-
- OopMap* map = new OopMap(framesize, 1); // rbp
- oop_maps->add_gc_map(the_pc - start, map);
-
- RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
- RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps, false);
- return stub;
- }
-
- // For c2: call to return a leased buffer.
- static RuntimeStub* generate_jfr_return_lease() {
- enum layout {
- FPUState_off = 0,
- rbp_off = FPUStateSizeInWords,
- rdi_off,
- rsi_off,
- rcx_off,
- rbx_off,
- saved_argument_off,
- saved_argument_off2, // 2nd half of double
- framesize
- };
-
- int insts_size = 1024;
- int locs_size = 64;
- CodeBuffer code("jfr_return_lease", insts_size, locs_size);
- OopMapSet* oop_maps = new OopMapSet();
- MacroAssembler* masm = new MacroAssembler(&code);
- MacroAssembler* _masm = masm;
-
- address start = __ pc();
- __ enter();
- int frame_complete = __ pc() - start;
- address the_pc = __ pc();
- jfr_prologue(the_pc, _masm);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1);
- jfr_epilogue(_masm);
- __ leave();
- __ ret(0);
-
- OopMap* map = new OopMap(framesize, 1); // rbp
- oop_maps->add_gc_map(the_pc - start, map);
-
- RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
- RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps, false);
- return stub;
- }
-
-#endif // INCLUDE_JFR
-
//---------------------------------------------------------------------------
// Initialization
@@ -4130,12 +3914,6 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::x86::_d2i_wrapper = generate_d2i_wrapper(T_INT, CAST_FROM_FN_PTR(address, SharedRuntime::d2i));
StubRoutines::x86::_d2l_wrapper = generate_d2i_wrapper(T_LONG, CAST_FROM_FN_PTR(address, SharedRuntime::d2l));
- // Build this early so it's available for the interpreter
- StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError));
- StubRoutines::_throw_delayed_StackOverflowError_entry = generate_throw_exception("delayed StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError));
-
if (UseCRC32Intrinsics) {
// set table address before stub generation which use it
StubRoutines::_crc_table_adr = (address)StubRoutines::x86::_crc_table;
@@ -4188,28 +3966,11 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_cont_thaw = generate_cont_thaw();
StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier();
StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception();
-
- JFR_ONLY(generate_jfr_stubs();)
}
-#if INCLUDE_JFR
- void generate_jfr_stubs() {
- StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint();
- StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point();
- StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease();
- StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point();
- }
-#endif // INCLUDE_JFR
-
void generate_final_stubs() {
// Generates all stubs and initializes the entry points
- // These entry points require SharedInfo::stack0 to be set up in non-core builds
- // and need to be relocatable, so they each fabricate a RuntimeStub internally.
- StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError));
- StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError));
- StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call));
-
// support for verify_oop (must happen after universe_init)
StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop();
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp
index c9c4b056eb5..e23c83ed197 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
+#include "classfile/javaClasses.hpp"
#include "classfile/vmIntrinsics.hpp"
#include "compiler/oopMap.hpp"
#include "gc/shared/barrierSet.hpp"
@@ -45,9 +46,6 @@
#if INCLUDE_JVMCI
#include "jvmci/jvmci_globals.hpp"
#endif
-#if INCLUDE_JFR
-#include "jfr/support/jfrIntrinsics.hpp"
-#endif
// For a more detailed description of the stub routine structure
// see the comment in stubRoutines.hpp
@@ -1560,7 +1558,7 @@ address StubGenerator::generate_sha256_implCompress(bool multi_block, const char
address StubGenerator::generate_sha512_implCompress(bool multi_block, const char *name) {
assert(VM_Version::supports_avx2(), "");
- assert(VM_Version::supports_bmi2(), "");
+ assert(VM_Version::supports_bmi2() || VM_Version::supports_sha512(), "");
__ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", name);
address start = __ pc();
@@ -1570,22 +1568,24 @@ address StubGenerator::generate_sha512_implCompress(bool multi_block, const char
Register ofs = c_rarg2;
Register limit = c_rarg3;
- const XMMRegister msg = xmm0;
- const XMMRegister state0 = xmm1;
- const XMMRegister state1 = xmm2;
- const XMMRegister msgtmp0 = xmm3;
- const XMMRegister msgtmp1 = xmm4;
- const XMMRegister msgtmp2 = xmm5;
- const XMMRegister msgtmp3 = xmm6;
- const XMMRegister msgtmp4 = xmm7;
-
- const XMMRegister shuf_mask = xmm8;
-
__ enter();
- __ sha512_AVX2(msg, state0, state1, msgtmp0, msgtmp1, msgtmp2, msgtmp3, msgtmp4,
- buf, state, ofs, limit, rsp, multi_block, shuf_mask);
-
+ if (VM_Version::supports_sha512()) {
+ __ sha512_update_ni_x1(state, buf, ofs, limit, multi_block);
+ } else {
+ const XMMRegister msg = xmm0;
+ const XMMRegister state0 = xmm1;
+ const XMMRegister state1 = xmm2;
+ const XMMRegister msgtmp0 = xmm3;
+ const XMMRegister msgtmp1 = xmm4;
+ const XMMRegister msgtmp2 = xmm5;
+ const XMMRegister msgtmp3 = xmm6;
+ const XMMRegister msgtmp4 = xmm7;
+
+ const XMMRegister shuf_mask = xmm8;
+ __ sha512_AVX2(msg, state0, state1, msgtmp0, msgtmp1, msgtmp2, msgtmp3, msgtmp4,
+ buf, state, ofs, limit, rsp, multi_block, shuf_mask);
+ }
__ vzeroupper();
__ leave();
__ ret(0);
@@ -3576,6 +3576,9 @@ void StubGenerator::generate_libm_stubs() {
if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dtan)) {
StubRoutines::_dtan = generate_libmTan(); // from stubGenerator_x86_64_tan.cpp
}
+ if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dtanh)) {
+ StubRoutines::_dtanh = generate_libmTanh(); // from stubGenerator_x86_64_tanh.cpp
+ }
if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dexp)) {
StubRoutines::_dexp = generate_libmExp(); // from stubGenerator_x86_64_exp.cpp
}
@@ -3702,7 +3705,7 @@ address StubGenerator::generate_cont_thaw(const char* label, Continuation::thaw_
Label L_thaw_success;
__ testptr(rbx, rbx);
__ jccb(Assembler::notZero, L_thaw_success);
- __ jump(ExternalAddress(StubRoutines::throw_StackOverflowError_entry()));
+ __ jump(RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry()));
__ bind(L_thaw_success);
// Make room for the thawed frames and align the stack.
@@ -3778,198 +3781,6 @@ address StubGenerator::generate_cont_returnBarrier_exception() {
return generate_cont_thaw("Cont thaw return barrier exception", Continuation::thaw_return_barrier_exception);
}
-#if INCLUDE_JFR
-
-// For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
-// It returns a jobject handle to the event writer.
-// The handle is dereferenced and the return value is the event writer oop.
-RuntimeStub* StubGenerator::generate_jfr_write_checkpoint() {
- enum layout {
- rbp_off,
- rbpH_off,
- return_off,
- return_off2,
- framesize // inclusive of return address
- };
-
- CodeBuffer code("jfr_write_checkpoint", 1024, 64);
- MacroAssembler* _masm = new MacroAssembler(&code);
- address start = __ pc();
-
- __ enter();
- address the_pc = __ pc();
-
- int frame_complete = the_pc - start;
-
- __ set_last_Java_frame(rsp, rbp, the_pc, rscratch1);
- __ movptr(c_rarg0, r15_thread);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1);
- __ reset_last_Java_frame(true);
-
- // rax is jobject handle result, unpack and process it through a barrier.
- __ resolve_global_jobject(rax, r15_thread, c_rarg0);
-
- __ leave();
- __ ret(0);
-
- OopMapSet* oop_maps = new OopMapSet();
- OopMap* map = new OopMap(framesize, 1);
- oop_maps->add_gc_map(frame_complete, map);
-
- RuntimeStub* stub =
- RuntimeStub::new_runtime_stub(code.name(),
- &code,
- frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps,
- false);
- return stub;
-}
-
-// For c2: call to return a leased buffer.
-RuntimeStub* StubGenerator::generate_jfr_return_lease() {
- enum layout {
- rbp_off,
- rbpH_off,
- return_off,
- return_off2,
- framesize // inclusive of return address
- };
-
- CodeBuffer code("jfr_return_lease", 1024, 64);
- MacroAssembler* _masm = new MacroAssembler(&code);
- address start = __ pc();
-
- __ enter();
- address the_pc = __ pc();
-
- int frame_complete = the_pc - start;
-
- __ set_last_Java_frame(rsp, rbp, the_pc, rscratch2);
- __ movptr(c_rarg0, r15_thread);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1);
- __ reset_last_Java_frame(true);
-
- __ leave();
- __ ret(0);
-
- OopMapSet* oop_maps = new OopMapSet();
- OopMap* map = new OopMap(framesize, 1);
- oop_maps->add_gc_map(frame_complete, map);
-
- RuntimeStub* stub =
- RuntimeStub::new_runtime_stub(code.name(),
- &code,
- frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps,
- false);
- return stub;
-}
-
-#endif // INCLUDE_JFR
-
-// Continuation point for throwing of implicit exceptions that are
-// not handled in the current activation. Fabricates an exception
-// oop and initiates normal exception dispatching in this
-// frame. Since we need to preserve callee-saved values (currently
-// only for C2, but done for C1 as well) we need a callee-saved oop
-// map and therefore have to make these stubs into RuntimeStubs
-// rather than BufferBlobs. If the compiler needs all registers to
-// be preserved between the fault point and the exception handler
-// then it must assume responsibility for that in
-// AbstractCompiler::continuation_for_implicit_null_exception or
-// continuation_for_implicit_division_by_zero_exception. All other
-// implicit exceptions (e.g., NullPointerException or
-// AbstractMethodError on entry) are either at call sites or
-// otherwise assume that stack unwinding will be initiated, so
-// caller saved registers were assumed volatile in the compiler.
-address StubGenerator::generate_throw_exception(const char* name,
- address runtime_entry,
- Register arg1,
- Register arg2) {
- // Information about frame layout at time of blocking runtime call.
- // Note that we only have to preserve callee-saved registers since
- // the compilers are responsible for supplying a continuation point
- // if they expect all registers to be preserved.
- enum layout {
- rbp_off = frame::arg_reg_save_area_bytes/BytesPerInt,
- rbp_off2,
- return_off,
- return_off2,
- framesize // inclusive of return address
- };
-
- int insts_size = 512;
- int locs_size = 64;
-
- CodeBuffer code(name, insts_size, locs_size);
- OopMapSet* oop_maps = new OopMapSet();
- MacroAssembler* _masm = new MacroAssembler(&code);
-
- address start = __ pc();
-
- // This is an inlined and slightly modified version of call_VM
- // which has the ability to fetch the return PC out of
- // thread-local storage and also sets up last_Java_sp slightly
- // differently than the real call_VM
-
- __ enter(); // required for proper stackwalking of RuntimeStub frame
-
- assert(is_even(framesize/2), "sp not 16-byte aligned");
-
- // return address and rbp are already in place
- __ subptr(rsp, (framesize-4) << LogBytesPerInt); // prolog
-
- int frame_complete = __ pc() - start;
-
- // Set up last_Java_sp and last_Java_fp
- address the_pc = __ pc();
- __ set_last_Java_frame(rsp, rbp, the_pc, rscratch1);
- __ andptr(rsp, -(StackAlignmentInBytes)); // Align stack
-
- // Call runtime
- if (arg1 != noreg) {
- assert(arg2 != c_rarg1, "clobbered");
- __ movptr(c_rarg1, arg1);
- }
- if (arg2 != noreg) {
- __ movptr(c_rarg2, arg2);
- }
- __ movptr(c_rarg0, r15_thread);
- BLOCK_COMMENT("call runtime_entry");
- __ call(RuntimeAddress(runtime_entry));
-
- // Generate oop map
- OopMap* map = new OopMap(framesize, 0);
-
- oop_maps->add_gc_map(the_pc - start, map);
-
- __ reset_last_Java_frame(true);
-
- __ leave(); // required for proper stackwalking of RuntimeStub frame
-
- // check for pending exceptions
-#ifdef ASSERT
- Label L;
- __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), NULL_WORD);
- __ jcc(Assembler::notEqual, L);
- __ should_not_reach_here();
- __ bind(L);
-#endif // ASSERT
- __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
-
-
- // codeBlob framesize is in words (not VMRegImpl::slot_size)
- RuntimeStub* stub =
- RuntimeStub::new_runtime_stub(name,
- &code,
- frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps, false);
- return stub->entry_point();
-}
-
// exception handler for upcall stubs
address StubGenerator::generate_upcall_stub_exception_handler() {
StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler");
@@ -3988,6 +3799,28 @@ address StubGenerator::generate_upcall_stub_exception_handler() {
return start;
}
+// load Method* target of MethodHandle
+// j_rarg0 = jobject receiver
+// rbx = result
+address StubGenerator::generate_upcall_stub_load_target() {
+ StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target");
+ address start = __ pc();
+
+ __ resolve_global_jobject(j_rarg0, r15_thread, rscratch1);
+ // Load target method from receiver
+ __ load_heap_oop(rbx, Address(j_rarg0, java_lang_invoke_MethodHandle::form_offset()), rscratch1);
+ __ load_heap_oop(rbx, Address(rbx, java_lang_invoke_LambdaForm::vmentry_offset()), rscratch1);
+ __ load_heap_oop(rbx, Address(rbx, java_lang_invoke_MemberName::method_offset()), rscratch1);
+ __ access_load_at(T_ADDRESS, IN_HEAP, rbx,
+ Address(rbx, java_lang_invoke_ResolvedMethodName::vmtarget_offset()),
+ noreg, noreg);
+ __ movptr(Address(r15_thread, JavaThread::callee_target_offset()), rbx); // just in case callee is deoptimized
+
+ __ ret(0);
+
+ return start;
+}
+
address StubGenerator::generate_lookup_secondary_supers_table_stub(u1 super_klass_index) {
StubCodeMark mark(this, "StubRoutines", "lookup_secondary_supers_table");
@@ -4087,17 +3920,6 @@ void StubGenerator::generate_initial_stubs() {
StubRoutines::x86::_double_sign_mask = generate_fp_mask("double_sign_mask", 0x7FFFFFFFFFFFFFFF);
StubRoutines::x86::_double_sign_flip = generate_fp_mask("double_sign_flip", 0x8000000000000000);
- // Build this early so it's available for the interpreter.
- StubRoutines::_throw_StackOverflowError_entry =
- generate_throw_exception("StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::
- throw_StackOverflowError));
- StubRoutines::_throw_delayed_StackOverflowError_entry =
- generate_throw_exception("delayed StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::
- throw_delayed_StackOverflowError));
if (UseCRC32Intrinsics) {
// set table address before stub generation which use it
StubRoutines::_crc_table_adr = (address)StubRoutines::x86::_crc_table;
@@ -4131,43 +3953,11 @@ void StubGenerator::generate_continuation_stubs() {
StubRoutines::_cont_thaw = generate_cont_thaw();
StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier();
StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception();
-
- JFR_ONLY(generate_jfr_stubs();)
}
-#if INCLUDE_JFR
-void StubGenerator::generate_jfr_stubs() {
- StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint();
- StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point();
- StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease();
- StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point();
-}
-#endif
-
void StubGenerator::generate_final_stubs() {
// Generates the rest of stubs and initializes the entry points
- // These entry points require SharedInfo::stack0 to be set up in
- // non-core builds and need to be relocatable, so they each
- // fabricate a RuntimeStub internally.
- StubRoutines::_throw_AbstractMethodError_entry =
- generate_throw_exception("AbstractMethodError throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::
- throw_AbstractMethodError));
-
- StubRoutines::_throw_IncompatibleClassChangeError_entry =
- generate_throw_exception("IncompatibleClassChangeError throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::
- throw_IncompatibleClassChangeError));
-
- StubRoutines::_throw_NullPointerException_at_call_entry =
- generate_throw_exception("NullPointerException at call throw_exception",
- CAST_FROM_FN_PTR(address,
- SharedRuntime::
- throw_NullPointerException_at_call));
-
// support for verify_oop (must happen after universe_init)
if (VerifyOops) {
StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop();
@@ -4190,6 +3980,7 @@ void StubGenerator::generate_final_stubs() {
}
StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler();
+ StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target();
}
void StubGenerator::generate_compiler_stubs() {
@@ -4395,41 +4186,41 @@ void StubGenerator::generate_compiler_stubs() {
log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "jsvml" JNI_LIB_SUFFIX, p2i(libjsvml));
if (UseAVX > 2) {
- for (int op = 0; op < VectorSupport::NUM_SVML_OP; op++) {
- int vop = VectorSupport::VECTOR_OP_SVML_START + op;
+ for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) {
+ int vop = VectorSupport::VECTOR_OP_MATH_START + op;
if ((!VM_Version::supports_avx512dq()) &&
(vop == VectorSupport::VECTOR_OP_LOG || vop == VectorSupport::VECTOR_OP_LOG10 || vop == VectorSupport::VECTOR_OP_POW)) {
continue;
}
- snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf16_ha_z0", VectorSupport::svmlname[op]);
+ snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf16_ha_z0", VectorSupport::mathname[op]);
StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_512][op] = (address)os::dll_lookup(libjsvml, ebuf);
- snprintf(ebuf, sizeof(ebuf), "__jsvml_%s8_ha_z0", VectorSupport::svmlname[op]);
+ snprintf(ebuf, sizeof(ebuf), "__jsvml_%s8_ha_z0", VectorSupport::mathname[op]);
StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_512][op] = (address)os::dll_lookup(libjsvml, ebuf);
}
}
const char* avx_sse_str = (UseAVX >= 2) ? "l9" : ((UseAVX == 1) ? "e9" : "ex");
- for (int op = 0; op < VectorSupport::NUM_SVML_OP; op++) {
- int vop = VectorSupport::VECTOR_OP_SVML_START + op;
+ for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) {
+ int vop = VectorSupport::VECTOR_OP_MATH_START + op;
if (vop == VectorSupport::VECTOR_OP_POW) {
continue;
}
- snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf4_ha_%s", VectorSupport::svmlname[op], avx_sse_str);
+ snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf4_ha_%s", VectorSupport::mathname[op], avx_sse_str);
StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_64][op] = (address)os::dll_lookup(libjsvml, ebuf);
- snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf4_ha_%s", VectorSupport::svmlname[op], avx_sse_str);
+ snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf4_ha_%s", VectorSupport::mathname[op], avx_sse_str);
StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libjsvml, ebuf);
- snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf8_ha_%s", VectorSupport::svmlname[op], avx_sse_str);
+ snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf8_ha_%s", VectorSupport::mathname[op], avx_sse_str);
StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_256][op] = (address)os::dll_lookup(libjsvml, ebuf);
- snprintf(ebuf, sizeof(ebuf), "__jsvml_%s1_ha_%s", VectorSupport::svmlname[op], avx_sse_str);
+ snprintf(ebuf, sizeof(ebuf), "__jsvml_%s1_ha_%s", VectorSupport::mathname[op], avx_sse_str);
StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_64][op] = (address)os::dll_lookup(libjsvml, ebuf);
- snprintf(ebuf, sizeof(ebuf), "__jsvml_%s2_ha_%s", VectorSupport::svmlname[op], avx_sse_str);
+ snprintf(ebuf, sizeof(ebuf), "__jsvml_%s2_ha_%s", VectorSupport::mathname[op], avx_sse_str);
StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libjsvml, ebuf);
- snprintf(ebuf, sizeof(ebuf), "__jsvml_%s4_ha_%s", VectorSupport::svmlname[op], avx_sse_str);
+ snprintf(ebuf, sizeof(ebuf), "__jsvml_%s4_ha_%s", VectorSupport::mathname[op], avx_sse_str);
StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_256][op] = (address)os::dll_lookup(libjsvml, ebuf);
}
}
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp
index 374679750a4..7280e9fbe95 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp
@@ -376,11 +376,22 @@ class StubGenerator: public StubCodeGenerator {
void roundDec(XMMRegister key, int rnum);
void lastroundDec(XMMRegister key, int rnum);
void gfmul_avx512(XMMRegister ghash, XMMRegister hkey);
- void generateHtbl_48_block_zmm(Register htbl, Register avx512_subkeyHtbl, Register rscratch);
- void ghash16_encrypt16_parallel(Register key, Register subkeyHtbl, XMMRegister ctr_blockx,
- XMMRegister aad_hashx, Register in, Register out, Register data, Register pos, bool reduction,
- XMMRegister addmask, bool no_ghash_input, Register rounds, Register ghash_pos,
- bool final_reduction, int index, XMMRegister counter_inc_mask);
+ void ghash16_encrypt_parallel16_avx512(Register in, Register out, Register ct, Register pos, Register avx512_subkeyHtbl,
+ Register CTR_CHECK, Register NROUNDS, Register key, XMMRegister CTR, XMMRegister GHASH,
+ XMMRegister ADDBE_4x4, XMMRegister ADDBE_1234, XMMRegister ADD_1234, XMMRegister SHUF_MASK,
+ bool hk_broadcast, bool is_hash_start, bool do_hash_reduction, bool do_hash_hxor,
+ bool no_ghash_in, int ghashin_offset, int aesout_offset, int hashkey_offset);
+ void generateHtbl_32_blocks_avx512(Register htbl, Register avx512_htbl);
+ void initial_blocks_16_avx512(Register in, Register out, Register ct, Register pos, Register key, Register avx512_subkeyHtbl,
+ Register CTR_CHECK, Register rounds, XMMRegister CTR, XMMRegister GHASH, XMMRegister ADDBE_4x4,
+ XMMRegister ADDBE_1234, XMMRegister ADD_1234, XMMRegister SHUF_MASK, int stack_offset);
+ void gcm_enc_dec_last_avx512(Register len, Register in, Register pos, XMMRegister HASH, XMMRegister SHUFM, Register subkeyHtbl,
+ int ghashin_offset, int hashkey_offset, bool start_ghash, bool do_reduction);
+ void ghash16_avx512(bool start_ghash, bool do_reduction, bool uload_shuffle, bool hk_broadcast, bool do_hxor,
+ Register in, Register pos, Register subkeyHtbl, XMMRegister HASH, XMMRegister SHUFM, int in_offset,
+ int in_disp, int displacement, int hashkey_offset);
+ void aesgcm_avx512(Register in, Register len, Register ct, Register out, Register key,
+ Register state, Register subkeyHtbl, Register avx512_subkeyHtbl, Register counter);
// AVX2 AES-GCM related functions
void initial_blocks_avx2(XMMRegister ctr, Register rounds, Register key, Register len,
Register in, Register out, Register ct, XMMRegister aad_hashx, Register pos);
@@ -546,6 +557,7 @@ class StubGenerator: public StubCodeGenerator {
address generate_libmSin();
address generate_libmCos();
address generate_libmTan();
+ address generate_libmTanh();
address generate_libmExp();
address generate_libmPow();
address generate_libmLog();
@@ -586,16 +598,6 @@ class StubGenerator: public StubCodeGenerator {
address generate_cont_returnBarrier();
address generate_cont_returnBarrier_exception();
-#if INCLUDE_JFR
- void generate_jfr_stubs();
- // For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
- // It returns a jobject handle to the event writer.
- // The handle is dereferenced and the return value is the event writer oop.
- RuntimeStub* generate_jfr_write_checkpoint();
- // For c2: call to runtime to return a buffer lease.
- RuntimeStub* generate_jfr_return_lease();
-#endif // INCLUDE_JFR
-
// Continuation point for throwing of implicit exceptions that are
// not handled in the current activation. Fabricates an exception
// oop and initiates normal exception dispatching in this
@@ -618,6 +620,7 @@ class StubGenerator: public StubCodeGenerator {
// shared exception handler for FFM upcall stubs
address generate_upcall_stub_exception_handler();
+ address generate_upcall_stub_load_target();
// Specialized stub implementations for UseSecondarySupersTable.
address generate_lookup_secondary_supers_table_stub(u1 super_klass_index);
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp
index 9744169498c..f14d368c376 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2019, 2023, Intel Corporation. All rights reserved.
+* Copyright (c) 2019, 2024, Intel Corporation. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -172,6 +172,38 @@ static address ghash_polynomial_two_one_addr() {
return (address)GHASH_POLYNOMIAL_TWO_ONE;
}
+// This mask is used for incrementing counter value
+ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_ADDBE_4444[] = {
+ 0x0000000000000000ULL, 0x0400000000000000ULL,
+ 0x0000000000000000ULL, 0x0400000000000000ULL,
+ 0x0000000000000000ULL, 0x0400000000000000ULL,
+ 0x0000000000000000ULL, 0x0400000000000000ULL,
+};
+static address counter_mask_addbe_4444_addr() {
+ return (address)COUNTER_MASK_ADDBE_4444;
+}
+
+// This mask is used for incrementing counter value
+ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_ADDBE_1234[] = {
+ 0x0000000000000000ULL, 0x0100000000000000ULL,
+ 0x0000000000000000ULL, 0x0200000000000000ULL,
+ 0x0000000000000000ULL, 0x0300000000000000ULL,
+ 0x0000000000000000ULL, 0x0400000000000000ULL,
+};
+static address counter_mask_addbe_1234_addr() {
+ return (address)COUNTER_MASK_ADDBE_1234;
+}
+
+// This mask is used for incrementing counter value
+ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_ADD_1234[] = {
+ 0x0000000000000001ULL, 0x0000000000000000ULL,
+ 0x0000000000000002ULL, 0x0000000000000000ULL,
+ 0x0000000000000003ULL, 0x0000000000000000ULL,
+ 0x0000000000000004ULL, 0x0000000000000000ULL,
+};
+static address counter_mask_add_1234_addr() {
+ return (address)COUNTER_MASK_ADD_1234;
+}
// AES intrinsic stubs
@@ -209,10 +241,10 @@ void StubGenerator::generate_aes_stubs() {
// len = rdx (c_rarg1) | rdi (c_rarg1)
// ct = r8 (c_rarg2) | rdx (c_rarg2)
// out = r9 (c_rarg3) | rcx (c_rarg3)
-// key = r10 | r8 (c_rarg4)
-// state = r13 | r9 (c_rarg5)
-// subkeyHtbl = r14 | r11
-// counter = rsi | r12
+// key = rsi | r8 (c_rarg4)
+// state = rdi | r9 (c_rarg5)
+// subkeyHtbl = r10 | r10
+// counter = r11 | r11
//
// Output:
// rax - number of processed bytes
@@ -230,31 +262,31 @@ address StubGenerator::generate_galoisCounterMode_AESCrypt() {
const Register key = c_rarg4;
const Register state = c_rarg5;
const Address subkeyH_mem(rbp, 2 * wordSize);
- const Register subkeyHtbl = r11;
- const Register avx512_subkeyHtbl = r13;
+ const Register subkeyHtbl = r10;
+ const Register avx512_subkeyHtbl = r12;
const Address counter_mem(rbp, 3 * wordSize);
- const Register counter = r12;
+ const Register counter = r11;
#else
const Address key_mem(rbp, 6 * wordSize);
- const Register key = r10;
+ const Register key = rsi;
const Address state_mem(rbp, 7 * wordSize);
- const Register state = r13;
+ const Register state = rdi;
const Address subkeyH_mem(rbp, 8 * wordSize);
- const Register subkeyHtbl = r14;
+ const Register subkeyHtbl = r10;
const Register avx512_subkeyHtbl = r12;
const Address counter_mem(rbp, 9 * wordSize);
- const Register counter = rsi;
+ const Register counter = r11;
#endif
__ enter();
// Save state before entering routine
- __ push(r12);
- __ push(r13);
- __ push(r14);
- __ push(r15);
- __ push(rbx);
+ __ push(r12);//holds pointer to avx512_subkeyHtbl
+ __ push(r14);//holds CTR_CHECK value to check for overflow
+ __ push(r15);//holds number of rounds
+ __ push(rbx);//scratch register
#ifdef _WIN64
// on win64, fill len_reg from stack position
__ push(rsi);
+ __ push(rdi);
__ movptr(key, key_mem);
__ movptr(state, state_mem);
#endif
@@ -262,24 +294,24 @@ address StubGenerator::generate_galoisCounterMode_AESCrypt() {
__ movptr(counter, counter_mem);
// Align stack
__ andq(rsp, -64);
- __ subptr(rsp, 96 * longSize); // Create space on the stack for htbl entries
+ __ subptr(rsp, 200 * longSize); // Create space on the stack for 64 htbl entries and 8 zmm AES entries
__ movptr(avx512_subkeyHtbl, rsp);
- aesgcm_encrypt(in, len, ct, out, key, state, subkeyHtbl, avx512_subkeyHtbl, counter);
+ aesgcm_avx512(in, len, ct, out, key, state, subkeyHtbl, avx512_subkeyHtbl, counter);
__ vzeroupper();
// Restore state before leaving routine
#ifdef _WIN64
__ lea(rsp, Address(rbp, -6 * wordSize));
+ __ pop(rdi);
__ pop(rsi);
#else
- __ lea(rsp, Address(rbp, -5 * wordSize));
+ __ lea(rsp, Address(rbp, -4 * wordSize));
#endif
__ pop(rbx);
__ pop(r15);
__ pop(r14);
- __ pop(r13);
__ pop(r12);
__ leave(); // required for proper stackwalking of RuntimeStub frame
@@ -2708,87 +2740,100 @@ void StubGenerator::gfmul_avx512(XMMRegister GH, XMMRegister HK) {
__ vpternlogq(GH, 0x96, TMP1, TMP2, Assembler::AVX_512bit);
}
-void StubGenerator::generateHtbl_48_block_zmm(Register htbl, Register avx512_htbl, Register rscratch) {
+// Holds 64 Htbl entries, 32 HKey and 32 HkKey (derived from HKey)
+void StubGenerator::generateHtbl_32_blocks_avx512(Register htbl, Register avx512_htbl) {
const XMMRegister HK = xmm6;
- const XMMRegister ZT5 = xmm4;
- const XMMRegister ZT7 = xmm7;
- const XMMRegister ZT8 = xmm8;
-
- Label GFMUL_AVX512;
+ const XMMRegister ZT1 = xmm0, ZT2 = xmm1, ZT3 = xmm2, ZT4 = xmm3;
+ const XMMRegister ZT5 = xmm4, ZT6 = xmm5, ZT7 = xmm7, ZT8 = xmm8;
+ const XMMRegister ZT10 = xmm10, ZT11 = xmm11, ZT12 = xmm12;
__ movdqu(HK, Address(htbl, 0));
- __ movdqu(xmm10, ExternalAddress(ghash_long_swap_mask_addr()), rscratch);
- __ vpshufb(HK, HK, xmm10, Assembler::AVX_128bit);
-
- __ movdqu(xmm11, ExternalAddress(ghash_polynomial_addr()), rscratch);
- __ movdqu(xmm12, ExternalAddress(ghash_polynomial_two_one_addr()), rscratch);
+ __ movdqu(ZT10, ExternalAddress(ghash_long_swap_mask_addr()), r15);
+ __ vpshufb(HK, HK, ZT10, Assembler::AVX_128bit);
+ __ movdqu(ZT11, ExternalAddress(ghash_polynomial_addr()), r15);
+ __ movdqu(ZT12, ExternalAddress(ghash_polynomial_two_one_addr()), r15);
// Compute H ^ 2 from the input subkeyH
- __ movdqu(xmm2, xmm6);
- __ vpsllq(xmm6, xmm6, 1, Assembler::AVX_128bit);
- __ vpsrlq(xmm2, xmm2, 63, Assembler::AVX_128bit);
- __ movdqu(xmm1, xmm2);
- __ vpslldq(xmm2, xmm2, 8, Assembler::AVX_128bit);
- __ vpsrldq(xmm1, xmm1, 8, Assembler::AVX_128bit);
- __ vpor(xmm6, xmm6, xmm2, Assembler::AVX_128bit);
+ __ movdqu(ZT3, HK);
+ __ vpsllq(HK, HK, 1, Assembler::AVX_128bit);
+ __ vpsrlq(ZT3, ZT3, 63, Assembler::AVX_128bit);
+ __ movdqu(ZT2, ZT3);
+ __ vpslldq(ZT3, ZT3, 8, Assembler::AVX_128bit);
+ __ vpsrldq(ZT2, ZT2, 8, Assembler::AVX_128bit);
+ __ vpor(HK, HK, ZT3, Assembler::AVX_128bit);
+ __ vpshufd(ZT3, ZT2, 0x24, Assembler::AVX_128bit);
+ __ vpcmpeqd(ZT3, ZT3, ZT12, Assembler::AVX_128bit);
+ __ vpand(ZT3, ZT3, ZT11, Assembler::AVX_128bit);
+ __ vpxor(HK, HK, ZT3, Assembler::AVX_128bit);
+ __ movdqu(Address(avx512_htbl, 16 * 31), HK); // H ^ 2
- __ vpshufd(xmm2, xmm1, 0x24, Assembler::AVX_128bit);
- __ vpcmpeqd(xmm2, xmm2, xmm12, Assembler::AVX_128bit);
- __ vpand(xmm2, xmm2, xmm11, Assembler::AVX_128bit);
- __ vpxor(xmm6, xmm6, xmm2, Assembler::AVX_128bit);
- __ movdqu(Address(avx512_htbl, 16 * 47), xmm6); // H ^ 2
- // Compute the remaining three powers of H using XMM registers and all following powers using ZMM
__ movdqu(ZT5, HK);
- __ vinserti32x4(ZT7, ZT7, HK, 3);
+ __ evinserti64x2(ZT7, ZT7, HK, 3, Assembler::AVX_512bit);
+ //calculate HashKey ^ 2 << 1 mod poly
gfmul_avx512(ZT5, HK);
- __ movdqu(Address(avx512_htbl, 16 * 46), ZT5); // H ^ 2 * 2
- __ vinserti32x4(ZT7, ZT7, ZT5, 2);
+ __ movdqu(Address(avx512_htbl, 16 * 30), ZT5);
+ __ evinserti64x2(ZT7, ZT7, ZT5, 2, Assembler::AVX_512bit);
+ //calculate HashKey ^ 3 << 1 mod poly
gfmul_avx512(ZT5, HK);
- __ movdqu(Address(avx512_htbl, 16 * 45), ZT5); // H ^ 2 * 3
- __ vinserti32x4(ZT7, ZT7, ZT5, 1);
+ __ movdqu(Address(avx512_htbl, 16 * 29), ZT5);
+ __ evinserti64x2(ZT7, ZT7, ZT5, 1, Assembler::AVX_512bit);
+ //calculate HashKey ^ 4 << 1 mod poly
gfmul_avx512(ZT5, HK);
- __ movdqu(Address(avx512_htbl, 16 * 44), ZT5); // H ^ 2 * 4
- __ vinserti32x4(ZT7, ZT7, ZT5, 0);
-
- __ evshufi64x2(ZT5, ZT5, ZT5, 0x00, Assembler::AVX_512bit);
- __ evmovdquq(ZT8, ZT7, Assembler::AVX_512bit);
- gfmul_avx512(ZT7, ZT5);
- __ evmovdquq(Address(avx512_htbl, 16 * 40), ZT7, Assembler::AVX_512bit);
- __ evshufi64x2(ZT5, ZT7, ZT7, 0x00, Assembler::AVX_512bit);
- gfmul_avx512(ZT8, ZT5);
- __ evmovdquq(Address(avx512_htbl, 16 * 36), ZT8, Assembler::AVX_512bit);
+ __ movdqu(Address(avx512_htbl, 16 * 28), ZT5);
+ __ evinserti64x2(ZT7, ZT7, ZT5, 0, Assembler::AVX_512bit);
+ // ZT5 amd ZT7 to be cleared(hash key)
+ //calculate HashKeyK = HashKey x POLY
+ __ evmovdquq(xmm11, ExternalAddress(ghash_polynomial_addr()), Assembler::AVX_512bit, r15);
+ __ evpclmulqdq(ZT1, ZT7, xmm11, 0x10, Assembler::AVX_512bit);
+ __ vpshufd(ZT2, ZT7, 78, Assembler::AVX_512bit);
+ __ evpxorq(ZT1, ZT1, ZT2, Assembler::AVX_512bit);
+ __ evmovdquq(Address(avx512_htbl, 16 * 60), ZT1, Assembler::AVX_512bit);
+ //**ZT1 amd ZT2 to be cleared(hash key)
+
+ //switch to 4x128 - bit computations now
+ __ evshufi64x2(ZT5, ZT5, ZT5, 0x00, Assembler::AVX_512bit); //;; broadcast HashKey ^ 4 across all ZT5
+ __ evmovdquq(ZT8, ZT7, Assembler::AVX_512bit);//; save HashKey ^ 4 to HashKey ^ 1 in ZT8
+ //**ZT8 to be cleared(hash key)
+
+ //calculate HashKey ^ 5 << 1 mod poly, HashKey ^ 6 << 1 mod poly, ... HashKey ^ 8 << 1 mod poly
gfmul_avx512(ZT7, ZT5);
- __ evmovdquq(Address(avx512_htbl, 16 * 32), ZT7, Assembler::AVX_512bit);
- gfmul_avx512(ZT8, ZT5);
- __ evmovdquq(Address(avx512_htbl, 16 * 28), ZT8, Assembler::AVX_512bit);
- gfmul_avx512(ZT7, ZT5);
- __ evmovdquq(Address(avx512_htbl, 16 * 24), ZT7, Assembler::AVX_512bit);
- gfmul_avx512(ZT8, ZT5);
- __ evmovdquq(Address(avx512_htbl, 16 * 20), ZT8, Assembler::AVX_512bit);
- gfmul_avx512(ZT7, ZT5);
- __ evmovdquq(Address(avx512_htbl, 16 * 16), ZT7, Assembler::AVX_512bit);
- gfmul_avx512(ZT8, ZT5);
- __ evmovdquq(Address(avx512_htbl, 16 * 12), ZT8, Assembler::AVX_512bit);
- gfmul_avx512(ZT7, ZT5);
- __ evmovdquq(Address(avx512_htbl, 16 * 8), ZT7, Assembler::AVX_512bit);
- gfmul_avx512(ZT8, ZT5);
- __ evmovdquq(Address(avx512_htbl, 16 * 4), ZT8, Assembler::AVX_512bit);
- gfmul_avx512(ZT7, ZT5);
- __ evmovdquq(Address(avx512_htbl, 16 * 0), ZT7, Assembler::AVX_512bit);
- __ ret(0);
-}
-
-#define vclmul_reduce(out, poly, hi128, lo128, tmp0, tmp1) \
-__ evpclmulqdq(tmp0, poly, lo128, 0x01, Assembler::AVX_512bit); \
-__ vpslldq(tmp0, tmp0, 8, Assembler::AVX_512bit); \
-__ evpxorq(tmp0, lo128, tmp0, Assembler::AVX_512bit); \
-__ evpclmulqdq(tmp1, poly, tmp0, 0x00, Assembler::AVX_512bit); \
-__ vpsrldq(tmp1, tmp1, 4, Assembler::AVX_512bit); \
-__ evpclmulqdq(out, poly, tmp0, 0x10, Assembler::AVX_512bit); \
-__ vpslldq(out, out, 4, Assembler::AVX_512bit); \
-__ vpternlogq(out, 0x96, tmp1, hi128, Assembler::AVX_512bit); \
+ __ evmovdquq(Address(avx512_htbl, 16 * 24), ZT7, Assembler::AVX_512bit);//; HashKey ^ 8 to HashKey ^ 5 in ZT7 now
+
+ //calculate HashKeyX = HashKey x POLY
+ __ evpclmulqdq(ZT1, ZT7, xmm11, 0x10, Assembler::AVX_512bit);
+ __ vpshufd(ZT2, ZT7, 78, Assembler::AVX_512bit);
+ __ evpxorq(ZT1, ZT1, ZT2, Assembler::AVX_512bit);
+ __ evmovdquq(Address(avx512_htbl, 16 * 56), ZT1, Assembler::AVX_512bit);
+
+ __ evshufi64x2(ZT5, ZT7, ZT7, 0x00, Assembler::AVX_512bit);//;; broadcast HashKey ^ 8 across all ZT5
+
+ for (int i = 20, j = 52; i > 0;) {
+ gfmul_avx512(ZT8, ZT5);
+ __ evmovdquq(Address(avx512_htbl, 16 * i), ZT8, Assembler::AVX_512bit);
+ //calculate HashKeyK = HashKey x POLY
+ __ evpclmulqdq(ZT1, ZT8, xmm11, 0x10, Assembler::AVX_512bit);
+ __ vpshufd(ZT2, ZT8, 78, Assembler::AVX_512bit);
+ __ evpxorq(ZT1, ZT1, ZT2, Assembler::AVX_512bit);
+ __ evmovdquq(Address(avx512_htbl, 16 * j), ZT1, Assembler::AVX_512bit);
+
+ i -= 4;
+ j -= 4;
+ //compute HashKey ^ (8 + n), HashKey ^ (7 + n), ... HashKey ^ (5 + n)
+ gfmul_avx512(ZT7, ZT5);
+ __ evmovdquq(Address(avx512_htbl, 16 * i), ZT7, Assembler::AVX_512bit);
+
+ //calculate HashKeyK = HashKey x POLY
+ __ evpclmulqdq(ZT1, ZT7, xmm11, 0x10, Assembler::AVX_512bit);
+ __ vpshufd(ZT2, ZT7, 78, Assembler::AVX_512bit);
+ __ evpxorq(ZT1, ZT1, ZT2, Assembler::AVX_512bit);
+ __ evmovdquq(Address(avx512_htbl, 16 * j), ZT1, Assembler::AVX_512bit);
+
+ i -= 4;
+ j -= 4;
+ }
+ }
#define vhpxori4x128(reg, tmp) \
__ vextracti64x4(tmp, reg, 1); \
@@ -2820,21 +2865,17 @@ __ evmovdquq(dst2, Address(src, position, Address::times_1, 1 * 64), Assembler::
__ evmovdquq(dst3, Address(src, position, Address::times_1, 2 * 64), Assembler::AVX_512bit); \
__ evmovdquq(dst4, Address(src, position, Address::times_1, 3 * 64), Assembler::AVX_512bit); \
-#define carrylessMultiply(dst00, dst01, dst10, dst11, ghdata, hkey) \
-__ evpclmulqdq(dst00, ghdata, hkey, 0x00, Assembler::AVX_512bit); \
-__ evpclmulqdq(dst01, ghdata, hkey, 0x01, Assembler::AVX_512bit); \
-__ evpclmulqdq(dst10, ghdata, hkey, 0x10, Assembler::AVX_512bit); \
-__ evpclmulqdq(dst11, ghdata, hkey, 0x11, Assembler::AVX_512bit); \
-
-#define shuffleExorRnd1Key(dst0, dst1, dst2, dst3, shufmask, rndkey) \
-__ vpshufb(dst0, dst0, shufmask, Assembler::AVX_512bit); \
-__ evpxorq(dst0, dst0, rndkey, Assembler::AVX_512bit); \
-__ vpshufb(dst1, dst1, shufmask, Assembler::AVX_512bit); \
-__ evpxorq(dst1, dst1, rndkey, Assembler::AVX_512bit); \
-__ vpshufb(dst2, dst2, shufmask, Assembler::AVX_512bit); \
-__ evpxorq(dst2, dst2, rndkey, Assembler::AVX_512bit); \
-__ vpshufb(dst3, dst3, shufmask, Assembler::AVX_512bit); \
-__ evpxorq(dst3, dst3, rndkey, Assembler::AVX_512bit); \
+#define carrylessMultiply(dst00, dst01, dst10, dst11, ghdata, hkey2, hkey1) \
+__ evpclmulqdq(dst00, ghdata, hkey2, 0x00, Assembler::AVX_512bit); \
+__ evpclmulqdq(dst01, ghdata, hkey2, 0x10, Assembler::AVX_512bit); \
+__ evpclmulqdq(dst10, ghdata, hkey1, 0x01, Assembler::AVX_512bit); \
+__ evpclmulqdq(dst11, ghdata, hkey1, 0x11, Assembler::AVX_512bit); \
+
+#define shuffle(dst0, dst1, dst2, dst3, src0, src1, src2, src3, shufmask) \
+__ vpshufb(dst0, src0, shufmask, Assembler::AVX_512bit); \
+__ vpshufb(dst1, src1, shufmask, Assembler::AVX_512bit); \
+__ vpshufb(dst2, src2, shufmask, Assembler::AVX_512bit); \
+__ vpshufb(dst3, src3, shufmask, Assembler::AVX_512bit); \
#define xorBeforeStore(dst0, dst1, dst2, dst3, src0, src1, src2, src3) \
__ evpxorq(dst0, dst0, src0, Assembler::AVX_512bit); \
@@ -2848,211 +2889,462 @@ __ vpternlogq(dst1, 0x96, src12, src13, Assembler::AVX_512bit); \
__ vpternlogq(dst2, 0x96, src22, src23, Assembler::AVX_512bit); \
__ vpternlogq(dst3, 0x96, src32, src33, Assembler::AVX_512bit); \
-void StubGenerator::ghash16_encrypt16_parallel(Register key, Register subkeyHtbl, XMMRegister ctr_blockx, XMMRegister aad_hashx,
- Register in, Register out, Register data, Register pos, bool first_time_reduction, XMMRegister addmask, bool ghash_input, Register rounds,
- Register ghash_pos, bool final_reduction, int i, XMMRegister counter_inc_mask) {
- Label AES_192, AES_256, LAST_AES_RND;
+//schoolbook multiply of 16 blocks(8 x 16 bytes)
+//it is assumed that data read is already shuffledand
+void StubGenerator::ghash16_avx512(bool start_ghash, bool do_reduction, bool uload_shuffle, bool hk_broadcast, bool do_hxor,
+ Register in, Register pos, Register subkeyHtbl, XMMRegister HASH, XMMRegister SHUFM, int in_offset,
+ int in_disp, int displacement, int hashkey_offset) {
const XMMRegister ZTMP0 = xmm0;
const XMMRegister ZTMP1 = xmm3;
const XMMRegister ZTMP2 = xmm4;
const XMMRegister ZTMP3 = xmm5;
+ const XMMRegister ZTMP4 = xmm6;
const XMMRegister ZTMP5 = xmm7;
const XMMRegister ZTMP6 = xmm10;
const XMMRegister ZTMP7 = xmm11;
const XMMRegister ZTMP8 = xmm12;
const XMMRegister ZTMP9 = xmm13;
- const XMMRegister ZTMP10 = xmm15;
- const XMMRegister ZTMP11 = xmm16;
- const XMMRegister ZTMP12 = xmm17;
+ const XMMRegister ZTMPA = xmm26;
+ const XMMRegister ZTMPB = xmm23;
+ const XMMRegister GH = xmm24;
+ const XMMRegister GL = xmm25;
+ const int hkey_gap = 16 * 32;
+
+ if (uload_shuffle) {
+ __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp), Assembler::AVX_512bit);
+ __ vpshufb(ZTMP9, ZTMP9, SHUFM, Assembler::AVX_512bit);
+ } else {
+ __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp), Assembler::AVX_512bit);
+ }
- const XMMRegister ZTMP13 = xmm19;
- const XMMRegister ZTMP14 = xmm20;
- const XMMRegister ZTMP15 = xmm21;
- const XMMRegister ZTMP16 = xmm30;
- const XMMRegister ZTMP17 = xmm31;
- const XMMRegister ZTMP18 = xmm1;
- const XMMRegister ZTMP19 = xmm2;
- const XMMRegister ZTMP20 = xmm8;
- const XMMRegister ZTMP21 = xmm22;
- const XMMRegister ZTMP22 = xmm23;
+ if (start_ghash) {
+ __ evpxorq(ZTMP9, ZTMP9, HASH, Assembler::AVX_512bit);
+ }
+ if (hk_broadcast) {
+ __ evbroadcastf64x2(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 0 * 64), Assembler::AVX_512bit);
+ __ evbroadcastf64x2(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 0 * 64), Assembler::AVX_512bit);
+ } else {
+ __ evmovdquq(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 0 * 64), Assembler::AVX_512bit);
+ __ evmovdquq(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 0 * 64), Assembler::AVX_512bit);
+ }
+
+ carrylessMultiply(ZTMP0, ZTMP1, ZTMP2, ZTMP3, ZTMP9, ZTMPA, ZTMP8);
+
+ //ghash blocks 4 - 7
+ if (uload_shuffle) {
+ __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 64), Assembler::AVX_512bit);
+ __ vpshufb(ZTMP9, ZTMP9, SHUFM, Assembler::AVX_512bit);
+ } else {
+ __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 64), Assembler::AVX_512bit);
+ }
+
+ if (hk_broadcast) {
+ __ evbroadcastf64x2(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 1 * 64), Assembler::AVX_512bit);;
+ __ evbroadcastf64x2(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 1 * 64), Assembler::AVX_512bit);
+ } else {
+ __ evmovdquq(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 1 * 64), Assembler::AVX_512bit);
+ __ evmovdquq(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 1 * 64), Assembler::AVX_512bit);
+ }
+
+ carrylessMultiply(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP9, ZTMPA, ZTMP8);
+
+ //update sums
+ if (start_ghash) {
+ __ evpxorq(GL, ZTMP0, ZTMP2, Assembler::AVX_512bit);//T2 = THL + TLL
+ __ evpxorq(GH, ZTMP1, ZTMP3, Assembler::AVX_512bit);//T1 = THH + TLH
+ } else { //mid, end, end_reduce
+ __ vpternlogq(GL, 0x96, ZTMP0, ZTMP2, Assembler::AVX_512bit);//T2 = THL + TLL
+ __ vpternlogq(GH, 0x96, ZTMP1, ZTMP3, Assembler::AVX_512bit);//T1 = THH + TLH
+ }
+ //ghash blocks 8 - 11
+ if (uload_shuffle) {
+ __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 128), Assembler::AVX_512bit);
+ __ vpshufb(ZTMP9, ZTMP9, SHUFM, Assembler::AVX_512bit);
+ } else {
+ __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 128), Assembler::AVX_512bit);
+ }
+ if (hk_broadcast) {
+ __ evbroadcastf64x2(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 2 * 64), Assembler::AVX_512bit);
+ __ evbroadcastf64x2(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 2 * 64), Assembler::AVX_512bit);
+ } else {
+ __ evmovdquq(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 2 * 64), Assembler::AVX_512bit);
+ __ evmovdquq(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 2 * 64), Assembler::AVX_512bit);
+ }
+
+ carrylessMultiply(ZTMP0, ZTMP1, ZTMP2, ZTMP3, ZTMP9, ZTMPA, ZTMP8);
+
+ //update sums
+ __ vpternlogq(GL, 0x96, ZTMP6, ZTMP4, Assembler::AVX_512bit);//T2 = THL + TLL
+ __ vpternlogq(GH, 0x96, ZTMP7, ZTMP5, Assembler::AVX_512bit);//T1 = THH + TLH
+ //ghash blocks 12 - 15
+ if (uload_shuffle) {
+ __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 192), Assembler::AVX_512bit);
+ __ vpshufb(ZTMP9, ZTMP9, SHUFM, Assembler::AVX_512bit);
+ } else {
+ __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 192), Assembler::AVX_512bit);
+ }
+
+ if (hk_broadcast) {
+ __ evbroadcastf64x2(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 3 * 64), Assembler::AVX_512bit);
+ __ evbroadcastf64x2(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 3 * 64), Assembler::AVX_512bit);
+ } else {
+ __ evmovdquq(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 3 * 64), Assembler::AVX_512bit);
+ __ evmovdquq(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 3 * 64), Assembler::AVX_512bit);
+ }
+ carrylessMultiply(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP9, ZTMPA, ZTMP8);
+
+ //update sums
+ xorGHASH(GL, GH, GL, GH, ZTMP0, ZTMP2, ZTMP1, ZTMP3, ZTMP6, ZTMP4, ZTMP7, ZTMP5);
+
+ if (do_reduction) {
+ //new reduction
+ __ evmovdquq(ZTMPB, ExternalAddress(ghash_polynomial_addr()), Assembler::AVX_512bit, rbx /*rscratch*/);
+ __ evpclmulqdq(HASH, GL, ZTMPB, 0x10, Assembler::AVX_512bit);
+ __ vpshufd(ZTMP0, GL, 78, Assembler::AVX_512bit);
+ __ vpternlogq(HASH, 0x96, GH, ZTMP0, Assembler::AVX_512bit);
+ if (do_hxor) {
+ vhpxori4x128(HASH, ZTMP0);
+ }
+ }
+}
- // Pre increment counters
- __ vpaddd(ZTMP0, ctr_blockx, counter_inc_mask, Assembler::AVX_512bit);
- __ vpaddd(ZTMP1, ZTMP0, counter_inc_mask, Assembler::AVX_512bit);
- __ vpaddd(ZTMP2, ZTMP1, counter_inc_mask, Assembler::AVX_512bit);
- __ vpaddd(ZTMP3, ZTMP2, counter_inc_mask, Assembler::AVX_512bit);
- // Save counter value
- __ evmovdquq(ctr_blockx, ZTMP3, Assembler::AVX_512bit);
-
- // Reuse ZTMP17 / ZTMP18 for loading AES Keys
- // Pre-load AES round keys
- ev_load_key(ZTMP17, key, 0, xmm29);
- ev_load_key(ZTMP18, key, 1 * 16, xmm29);
-
- // ZTMP19 & ZTMP20 used for loading hash key
- // Pre-load hash key
- __ evmovdquq(ZTMP19, Address(subkeyHtbl, i * 64), Assembler::AVX_512bit);
- __ evmovdquq(ZTMP20, Address(subkeyHtbl, ++i * 64), Assembler::AVX_512bit);
- // Load data for computing ghash
- __ evmovdquq(ZTMP21, Address(data, ghash_pos, Address::times_1, 0 * 64), Assembler::AVX_512bit);
- __ vpshufb(ZTMP21, ZTMP21, xmm24, Assembler::AVX_512bit);
-
- // Xor cipher block 0 with input ghash, if available
- if (ghash_input) {
- __ evpxorq(ZTMP21, ZTMP21, aad_hashx, Assembler::AVX_512bit);
+//Stitched GHASH of 16 blocks(with reduction) with encryption of 0 blocks
+void StubGenerator::gcm_enc_dec_last_avx512(Register len, Register in, Register pos, XMMRegister HASH, XMMRegister SHUFM, Register subkeyHtbl,
+ int ghashin_offset, int hashkey_offset, bool start_ghash, bool do_reduction) {
+ //there is 0 blocks to cipher so there are only 16 blocks for ghash and reduction
+ ghash16_avx512(start_ghash, do_reduction, false, false, true, in, pos, subkeyHtbl, HASH, SHUFM, ghashin_offset, 0, 0, hashkey_offset);
+}
+
+//Main GCM macro stitching cipher with GHASH
+//encrypts 16 blocks at a time
+//ghash the 16 previously encrypted ciphertext blocks
+void StubGenerator::ghash16_encrypt_parallel16_avx512(Register in, Register out, Register ct, Register pos, Register avx512_subkeyHtbl,
+ Register CTR_CHECK, Register NROUNDS, Register key, XMMRegister CTR_BE, XMMRegister GHASH_IN,
+ XMMRegister ADDBE_4x4, XMMRegister ADDBE_1234, XMMRegister ADD_1234, XMMRegister SHFMSK,
+ bool hk_broadcast, bool is_hash_start, bool do_hash_reduction, bool do_hash_hxor,
+ bool no_ghash_in, int ghashin_offset, int aesout_offset, int hashkey_offset) {
+ const XMMRegister B00_03 = xmm0;
+ const XMMRegister B04_07 = xmm3;
+ const XMMRegister B08_11 = xmm4;
+ const XMMRegister B12_15 = xmm5;
+ const XMMRegister THH1 = xmm6;
+ const XMMRegister THL1 = xmm7;
+ const XMMRegister TLH1 = xmm10;
+ const XMMRegister TLL1 = xmm11, THH2 = xmm12, THL2 = xmm13, TLH2 = xmm15;
+ const XMMRegister TLL2 = xmm16, THH3 = xmm17, THL3 = xmm19, TLH3 = xmm20;
+ const XMMRegister TLL3 = xmm21, DATA1 = xmm17, DATA2 = xmm19, DATA3 = xmm20, DATA4 = xmm21;
+ const XMMRegister AESKEY1 = xmm30, AESKEY2 = xmm31;
+ const XMMRegister GHKEY1 = xmm1, GHKEY2 = xmm18, GHDAT1 = xmm8, GHDAT2 = xmm22;
+ const XMMRegister ZT = xmm23, TO_REDUCE_L = xmm25, TO_REDUCE_H = xmm24;
+ const int hkey_gap = 16 * 32;
+
+ Label blocks_overflow, blocks_ok, skip_shuffle, cont, aes_256, aes_192, last_aes_rnd;
+
+ __ cmpb(CTR_CHECK, (256 - 16));
+ __ jcc(Assembler::aboveEqual, blocks_overflow);
+ __ vpaddd(B00_03, CTR_BE, ADDBE_1234, Assembler::AVX_512bit);
+ __ vpaddd(B04_07, B00_03, ADDBE_4x4, Assembler::AVX_512bit);
+ __ vpaddd(B08_11, B04_07, ADDBE_4x4, Assembler::AVX_512bit);
+ __ vpaddd(B12_15, B08_11, ADDBE_4x4, Assembler::AVX_512bit);
+ __ jmp(blocks_ok);
+ __ bind(blocks_overflow);
+ __ vpshufb(CTR_BE, CTR_BE, SHFMSK, Assembler::AVX_512bit);
+ __ evmovdquq(B12_15, ExternalAddress(counter_mask_linc4_addr()), Assembler::AVX_512bit, rbx /*rscratch*/);
+ __ vpaddd(B00_03, CTR_BE, ADD_1234, Assembler::AVX_512bit);
+ __ vpaddd(B04_07, B00_03, B12_15, Assembler::AVX_512bit);
+ __ vpaddd(B08_11, B04_07, B12_15, Assembler::AVX_512bit);
+ __ vpaddd(B12_15, B08_11, B12_15, Assembler::AVX_512bit);
+ shuffle(B00_03, B04_07, B08_11, B12_15, B00_03, B04_07, B08_11, B12_15, SHFMSK);
+
+ __ bind(blocks_ok);
+
+ //pre - load constants
+ ev_load_key(AESKEY1, key, 0, rbx);
+ if (!no_ghash_in) {
+ __ evpxorq(GHDAT1, GHASH_IN, Address(avx512_subkeyHtbl, 16 * ghashin_offset), Assembler::AVX_512bit);
+ } else {
+ __ evmovdquq(GHDAT1, Address(avx512_subkeyHtbl, 16 * ghashin_offset), Assembler::AVX_512bit);
+ }
+
+ if (hk_broadcast) {
+ __ evbroadcastf64x2(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 0 * 64), Assembler::AVX_512bit);
+ __ evbroadcastf64x2(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 0 * 64), Assembler::AVX_512bit);
+ } else {
+ __ evmovdquq(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 0 * 64), Assembler::AVX_512bit);
+ __ evmovdquq(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 0 * 64), Assembler::AVX_512bit);
+ }
+
+ //save counter for the next round
+ //increment counter overflow check register
+ __ evshufi64x2(CTR_BE, B12_15, B12_15, 255, Assembler::AVX_512bit);
+ __ addb(CTR_CHECK, 16);
+
+ //pre - load constants
+ ev_load_key(AESKEY2, key, 1 * 16, rbx);
+ __ evmovdquq(GHDAT2, Address(avx512_subkeyHtbl, 16 * (ghashin_offset +4)), Assembler::AVX_512bit);
+
+ //stitch AES rounds with GHASH
+ //AES round 0
+ __ evpxorq(B00_03, B00_03, AESKEY1, Assembler::AVX_512bit);
+ __ evpxorq(B04_07, B04_07, AESKEY1, Assembler::AVX_512bit);
+ __ evpxorq(B08_11, B08_11, AESKEY1, Assembler::AVX_512bit);
+ __ evpxorq(B12_15, B12_15, AESKEY1, Assembler::AVX_512bit);
+ ev_load_key(AESKEY1, key, 2 * 16, rbx);
+
+ //GHASH 4 blocks(15 to 12)
+ carrylessMultiply(TLL1, TLH1, THL1, THH1, GHDAT1, GHKEY2, GHKEY1);
+
+ if (hk_broadcast) {
+ __ evbroadcastf64x2(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 1 * 64), Assembler::AVX_512bit);
+ __ evbroadcastf64x2(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 1 * 64), Assembler::AVX_512bit);
+ } else {
+ __ evmovdquq(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 1 * 64), Assembler::AVX_512bit);
+ __ evmovdquq(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 1 * 64), Assembler::AVX_512bit);
+ }
+
+ __ evmovdquq(GHDAT1, Address(avx512_subkeyHtbl, 16 * (ghashin_offset + 8)), Assembler::AVX_512bit);
+
+ //AES round 1
+ roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15);
+
+ ev_load_key(AESKEY2, key, 3 * 16, rbx);
+
+ //GHASH 4 blocks(11 to 8)
+ carrylessMultiply(TLL2, TLH2, THL2, THH2, GHDAT2, GHKEY2, GHKEY1);
+
+ if (hk_broadcast) {
+ __ evbroadcastf64x2(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 2 * 64), Assembler::AVX_512bit);
+ __ evbroadcastf64x2(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 2 * 64), Assembler::AVX_512bit);
+ } else {
+ __ evmovdquq(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 2 * 64 ), Assembler::AVX_512bit);
+ __ evmovdquq(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 2 * 64), Assembler::AVX_512bit);
}
- // Load data for computing ghash
- __ evmovdquq(ZTMP22, Address(data, ghash_pos, Address::times_1, 1 * 64), Assembler::AVX_512bit);
- __ vpshufb(ZTMP22, ZTMP22, xmm24, Assembler::AVX_512bit);
-
- // stitch AES rounds with GHASH
- // AES round 0, xmm24 has shuffle mask
- shuffleExorRnd1Key(ZTMP0, ZTMP1, ZTMP2, ZTMP3, xmm24, ZTMP17);
- // Reuse ZTMP17 / ZTMP18 for loading remaining AES Keys
- ev_load_key(ZTMP17, key, 2 * 16, xmm29);
- // GHASH 4 blocks
- carrylessMultiply(ZTMP6, ZTMP7, ZTMP8, ZTMP5, ZTMP21, ZTMP19);
- // Load the next hkey and Ghash data
- __ evmovdquq(ZTMP19, Address(subkeyHtbl, ++i * 64), Assembler::AVX_512bit);
- __ evmovdquq(ZTMP21, Address(data, ghash_pos, Address::times_1, 2 * 64), Assembler::AVX_512bit);
- __ vpshufb(ZTMP21, ZTMP21, xmm24, Assembler::AVX_512bit);
-
- // AES round 1
- roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- ev_load_key(ZTMP18, key, 3 * 16, xmm29);
-
- // GHASH 4 blocks(11 to 8)
- carrylessMultiply(ZTMP10, ZTMP12, ZTMP11, ZTMP9, ZTMP22, ZTMP20);
- // Load the next hkey and GDATA
- __ evmovdquq(ZTMP20, Address(subkeyHtbl, ++i * 64), Assembler::AVX_512bit);
- __ evmovdquq(ZTMP22, Address(data, ghash_pos, Address::times_1, 3 * 64), Assembler::AVX_512bit);
- __ vpshufb(ZTMP22, ZTMP22, xmm24, Assembler::AVX_512bit);
-
- // AES round 2
- roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- ev_load_key(ZTMP17, key, 4 * 16, xmm29);
-
- // GHASH 4 blocks(7 to 4)
- carrylessMultiply(ZTMP14, ZTMP16, ZTMP15, ZTMP13, ZTMP21, ZTMP19);
- // AES rounds 3
- roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- ev_load_key(ZTMP18, key, 5 * 16, xmm29);
-
- // Gather(XOR) GHASH for 12 blocks
- xorGHASH(ZTMP5, ZTMP6, ZTMP8, ZTMP7, ZTMP9, ZTMP13, ZTMP10, ZTMP14, ZTMP12, ZTMP16, ZTMP11, ZTMP15);
-
- // AES rounds 4
- roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- ev_load_key(ZTMP17, key, 6 * 16, xmm29);
-
- // load plain / cipher text(recycle registers)
- loadData(in, pos, ZTMP13, ZTMP14, ZTMP15, ZTMP16);
-
- // AES rounds 5
- roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- ev_load_key(ZTMP18, key, 7 * 16, xmm29);
- // GHASH 4 blocks(3 to 0)
- carrylessMultiply(ZTMP10, ZTMP12, ZTMP11, ZTMP9, ZTMP22, ZTMP20);
-
- // AES round 6
- roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- ev_load_key(ZTMP17, key, 8 * 16, xmm29);
-
- // gather GHASH in ZTMP6(low) and ZTMP5(high)
- if (first_time_reduction) {
- __ vpternlogq(ZTMP7, 0x96, ZTMP8, ZTMP12, Assembler::AVX_512bit);
- __ evpxorq(xmm25, ZTMP7, ZTMP11, Assembler::AVX_512bit);
- __ evpxorq(xmm27, ZTMP5, ZTMP9, Assembler::AVX_512bit);
- __ evpxorq(xmm26, ZTMP6, ZTMP10, Assembler::AVX_512bit);
- } else if (!first_time_reduction && !final_reduction) {
- xorGHASH(ZTMP7, xmm25, xmm27, xmm26, ZTMP8, ZTMP12, ZTMP7, ZTMP11, ZTMP5, ZTMP9, ZTMP6, ZTMP10);
+ __ evmovdquq(GHDAT2, Address(avx512_subkeyHtbl, 16 * (ghashin_offset + 12)), Assembler::AVX_512bit);
+
+ //AES round 2
+ roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15);
+ ev_load_key(AESKEY1, key, 4 * 16, rbx);
+
+ //GHASH 4 blocks(7 to 4)
+ carrylessMultiply(TLL3, TLH3, THL3, THH3, GHDAT1, GHKEY2, GHKEY1);
+
+ if (hk_broadcast) {
+ __ evbroadcastf64x2(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 3 * 64), Assembler::AVX_512bit);
+ __ evbroadcastf64x2(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 3 * 64), Assembler::AVX_512bit);
+ } else {
+ __ evmovdquq(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 3 * 64), Assembler::AVX_512bit);
+ __ evmovdquq(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 3 * 64), Assembler::AVX_512bit);
}
- if (final_reduction) {
- // Phase one: Add mid products together
- // Also load polynomial constant for reduction
- __ vpternlogq(ZTMP7, 0x96, ZTMP8, ZTMP12, Assembler::AVX_512bit);
- __ vpternlogq(ZTMP7, 0x96, xmm25, ZTMP11, Assembler::AVX_512bit);
- __ vpsrldq(ZTMP11, ZTMP7, 8, Assembler::AVX_512bit);
- __ vpslldq(ZTMP7, ZTMP7, 8, Assembler::AVX_512bit);
- __ evmovdquq(ZTMP12, ExternalAddress(ghash_polynomial_reduction_addr()), Assembler::AVX_512bit, rbx /*rscratch*/);
+ //AES rounds 3
+ roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15);
+ ev_load_key(AESKEY2, key, 5 * 16, rbx);
+
+ //Gather(XOR) GHASH for 12 blocks
+ xorGHASH(TLL1, TLH1, THL1, THH1, TLL2, TLL3, TLH2, TLH3, THL2, THL3, THH2, THH3);
+
+ //AES rounds 4
+ roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15);
+ ev_load_key(AESKEY1, key, 6 * 16, rbx);
+
+ //load plain / cipher text(recycle GH3xx registers)
+ loadData(in, pos, DATA1, DATA2, DATA3, DATA4);
+
+ //AES rounds 5
+ roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15);
+ ev_load_key(AESKEY2, key, 7 * 16, rbx);
+
+ //GHASH 4 blocks(3 to 0)
+ carrylessMultiply(TLL2, TLH2, THL2, THH2, GHDAT2, GHKEY2, GHKEY1);
+
+ //AES round 6
+ roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15);
+ ev_load_key(AESKEY1, key, 8 * 16, rbx);
+
+ //gather GHASH in TO_REDUCE_H / L
+ if (is_hash_start) {
+ __ evpxorq(TO_REDUCE_L, TLL2, THL2, Assembler::AVX_512bit);
+ __ evpxorq(TO_REDUCE_H, THH2, TLH2, Assembler::AVX_512bit);
+ __ vpternlogq(TO_REDUCE_L, 0x96, TLL1, THL1, Assembler::AVX_512bit);
+ __ vpternlogq(TO_REDUCE_H, 0x96, THH1, TLH1, Assembler::AVX_512bit);
+ } else {
+ //not the first round so sums need to be updated
+ xorGHASH(TO_REDUCE_L, TO_REDUCE_H, TO_REDUCE_L, TO_REDUCE_H, TLL2, THL2, THH2, TLH2, TLL1, THL1, THH1, TLH1);
}
- // AES round 7
- roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- ev_load_key(ZTMP18, key, 9 * 16, xmm29);
- if (final_reduction) {
- __ vpternlogq(ZTMP5, 0x96, ZTMP9, ZTMP11, Assembler::AVX_512bit);
- __ evpxorq(ZTMP5, ZTMP5, xmm27, Assembler::AVX_512bit);
- __ vpternlogq(ZTMP6, 0x96, ZTMP10, ZTMP7, Assembler::AVX_512bit);
- __ evpxorq(ZTMP6, ZTMP6, xmm26, Assembler::AVX_512bit);
+
+ //AES round 7
+ roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15);
+ ev_load_key(AESKEY2, key, 9 * 16, rbx);
+
+ //new reduction
+ if (do_hash_reduction) {
+ __ evmovdquq(ZT, ExternalAddress(ghash_polynomial_reduction_addr()), Assembler::AVX_512bit, rbx /*rscratch*/);
+ __ evpclmulqdq(THH1, TO_REDUCE_L, ZT, 0x10, Assembler::AVX_512bit);
+ __ vpshufd(TO_REDUCE_L, TO_REDUCE_L, 78, Assembler::AVX_512bit);
+ __ vpternlogq(THH1, 0x96, TO_REDUCE_H, TO_REDUCE_L, Assembler::AVX_512bit);
}
- // AES round 8
- roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- ev_load_key(ZTMP17, key, 10 * 16, xmm29);
-
- // Horizontal xor of low and high 4*128
- if (final_reduction) {
- vhpxori4x128(ZTMP5, ZTMP9);
- vhpxori4x128(ZTMP6, ZTMP10);
+
+ //AES round 8
+ roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15);
+ ev_load_key(AESKEY1, key, 10 * 16, rbx);
+
+ //horizontalxor of 4 reduced hashes
+ if (do_hash_hxor) {
+ vhpxori4x128(THH1, TLL1);
}
- // AES round 9
- roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- // First phase of reduction
- if (final_reduction) {
- __ evpclmulqdq(ZTMP10, ZTMP12, ZTMP6, 0x01, Assembler::AVX_128bit);
- __ vpslldq(ZTMP10, ZTMP10, 8, Assembler::AVX_128bit);
- __ evpxorq(ZTMP10, ZTMP6, ZTMP10, Assembler::AVX_128bit);
+
+ //AES round 9
+ roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15);
+ ev_load_key(AESKEY2, key, 11 * 16, rbx);
+ //AES rounds up to 11 (AES192) or 13 (AES256)
+ //AES128 is done
+ __ cmpl(NROUNDS, 52);
+ __ jcc(Assembler::less, last_aes_rnd);
+ __ bind(aes_192);
+ roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15);
+ ev_load_key(AESKEY1, key, 12 * 16, rbx);
+ roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15);
+ __ cmpl(NROUNDS, 60);
+ __ jcc(Assembler::less, last_aes_rnd);
+ __ bind(aes_256);
+ ev_load_key(AESKEY2, key, 13 * 16, rbx);
+ roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15);
+ ev_load_key(AESKEY1, key, 14 * 16, rbx);
+ roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15);
+
+ __ bind(last_aes_rnd);
+ //the last AES round
+ lastroundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15);
+ //AESKEY1and AESKEY2 contain AES round keys
+
+ //XOR against plain / cipher text
+ xorBeforeStore(B00_03, B04_07, B08_11, B12_15, DATA1, DATA2, DATA3, DATA4);
+
+ //store cipher / plain text
+ storeData(out, pos, B00_03, B04_07, B08_11, B12_15);
+ //**B00_03, B04_07, B08_011, B12_B15 may contain sensitive data
+
+ //shuffle cipher text blocks for GHASH computation
+ __ cmpptr(ct, out);
+ __ jcc(Assembler::notEqual, skip_shuffle);
+ shuffle(B00_03, B04_07, B08_11, B12_15, B00_03, B04_07, B08_11, B12_15, SHFMSK);
+ __ jmp(cont);
+ __ bind(skip_shuffle);
+ shuffle(B00_03, B04_07, B08_11, B12_15, DATA1, DATA2, DATA3, DATA4, SHFMSK);
+
+ //**B00_03, B04_07, B08_011, B12_B15 overwritten with shuffled cipher text
+ __ bind(cont);
+ //store shuffled cipher text for ghashing
+ __ evmovdquq(Address(avx512_subkeyHtbl, 16 * aesout_offset), B00_03, Assembler::AVX_512bit);
+ __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (aesout_offset + 4)), B04_07, Assembler::AVX_512bit);
+ __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (aesout_offset + 8)), B08_11, Assembler::AVX_512bit);
+ __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (aesout_offset + 12)), B12_15, Assembler::AVX_512bit);
+}
+
+
+//Encrypt / decrypt the initial 16 blocks
+void StubGenerator::initial_blocks_16_avx512(Register in, Register out, Register ct, Register pos, Register key, Register avx512_subkeyHtbl,
+ Register CTR_CHECK, Register rounds, XMMRegister CTR, XMMRegister GHASH, XMMRegister ADDBE_4x4,
+ XMMRegister ADDBE_1234, XMMRegister ADD_1234, XMMRegister SHUF_MASK, int stack_offset) {
+ const XMMRegister B00_03 = xmm7;
+ const XMMRegister B04_07 = xmm10;
+ const XMMRegister B08_11 = xmm11;
+ const XMMRegister B12_15 = xmm12;
+ const XMMRegister T0 = xmm0;
+ const XMMRegister T1 = xmm3;
+ const XMMRegister T2 = xmm4;
+ const XMMRegister T3 = xmm5;
+ const XMMRegister T4 = xmm6;
+ const XMMRegister T5 = xmm30;
+
+ Label next_16_overflow, next_16_ok, cont, skip_shuffle, aes_256, aes_192, last_aes_rnd;
+ //prepare counter blocks
+ __ cmpb(CTR_CHECK, (256 - 16));
+ __ jcc(Assembler::aboveEqual, next_16_overflow);
+ __ vpaddd(B00_03, CTR, ADDBE_1234, Assembler::AVX_512bit);
+ __ vpaddd(B04_07, B00_03, ADDBE_4x4, Assembler::AVX_512bit);
+ __ vpaddd(B08_11, B04_07, ADDBE_4x4, Assembler::AVX_512bit);
+ __ vpaddd(B12_15, B08_11, ADDBE_4x4, Assembler::AVX_512bit);
+ __ jmp(next_16_ok);
+ __ bind(next_16_overflow);
+ __ vpshufb(CTR, CTR, SHUF_MASK, Assembler::AVX_512bit);
+ __ evmovdquq(B12_15, ExternalAddress(counter_mask_linc4_addr()), Assembler::AVX_512bit, rbx);
+ __ vpaddd(B00_03, CTR, ADD_1234, Assembler::AVX_512bit);
+ __ vpaddd(B04_07, B00_03, B12_15, Assembler::AVX_512bit);
+ __ vpaddd(B08_11, B04_07, B12_15, Assembler::AVX_512bit);
+ __ vpaddd(B12_15, B08_11, B12_15, Assembler::AVX_512bit);
+ shuffle(B00_03, B04_07, B08_11, B12_15, B00_03, B04_07, B08_11, B12_15, SHUF_MASK);
+ __ bind(next_16_ok);
+ __ evshufi64x2(CTR, B12_15, B12_15, 255, Assembler::AVX_512bit);
+ __ addb(CTR_CHECK, 16);
+
+ //load 16 blocks of data
+ loadData(in, pos, T0, T1, T2, T3);
+
+ //move to AES encryption rounds
+ __ movdqu(T5, ExternalAddress(key_shuffle_mask_addr()), rbx /*rscratch*/);
+ ev_load_key(T4, key, 0, T5);
+ __ evpxorq(B00_03, B00_03, T4, Assembler::AVX_512bit);
+ __ evpxorq(B04_07, B04_07, T4, Assembler::AVX_512bit);
+ __ evpxorq(B08_11, B08_11, T4, Assembler::AVX_512bit);
+ __ evpxorq(B12_15, B12_15, T4, Assembler::AVX_512bit);
+
+ for (int i = 1; i < 10; i++) {
+ ev_load_key(T4, key, i * 16, T5);
+ roundEncode(T4, B00_03, B04_07, B08_11, B12_15);
}
+
+ ev_load_key(T4, key, 10 * 16, T5);
__ cmpl(rounds, 52);
- __ jcc(Assembler::greaterEqual, AES_192);
- __ jmp(LAST_AES_RND);
- // AES rounds up to 11 (AES192) or 13 (AES256)
- __ bind(AES_192);
- roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- ev_load_key(ZTMP18, key, 11 * 16, xmm29);
- roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- ev_load_key(ZTMP17, key, 12 * 16, xmm29);
+ __ jcc(Assembler::less, last_aes_rnd);
+ __ bind(aes_192);
+ roundEncode(T4, B00_03, B04_07, B08_11, B12_15);
+ ev_load_key(T4, key, 16 * 11, T5);
+ roundEncode(T4, B00_03, B04_07, B08_11, B12_15);
+ ev_load_key(T4, key, 16 * 12, T5);
__ cmpl(rounds, 60);
- __ jcc(Assembler::aboveEqual, AES_256);
- __ jmp(LAST_AES_RND);
-
- __ bind(AES_256);
- roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- ev_load_key(ZTMP18, key, 13 * 16, xmm29);
- roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- ev_load_key(ZTMP17, key, 14 * 16, xmm29);
-
- __ bind(LAST_AES_RND);
- // Second phase of reduction
- if (final_reduction) {
- __ evpclmulqdq(ZTMP9, ZTMP12, ZTMP10, 0x00, Assembler::AVX_128bit);
- __ vpsrldq(ZTMP9, ZTMP9, 4, Assembler::AVX_128bit); // Shift-R 1-DW to obtain 2-DWs shift-R
- __ evpclmulqdq(ZTMP11, ZTMP12, ZTMP10, 0x10, Assembler::AVX_128bit);
- __ vpslldq(ZTMP11, ZTMP11, 4, Assembler::AVX_128bit); // Shift-L 1-DW for result
- // ZTMP5 = ZTMP5 X ZTMP11 X ZTMP9
- __ vpternlogq(ZTMP5, 0x96, ZTMP11, ZTMP9, Assembler::AVX_128bit);
- }
- // Last AES round
- lastroundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- // XOR against plain / cipher text
- xorBeforeStore(ZTMP0, ZTMP1, ZTMP2, ZTMP3, ZTMP13, ZTMP14, ZTMP15, ZTMP16);
- // store cipher / plain text
- storeData(out, pos, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
+ __ jcc(Assembler::less, last_aes_rnd);
+ __ bind(aes_256);
+ roundEncode(T4, B00_03, B04_07, B08_11, B12_15);
+ ev_load_key(T4, key, 16 * 13, T5);
+ roundEncode(T4, B00_03, B04_07, B08_11, B12_15);
+ ev_load_key(T4, key, 16 * 14, T5);
+
+ __ bind(last_aes_rnd);
+ lastroundEncode(T4, B00_03, B04_07, B08_11, B12_15);
+
+ //xor against text
+ xorBeforeStore(B00_03, B04_07, B08_11, B12_15, T0, T1, T2, T3);
+
+ //store
+ storeData(out, pos, B00_03, B04_07, B08_11, B12_15);
+
+ __ cmpptr(ct, out);
+ __ jcc(Assembler::equal, skip_shuffle);
+ //decryption - cipher text needs to go to GHASH phase
+ shuffle(B00_03, B04_07, B08_11, B12_15, T0, T1, T2, T3, SHUF_MASK);
+ __ jmp(cont);
+ __ bind(skip_shuffle);
+ shuffle(B00_03, B04_07, B08_11, B12_15, B00_03, B04_07, B08_11, B12_15, SHUF_MASK);
+
+ //B00_03, B04_07, B08_11, B12_15 overwritten with shuffled cipher text
+ __ bind(cont);
+ __ evmovdquq(Address(avx512_subkeyHtbl, 16 * stack_offset), B00_03, Assembler::AVX_512bit);
+ __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (stack_offset + 4)), B04_07, Assembler::AVX_512bit);
+ __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (stack_offset + 8)), B08_11, Assembler::AVX_512bit);
+ __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (stack_offset + 12)), B12_15, Assembler::AVX_512bit);
}
-void StubGenerator::aesgcm_encrypt(Register in, Register len, Register ct, Register out, Register key,
- Register state, Register subkeyHtbl, Register avx512_subkeyHtbl, Register counter) {
- Label ENC_DEC_DONE, GENERATE_HTBL_48_BLKS, AES_192, AES_256, STORE_CT, GHASH_LAST_32,
- AES_32_BLOCKS, GHASH_AES_PARALLEL, LOOP, ACCUMULATE, GHASH_16_AES_16;
- const XMMRegister CTR_BLOCKx = xmm9;
+void StubGenerator::aesgcm_avx512(Register in, Register len, Register ct, Register out, Register key, Register state,
+ Register subkeyHtbl, Register avx512_subkeyHtbl, Register counter) {
+ Label ENC_DEC_DONE, MESG_BELOW_32_BLKS, NO_BIG_BLKS, ENCRYPT_BIG_BLKS_NO_HXOR,
+ ENCRYPT_BIG_NBLKS, ENCRYPT_16_BLKS, ENCRYPT_N_GHASH_32_N_BLKS, GHASH_DONE;
+ const XMMRegister CTR_BLOCKx = xmm2;
const XMMRegister AAD_HASHx = xmm14;
- const Register pos = rax;
- const Register rounds = r15;
- const Register ghash_pos = NOT_WIN64( r14) WIN64_ONLY( r11 );
const XMMRegister ZTMP0 = xmm0;
- const XMMRegister ZTMP1 = xmm3;
- const XMMRegister ZTMP2 = xmm4;
- const XMMRegister ZTMP3 = xmm5;
+ const XMMRegister ZTMP1 = xmm3; //**sensitive
+ const XMMRegister ZTMP2 = xmm4; //**sensitive(small data)
+ const XMMRegister ZTMP3 = xmm5; //**sensitive(small data)
const XMMRegister ZTMP4 = xmm6;
const XMMRegister ZTMP5 = xmm7;
const XMMRegister ZTMP6 = xmm10;
@@ -3066,235 +3358,170 @@ void StubGenerator::aesgcm_encrypt(Register in, Register len, Register ct, Regis
const XMMRegister ZTMP14 = xmm20;
const XMMRegister ZTMP15 = xmm21;
const XMMRegister ZTMP16 = xmm30;
- const XMMRegister COUNTER_INC_MASK = xmm18;
-
- __ movl(pos, 0); // Total length processed
- // Min data size processed = 768 bytes
- __ cmpl(len, 768);
- __ jcc(Assembler::less, ENC_DEC_DONE);
+ const XMMRegister ZTMP17 = xmm31;
+ const XMMRegister ZTMP18 = xmm1;
+ const XMMRegister ZTMP19 = xmm18;
+ const XMMRegister ZTMP20 = xmm8;
+ const XMMRegister ZTMP21 = xmm22;
+ const XMMRegister ZTMP22 = xmm23;
+ const XMMRegister ZTMP23 = xmm26;
+ const XMMRegister GH = xmm24;
+ const XMMRegister GL = xmm25;
+ const XMMRegister SHUF_MASK = xmm29;
+ const XMMRegister ADDBE_4x4 = xmm27;
+ const XMMRegister ADDBE_1234 = xmm28;
+ const XMMRegister ADD_1234 = xmm9;
+ const KRegister MASKREG = k1;
+ const Register pos = rax;
+ const Register rounds = r15;
+ const Register CTR_CHECK = r14;
- // Generate 48 constants for htbl
- __ call(GENERATE_HTBL_48_BLKS, relocInfo::none);
- int index = 0; // Index for choosing subkeyHtbl entry
- __ movl(ghash_pos, 0); // Pointer for ghash read and store operations
+ const int stack_offset = 64;
+ const int ghashin_offset = 64;
+ const int aesout_offset = 64;
+ const int hashkey_offset = 0;
+ const int hashkey_gap = 16 * 32;
+ const int HashKey_32 = 0;
+ const int HashKey_16 = 16 * 16;
- // Move initial counter value and STATE value into variables
+ __ movl(pos, 0);
+ __ cmpl(len, 256);
+ __ jcc(Assembler::lessEqual, ENC_DEC_DONE);
+
+ /* Structure of the Htbl is as follows:
+ * Where 0 - 31 we have 32 Hashkey's and 32-63 we have 32 HashKeyK (derived from HashKey)
+ * Rest 8 entries are for storing CTR values post AES rounds
+ * ----------------------------------------------------------------------------------------
+ Hashkey32 -> 16 * 0
+ Hashkey31 -> 16 * 1
+ Hashkey30 -> 16 * 2
+ ........
+ Hashkey1 -> 16 * 31
+ ---------------------
+ HaskeyK32 -> 16 * 32
+ HashkeyK31 -> 16 * 33
+ .........
+ HashkeyK1 -> 16 * 63
+ ---------------------
+ 1st set of AES Entries
+ B00_03 -> 16 * 64
+ B04_07 -> 16 * 68
+ B08_11 -> 16 * 72
+ B12_15 -> 16 * 80
+ ---------------------
+ 2nd set of AES Entries
+ B00_03 -> 16 * 84
+ B04_07 -> 16 * 88
+ B08_11 -> 16 * 92
+ B12_15 -> 16 * 96
+ ---------------------*/
+ generateHtbl_32_blocks_avx512(subkeyHtbl, avx512_subkeyHtbl);
+
+ //Move initial counter value and STATE value into variables
__ movdqu(CTR_BLOCKx, Address(counter, 0));
__ movdqu(AAD_HASHx, Address(state, 0));
- // Load lswap mask for ghash
+
+ //Load lswap mask for ghash
__ movdqu(xmm24, ExternalAddress(ghash_long_swap_mask_addr()), rbx /*rscratch*/);
- // Shuffle input state using lswap mask
+ //Shuffle input state using lswap mask
__ vpshufb(AAD_HASHx, AAD_HASHx, xmm24, Assembler::AVX_128bit);
// Compute #rounds for AES based on the length of the key array
__ movl(rounds, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
- // Broadcast counter value to 512 bit register
+ __ evmovdquq(ADDBE_4x4, ExternalAddress(counter_mask_addbe_4444_addr()), Assembler::AVX_512bit, rbx /*rscratch*/);
+ __ evmovdquq(ADDBE_1234, ExternalAddress(counter_mask_addbe_1234_addr()), Assembler::AVX_512bit, rbx /*rscratch*/);
+ __ evmovdquq(SHUF_MASK, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_512bit, rbx /*rscratch*/);
+ __ evmovdquq(ADD_1234, ExternalAddress(counter_mask_add_1234_addr()), Assembler::AVX_512bit, rbx /*rscratch*/);
+
+ //Shuffle counter, subtract 1 from the pre-incremented counter value and broadcast counter value to 512 bit register
+ __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, SHUF_MASK, Assembler::AVX_128bit);
+ __ vpsubd(CTR_BLOCKx, CTR_BLOCKx, ADD_1234, Assembler::AVX_128bit);
__ evshufi64x2(CTR_BLOCKx, CTR_BLOCKx, CTR_BLOCKx, 0, Assembler::AVX_512bit);
- // Load counter shuffle mask
- __ evmovdquq(xmm24, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_512bit, rbx /*rscratch*/);
- // Shuffle counter
- __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, xmm24, Assembler::AVX_512bit);
-
- // Load mask for incrementing counter
- __ evmovdquq(COUNTER_INC_MASK, ExternalAddress(counter_mask_linc4_addr()), Assembler::AVX_512bit, rbx /*rscratch*/);
- // Pre-increment counter
- __ vpaddd(ZTMP5, CTR_BLOCKx, ExternalAddress(counter_mask_linc0_addr()), Assembler::AVX_512bit, rbx /*rscratch*/);
- __ vpaddd(ZTMP6, ZTMP5, COUNTER_INC_MASK, Assembler::AVX_512bit);
- __ vpaddd(ZTMP7, ZTMP6, COUNTER_INC_MASK, Assembler::AVX_512bit);
- __ vpaddd(ZTMP8, ZTMP7, COUNTER_INC_MASK, Assembler::AVX_512bit);
-
- // Begin 32 blocks of AES processing
- __ bind(AES_32_BLOCKS);
- // Save incremented counter before overwriting it with AES data
- __ evmovdquq(CTR_BLOCKx, ZTMP8, Assembler::AVX_512bit);
-
- // Move 256 bytes of data
- loadData(in, pos, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- // Load key shuffle mask
- __ movdqu(xmm29, ExternalAddress(key_shuffle_mask_addr()), rbx /*rscratch*/);
- // Load 0th AES round key
- ev_load_key(ZTMP4, key, 0, xmm29);
- // AES-ROUND0, xmm24 has the shuffle mask
- shuffleExorRnd1Key(ZTMP5, ZTMP6, ZTMP7, ZTMP8, xmm24, ZTMP4);
-
- for (int j = 1; j < 10; j++) {
- ev_load_key(ZTMP4, key, j * 16, xmm29);
- roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8);
- }
- ev_load_key(ZTMP4, key, 10 * 16, xmm29);
- // AES rounds up to 11 (AES192) or 13 (AES256)
- __ cmpl(rounds, 52);
- __ jcc(Assembler::greaterEqual, AES_192);
- lastroundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8);
- __ jmp(STORE_CT);
-
- __ bind(AES_192);
- roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8);
- ev_load_key(ZTMP4, key, 11 * 16, xmm29);
- roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8);
- __ cmpl(rounds, 60);
- __ jcc(Assembler::aboveEqual, AES_256);
- ev_load_key(ZTMP4, key, 12 * 16, xmm29);
- lastroundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8);
- __ jmp(STORE_CT);
-
- __ bind(AES_256);
- ev_load_key(ZTMP4, key, 12 * 16, xmm29);
- roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8);
- ev_load_key(ZTMP4, key, 13 * 16, xmm29);
- roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8);
- ev_load_key(ZTMP4, key, 14 * 16, xmm29);
- // Last AES round
- lastroundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8);
-
- __ bind(STORE_CT);
- // Xor the encrypted key with PT to obtain CT
- xorBeforeStore(ZTMP5, ZTMP6, ZTMP7, ZTMP8, ZTMP0, ZTMP1, ZTMP2, ZTMP3);
- storeData(out, pos, ZTMP5, ZTMP6, ZTMP7, ZTMP8);
- // 16 blocks encryption completed
- __ addl(pos, 256);
- __ cmpl(pos, 512);
- __ jcc(Assembler::aboveEqual, GHASH_AES_PARALLEL);
- __ vpaddd(ZTMP5, CTR_BLOCKx, COUNTER_INC_MASK, Assembler::AVX_512bit);
- __ vpaddd(ZTMP6, ZTMP5, COUNTER_INC_MASK, Assembler::AVX_512bit);
- __ vpaddd(ZTMP7, ZTMP6, COUNTER_INC_MASK, Assembler::AVX_512bit);
- __ vpaddd(ZTMP8, ZTMP7, COUNTER_INC_MASK, Assembler::AVX_512bit);
- __ jmp(AES_32_BLOCKS);
-
- __ bind(GHASH_AES_PARALLEL);
- // Ghash16_encrypt16_parallel takes place in the order with three reduction values:
- // 1) First time -> cipher xor input ghash
- // 2) No reduction -> accumulate multiplication values
- // 3) Final reduction post 48 blocks -> new ghash value is computed for the next round
- // Reduction value = first time
- ghash16_encrypt16_parallel(key, avx512_subkeyHtbl, CTR_BLOCKx, AAD_HASHx, in, out, ct, pos, true, xmm24, true, rounds, ghash_pos, false, index, COUNTER_INC_MASK);
- __ addl(pos, 256);
- __ addl(ghash_pos, 256);
- index += 4;
-
- // At this point we have processed 768 bytes of AES and 256 bytes of GHASH.
- // If the remaining length is less than 768, process remaining 512 bytes of ghash in GHASH_LAST_32 code
- __ subl(len, 768);
- __ cmpl(len, 768);
- __ jcc(Assembler::less, GHASH_LAST_32);
-
- // AES 16 blocks and GHASH 16 blocks in parallel
- // For multiples of 48 blocks we will do ghash16_encrypt16 interleaved multiple times
- // Reduction value = no reduction means that the carryless multiplication values are accumulated for further calculations
- // Each call uses 4 subkeyHtbl values, so increment the index by 4.
- __ bind(GHASH_16_AES_16);
- // Reduction value = no reduction
- ghash16_encrypt16_parallel(key, avx512_subkeyHtbl, CTR_BLOCKx, AAD_HASHx, in, out, ct, pos, false, xmm24, false, rounds, ghash_pos, false, index, COUNTER_INC_MASK);
- __ addl(pos, 256);
- __ addl(ghash_pos, 256);
- index += 4;
- // Reduction value = final reduction means that the accumulated values have to be reduced as we have completed 48 blocks of ghash
- ghash16_encrypt16_parallel(key, avx512_subkeyHtbl, CTR_BLOCKx, AAD_HASHx, in, out, ct, pos, false, xmm24, false, rounds, ghash_pos, true, index, COUNTER_INC_MASK);
- __ addl(pos, 256);
- __ addl(ghash_pos, 256);
- // Calculated ghash value needs to be __ moved to AAD_HASHX so that we can restart the ghash16-aes16 pipeline
- __ movdqu(AAD_HASHx, ZTMP5);
- index = 0; // Reset subkeyHtbl index
-
- // Restart the pipeline
- // Reduction value = first time
- ghash16_encrypt16_parallel(key, avx512_subkeyHtbl, CTR_BLOCKx, AAD_HASHx, in, out, ct, pos, true, xmm24, true, rounds, ghash_pos, false, index, COUNTER_INC_MASK);
- __ addl(pos, 256);
- __ addl(ghash_pos, 256);
- index += 4;
-
- __ subl(len, 768);
- __ cmpl(len, 768);
- __ jcc(Assembler::greaterEqual, GHASH_16_AES_16);
-
- // GHASH last 32 blocks processed here
- // GHASH products accumulated in ZMM27, ZMM25 and ZMM26 during GHASH16-AES16 operation is used
- __ bind(GHASH_LAST_32);
- // Use rbx as a pointer to the htbl; For last 32 blocks of GHASH, use key# 4-11 entry in subkeyHtbl
- __ movl(rbx, 256);
- // Load cipher blocks
- __ evmovdquq(ZTMP13, Address(ct, ghash_pos, Address::times_1, 0 * 64), Assembler::AVX_512bit);
- __ evmovdquq(ZTMP14, Address(ct, ghash_pos, Address::times_1, 1 * 64), Assembler::AVX_512bit);
- __ vpshufb(ZTMP13, ZTMP13, xmm24, Assembler::AVX_512bit);
- __ vpshufb(ZTMP14, ZTMP14, xmm24, Assembler::AVX_512bit);
- // Load ghash keys
- __ evmovdquq(ZTMP15, Address(avx512_subkeyHtbl, rbx, Address::times_1, 0 * 64), Assembler::AVX_512bit);
- __ evmovdquq(ZTMP16, Address(avx512_subkeyHtbl, rbx, Address::times_1, 1 * 64), Assembler::AVX_512bit);
-
- // Ghash blocks 0 - 3
- carrylessMultiply(ZTMP2, ZTMP3, ZTMP4, ZTMP1, ZTMP13, ZTMP15);
- // Ghash blocks 4 - 7
- carrylessMultiply(ZTMP6, ZTMP7, ZTMP8, ZTMP5, ZTMP14, ZTMP16);
-
- __ vpternlogq(ZTMP1, 0x96, ZTMP5, xmm27, Assembler::AVX_512bit); // ZTMP1 = ZTMP1 + ZTMP5 + zmm27
- __ vpternlogq(ZTMP2, 0x96, ZTMP6, xmm26, Assembler::AVX_512bit); // ZTMP2 = ZTMP2 + ZTMP6 + zmm26
- __ vpternlogq(ZTMP3, 0x96, ZTMP7, xmm25, Assembler::AVX_512bit); // ZTMP3 = ZTMP3 + ZTMP7 + zmm25
- __ evpxorq(ZTMP4, ZTMP4, ZTMP8, Assembler::AVX_512bit); // ZTMP4 = ZTMP4 + ZTMP8
-
- __ addl(ghash_pos, 128);
- __ addl(rbx, 128);
-
- // Ghash remaining blocks
- __ bind(LOOP);
- __ cmpl(ghash_pos, pos);
- __ jcc(Assembler::aboveEqual, ACCUMULATE);
- // Load next cipher blocks and corresponding ghash keys
- __ evmovdquq(ZTMP13, Address(ct, ghash_pos, Address::times_1, 0 * 64), Assembler::AVX_512bit);
- __ evmovdquq(ZTMP14, Address(ct, ghash_pos, Address::times_1, 1 * 64), Assembler::AVX_512bit);
- __ vpshufb(ZTMP13, ZTMP13, xmm24, Assembler::AVX_512bit);
- __ vpshufb(ZTMP14, ZTMP14, xmm24, Assembler::AVX_512bit);
- __ evmovdquq(ZTMP15, Address(avx512_subkeyHtbl, rbx, Address::times_1, 0 * 64), Assembler::AVX_512bit);
- __ evmovdquq(ZTMP16, Address(avx512_subkeyHtbl, rbx, Address::times_1, 1 * 64), Assembler::AVX_512bit);
-
- // ghash blocks 0 - 3
- carrylessMultiply(ZTMP6, ZTMP7, ZTMP8, ZTMP5, ZTMP13, ZTMP15);
-
- // ghash blocks 4 - 7
- carrylessMultiply(ZTMP10, ZTMP11, ZTMP12, ZTMP9, ZTMP14, ZTMP16);
-
- // update sums
- // ZTMP1 = ZTMP1 + ZTMP5 + ZTMP9
- // ZTMP2 = ZTMP2 + ZTMP6 + ZTMP10
- // ZTMP3 = ZTMP3 + ZTMP7 xor ZTMP11
- // ZTMP4 = ZTMP4 + ZTMP8 xor ZTMP12
- xorGHASH(ZTMP1, ZTMP2, ZTMP3, ZTMP4, ZTMP5, ZTMP9, ZTMP6, ZTMP10, ZTMP7, ZTMP11, ZTMP8, ZTMP12);
- __ addl(ghash_pos, 128);
- __ addl(rbx, 128);
- __ jmp(LOOP);
- // Integrate ZTMP3/ZTMP4 into ZTMP1 and ZTMP2
- __ bind(ACCUMULATE);
- __ evpxorq(ZTMP3, ZTMP3, ZTMP4, Assembler::AVX_512bit);
- __ vpsrldq(ZTMP7, ZTMP3, 8, Assembler::AVX_512bit);
- __ vpslldq(ZTMP8, ZTMP3, 8, Assembler::AVX_512bit);
- __ evpxorq(ZTMP1, ZTMP1, ZTMP7, Assembler::AVX_512bit);
- __ evpxorq(ZTMP2, ZTMP2, ZTMP8, Assembler::AVX_512bit);
-
- // Add ZTMP1 and ZTMP2 128 - bit words horizontally
- vhpxori4x128(ZTMP1, ZTMP11);
- vhpxori4x128(ZTMP2, ZTMP12);
- // Load reduction polynomial and compute final reduction
- __ evmovdquq(ZTMP15, ExternalAddress(ghash_polynomial_reduction_addr()), Assembler::AVX_512bit, rbx /*rscratch*/);
- vclmul_reduce(AAD_HASHx, ZTMP15, ZTMP1, ZTMP2, ZTMP3, ZTMP4);
-
- // Pre-increment counter for next operation
- __ vpaddd(CTR_BLOCKx, CTR_BLOCKx, xmm18, Assembler::AVX_128bit);
- // Shuffle counter and save the updated value
- __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, xmm24, Assembler::AVX_512bit);
+ __ movdl(CTR_CHECK, CTR_BLOCKx);
+ __ andl(CTR_CHECK, 255);
+
+ // Reshuffle counter
+ __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, SHUF_MASK, Assembler::AVX_512bit);
+
+ initial_blocks_16_avx512(in, out, ct, pos, key, avx512_subkeyHtbl, CTR_CHECK, rounds, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, stack_offset);
+ __ addl(pos, 16 * 16);
+ __ cmpl(len, 32 * 16);
+ __ jcc(Assembler::below, MESG_BELOW_32_BLKS);
+
+ initial_blocks_16_avx512(in, out, ct, pos, key, avx512_subkeyHtbl, CTR_CHECK, rounds, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, stack_offset + 16);
+ __ addl(pos, 16 * 16);
+ __ subl(len, 32 * 16);
+
+ __ cmpl(len, 32 * 16);
+ __ jcc(Assembler::below, NO_BIG_BLKS);
+
+ __ bind(ENCRYPT_BIG_BLKS_NO_HXOR);
+ __ cmpl(len, 2 * 32 * 16);
+ __ jcc(Assembler::below, ENCRYPT_BIG_NBLKS);
+ ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK,
+ true, true, false, false, false, ghashin_offset, aesout_offset, HashKey_32);
+ __ addl(pos, 16 * 16);
+
+ ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK,
+ true, false, true, false, true, ghashin_offset + 16, aesout_offset + 16, HashKey_16);
+ __ evmovdquq(AAD_HASHx, ZTMP4, Assembler::AVX_512bit);
+ __ addl(pos, 16 * 16);
+ __ subl(len, 32 * 16);
+ __ jmp(ENCRYPT_BIG_BLKS_NO_HXOR);
+
+ __ bind(ENCRYPT_BIG_NBLKS);
+ ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK,
+ false, true, false, false, false, ghashin_offset, aesout_offset, HashKey_32);
+ __ addl(pos, 16 * 16);
+ ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK,
+ false, false, true, true, true, ghashin_offset + 16, aesout_offset + 16, HashKey_16);
+
+ __ movdqu(AAD_HASHx, ZTMP4);
+ __ addl(pos, 16 * 16);
+ __ subl(len, 32 * 16);
+
+ __ bind(NO_BIG_BLKS);
+ __ cmpl(len, 16 * 16);
+ __ jcc(Assembler::aboveEqual, ENCRYPT_16_BLKS);
+
+ __ bind(ENCRYPT_N_GHASH_32_N_BLKS);
+ ghash16_avx512(true, false, false, false, true, in, pos, avx512_subkeyHtbl, AAD_HASHx, SHUF_MASK, stack_offset, 0, 0, HashKey_32);
+ gcm_enc_dec_last_avx512(len, in, pos, AAD_HASHx, SHUF_MASK, avx512_subkeyHtbl, ghashin_offset + 16, HashKey_16, false, true);
+ __ jmp(GHASH_DONE);
+
+ __ bind(ENCRYPT_16_BLKS);
+ ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK,
+ false, true, false, false, false, ghashin_offset, aesout_offset, HashKey_32);
+
+ ghash16_avx512(false, true, false, false, true, in, pos, avx512_subkeyHtbl, AAD_HASHx, SHUF_MASK, stack_offset, 16 * 16, 0, HashKey_16);
+
+ __ bind(MESG_BELOW_32_BLKS);
+ __ subl(len, 16 * 16);
+ __ addl(pos, 16 * 16);
+ gcm_enc_dec_last_avx512(len, in, pos, AAD_HASHx, SHUF_MASK, avx512_subkeyHtbl, ghashin_offset, HashKey_16, true, true);
+
+ __ bind(GHASH_DONE);
+ //Pre-increment counter for next operation, make sure that counter value is incremented on the LSB
+ __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, SHUF_MASK, Assembler::AVX_128bit);
+ __ vpaddd(CTR_BLOCKx, CTR_BLOCKx, ADD_1234, Assembler::AVX_128bit);
+ __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, SHUF_MASK, Assembler::AVX_128bit);
__ movdqu(Address(counter, 0), CTR_BLOCKx);
- // Load ghash lswap mask
+ //Load ghash lswap mask
__ movdqu(xmm24, ExternalAddress(ghash_long_swap_mask_addr()), rbx /*rscratch*/);
- // Shuffle ghash using lbswap_mask and store it
+ //Shuffle ghash using lbswap_mask and store it
__ vpshufb(AAD_HASHx, AAD_HASHx, xmm24, Assembler::AVX_128bit);
__ movdqu(Address(state, 0), AAD_HASHx);
- __ jmp(ENC_DEC_DONE);
- __ bind(GENERATE_HTBL_48_BLKS);
- generateHtbl_48_block_zmm(subkeyHtbl, avx512_subkeyHtbl, rbx /*rscratch*/);
+ //Zero out sensitive data
+ __ evpxorq(ZTMP21, ZTMP21, ZTMP21, Assembler::AVX_512bit);
+ __ evpxorq(ZTMP0, ZTMP0, ZTMP0, Assembler::AVX_512bit);
+ __ evpxorq(ZTMP1, ZTMP1, ZTMP1, Assembler::AVX_512bit);
+ __ evpxorq(ZTMP2, ZTMP2, ZTMP2, Assembler::AVX_512bit);
+ __ evpxorq(ZTMP3, ZTMP3, ZTMP3, Assembler::AVX_512bit);
__ bind(ENC_DEC_DONE);
- __ movq(rax, pos);
}
//Implements data * hashkey mod (128, 127, 126, 121, 0)
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp
index d8f7a6b272b..c72c32e796d 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp
@@ -215,7 +215,7 @@ void StubGenerator::array_overlap_test(address no_overlap_target, Label* NOLp, A
__ cmpptr(to, from);
__ lea(end_from, Address(from, count, sf, 0));
if (NOLp == nullptr) {
- ExternalAddress no_overlap(no_overlap_target);
+ RuntimeAddress no_overlap(no_overlap_target);
__ jump_cc(Assembler::belowEqual, no_overlap);
__ cmpptr(to, end_from);
__ jump_cc(Assembler::aboveEqual, no_overlap);
@@ -2627,7 +2627,6 @@ address StubGenerator::generate_unsafe_setmemory(const char *name,
// Fill words
{
- Label L_wordsTail, L_wordsLoop, L_wordsTailLoop;
UnsafeMemoryAccessMark umam(this, true, true);
// At this point, we know the lower bit of size is zero and a
@@ -2641,7 +2640,6 @@ address StubGenerator::generate_unsafe_setmemory(const char *name,
// Fill QUADWORDs
{
- Label L_qwordLoop, L_qwordsTail, L_qwordsTailLoop;
UnsafeMemoryAccessMark umam(this, true, true);
// At this point, we know the lower 3 bits of size are zero and a
@@ -2658,7 +2656,6 @@ address StubGenerator::generate_unsafe_setmemory(const char *name,
// Fill DWORDs
{
- Label L_dwordLoop, L_dwordsTail, L_dwordsTailLoop;
UnsafeMemoryAccessMark umam(this, true, true);
// At this point, we know the lower 2 bits of size are zero and a
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp
index 2056fa05765..5a9b0848413 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2019, 2021, Intel Corporation. All rights reserved.
+* Copyright (c) 2019, 2024, Intel Corporation. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -57,7 +57,10 @@ address StubGenerator::ghash_byte_swap_mask_addr() {
// Polynomial x^128+x^127+x^126+x^121+1
ATTRIBUTE_ALIGNED(16) static const uint64_t GHASH_POLYNOMIAL[] = {
- 0x0000000000000001UL, 0xC200000000000000UL,
+ 0x0000000000000001ULL, 0xC200000000000000ULL,
+ 0x0000000000000001ULL, 0xC200000000000000ULL,
+ 0x0000000000000001ULL, 0xC200000000000000ULL,
+ 0x0000000000000001ULL, 0xC200000000000000ULL
};
address StubGenerator::ghash_polynomial_addr() {
return (address)GHASH_POLYNOMIAL;
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp
new file mode 100644
index 00000000000..92ac78e15cb
--- /dev/null
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp
@@ -0,0 +1,502 @@
+/*
+* Copyright (c) 2024, Intel Corporation. All rights reserved.
+* Intel Math Library (LIBM) Source Code
+*
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#include "precompiled.hpp"
+#include "macroAssembler_x86.hpp"
+#include "stubGenerator_x86_64.hpp"
+
+/******************************************************************************/
+// ALGORITHM DESCRIPTION
+// ---------------------
+//
+// tanh(x)=(exp(x)-exp(-x))/(exp(x)+exp(-x))=(1-exp(-2*x))/(1+exp(-2*x))
+//
+// Let |x|=xH+xL (upper 26 bits, lower 27 bits)
+// log2(e) rounded to 26 bits (high part) plus a double precision low part is
+// L2EH+L2EL (upper 26, lower 53 bits)
+//
+// Let xH*L2EH=k+f+r`, where (k+f)*2^8*2=int(xH*L2EH*2^9),
+// f=0.b1 b2 ... b8, k integer
+// 2^{-f} is approximated as Tn[f]+Dn[f]
+// Tn stores the high 53 bits, Dn stores (2^{-f}-Tn[f]) rounded to double precision
+//
+// r=r`+xL*L2EH+|x|*L2EL, |r|<2^{-9}+2^{-14},
+// for |x| in [23/64,3*2^7)
+// e^{-2*|x|}=2^{-k-f}*2^{-r} ~ 2^{-k}*(Tn+Dn)*(1+p)=(T0+D0)*(1+p)
+//
+// For |x| in [2^{-4},2^5):
+// 2^{-r}-1 ~ p=c1*r+c2*r^2+..+c5*r^5
+// Let R=1/(1+T0+p*T0), truncated to 35 significant bits
+// R=1/(1+T0+D0+p*(T0+D0))*(1+eps), |eps|<2^{-33}
+// 1+T0+D0+p*(T0+D0)=KH+KL, where
+// KH=(1+T0+c1*r*T0)_high (leading 17 bits)
+// KL=T0_low+D0+(c1*r*T0)_low+c1*r*D0+(c2*r^2+..c5*r^5)*T0
+// eps ~ (R*KH-1)+R*KL
+// 1/(1+T0+D0+p*(T0+D0)) ~ R-R*eps
+// The result is approximated as (1-T0-D0-(T0+D0)*p)*(R-R*eps)
+// 1-T0-D0-(T0+D0)*p=-((KH-2)+KL)
+// The result is formed as
+// (KH-2)*R+(-(KH-2)*R*eps+(KL*R-KL*R*eps)), with the correct sign
+// set at the end
+//
+// For |x| in [2^{-64},2^{-4}):
+// A Taylor series expansion is used (x+p3*x^3+..+p13*x^{13})
+//
+// For |x|<2^{-64}: x is returned
+//
+// For |x|>=2^32: return +/-1
+//
+// Special cases:
+// tanh(NaN) = quiet NaN, and raise invalid exception
+// tanh(INF) = that INF
+// tanh(+/-0) = +/-0
+//
+/******************************************************************************/
+
+ATTRIBUTE_ALIGNED(4) static const juint _HALFMASK[] =
+{
+ 4160749568, 2147483647
+};
+
+ATTRIBUTE_ALIGNED(4) static const juint _ONEMASK[] =
+{
+ 0, 1072693248
+};
+
+ATTRIBUTE_ALIGNED(4) static const juint _TWOMASK[] =
+{
+ 0, 1073741824
+};
+
+ATTRIBUTE_ALIGNED(16) static const juint _MASK3[] =
+{
+ 0, 4294967280, 0, 4294967280
+};
+
+ATTRIBUTE_ALIGNED(16) static const juint _RMASK[] =
+{
+ 4294705152, 4294967295, 4294705152, 4294967295
+};
+
+ATTRIBUTE_ALIGNED(16) static const juint _L2E[] =
+{
+ 1610612736, 1082594631, 4166901572, 1055174155
+};
+
+ATTRIBUTE_ALIGNED(16) static const juint _Shifter[] =
+{
+ 0, 1127743488, 0, 3275227136
+};
+
+ATTRIBUTE_ALIGNED(16) static const juint _cv[] =
+{
+ 3884607281, 3168131199, 3607404735, 3190582024, 1874480759,
+ 1032041131, 4286760334, 1053736893, 4277811695, 3211144770,
+ 0, 0
+};
+
+ATTRIBUTE_ALIGNED(4) static const juint _pv[] =
+{
+ 236289503, 1064135997, 463583772, 3215696314, 1441186365,
+ 3212977891, 286331153, 1069617425, 2284589306, 1066820852,
+ 1431655765, 3218429269
+};
+
+ATTRIBUTE_ALIGNED(16) static const juint _T2_neg_f[] =
+{
+ 0, 1072693248, 0, 0, 1797923801, 1072687577,
+ 1950547427, 1013229059, 730821105, 1072681922, 2523232743, 1012067188,
+ 915592468, 1072676282, 352947894, 3161024371, 2174652632, 1072670657,
+ 4087714590, 1014450259, 35929225, 1072665048, 2809788041, 3159436968,
+ 2912730644, 1072659453, 3490067722, 3163405074, 2038973688, 1072653874,
+ 892941374, 1016046459, 1533953344, 1072648310, 769171851, 1015665633,
+ 1222472308, 1072642761, 1054357470, 3161021018, 929806999, 1072637227,
+ 3205336643, 1015259557, 481706282, 1072631708, 1696079173, 3162710528,
+ 3999357479, 1072626203, 2258941616, 1015924724, 2719515920, 1072620714,
+ 2760332941, 1015137933, 764307441, 1072615240, 3021057420, 3163329523,
+ 2256325230, 1072609780, 580117746, 1015317295, 2728693978, 1072604335,
+ 396109971, 3163462691, 2009970496, 1072598905, 2159039665, 3162572948,
+ 4224142467, 1072593489, 3389820386, 1015207202, 610758006, 1072588089,
+ 1965209397, 3161866232, 3884662774, 1072582702, 2158611599, 1014210185,
+ 991358482, 1072577331, 838715019, 3163157668, 351641897, 1072571974,
+ 2172261526, 3163010599, 1796832535, 1072566631, 3176955716, 3160585513,
+ 863738719, 1072561303, 1326992220, 3162613197, 1679558232, 1072555989,
+ 2390342287, 3163333970, 4076975200, 1072550689, 2029000899, 1015208535,
+ 3594158869, 1072545404, 2456521700, 3163256561, 64696965, 1072540134,
+ 1768797490, 1015816960, 1912561781, 1072534877, 3147495102, 1015678253,
+ 382305176, 1072529635, 2347622376, 3162578625, 3898795731, 1072524406,
+ 1249994144, 1011869818, 3707479175, 1072519192, 3613079303, 1014164738,
+ 3939148246, 1072513992, 3210352148, 1015274323, 135105010, 1072508807,
+ 1906148728, 3163375739, 721996136, 1072503635, 563754734, 1015371318,
+ 1242007932, 1072498477, 1132034716, 3163339831, 1532734324, 1072493333,
+ 3094216535, 3163162857, 1432208378, 1072488203, 1401068914, 3162363963,
+ 778901109, 1072483087, 2248183955, 3161268751, 3706687593, 1072477984,
+ 3521726940, 1013253067, 1464976603, 1072472896, 3507292405, 3161977534,
+ 2483480501, 1072467821, 1216371780, 1013034172, 2307442995, 1072462760,
+ 3190117721, 3162404539, 777507147, 1072457713, 4282924205, 1015187533,
+ 2029714210, 1072452679, 613660079, 1015099143, 1610600570, 1072447659,
+ 3766732298, 1015760183, 3657065772, 1072442652, 399025623, 3162957078,
+ 3716502172, 1072437659, 2303740125, 1014042725, 1631695677, 1072432680,
+ 2717633076, 3162344026, 1540824585, 1072427714, 1064017011, 3163487690,
+ 3287523847, 1072422761, 1625971539, 3157009955, 2420883922, 1072417822,
+ 2049810052, 1014119888, 3080351519, 1072412896, 3379126788, 3157218001,
+ 815859274, 1072407984, 240396590, 3163487443, 4062661092, 1072403084,
+ 1422616006, 3163255318, 4076559943, 1072398198, 2119478331, 3160758351,
+ 703710506, 1072393326, 1384660846, 1015195891, 2380618042, 1072388466,
+ 3149557219, 3163320799, 364333489, 1072383620, 3923737744, 3161421373,
+ 3092190715, 1072378786, 814012168, 3159523422, 1822067026, 1072373966,
+ 1241994956, 1015340290, 697153126, 1072369159, 1283515429, 3163283189,
+ 3861050111, 1072364364, 254893773, 3162813180, 2572866477, 1072359583,
+ 878562433, 1015521741, 977020788, 1072354815, 3065100517, 1015541563,
+ 3218338682, 1072350059, 3404164304, 3162477108, 557149882, 1072345317,
+ 3672720709, 1014537265, 1434058175, 1072340587, 251133233, 1015085769,
+ 1405169241, 1072335870, 2998539689, 3162830951, 321958744, 1072331166,
+ 3401933767, 1015794558, 2331271250, 1072326474, 812057446, 1012207446,
+ 2990417245, 1072321795, 3683467745, 3163369326, 2152073944, 1072317129,
+ 1486860576, 3163203456, 3964284211, 1072312475, 2111583915, 1015427164,
+ 3985553595, 1072307834, 4002146062, 1015834136, 2069751141, 1072303206,
+ 1562170675, 3162724681, 2366108318, 1072298590, 2867985102, 3161762254,
+ 434316067, 1072293987, 2028358766, 1013458122, 424392917, 1072289396,
+ 2749202995, 3162838718, 2191782032, 1072284817, 2960257726, 1013742662,
+ 1297350157, 1072280251, 1308022040, 3163412558, 1892288442, 1072275697,
+ 2446255666, 3162600381, 3833209506, 1072271155, 2722920684, 1013754842,
+ 2682146384, 1072266626, 2082178513, 3163363419, 2591453363, 1072262109,
+ 2132396182, 3159074198, 3418903055, 1072257604, 2527457337, 3160820604,
+ 727685349, 1072253112, 2038246809, 3162358742, 2966275557, 1072248631,
+ 2176155324, 3159842759, 1403662306, 1072244163, 2788809599, 3161671007,
+ 194117574, 1072239707, 777528612, 3163412089, 3492293770, 1072235262,
+ 2248032210, 1015386826, 2568320822, 1072230830, 2732824428, 1014352915,
+ 1577608921, 1072226410, 1875489510, 3162968394, 380978316, 1072222002,
+ 854188970, 3160462686, 3134592888, 1072217605, 4232266862, 1015991134,
+ 1110089947, 1072213221, 1451641639, 1015474673, 2759350287, 1072208848,
+ 1148526634, 1015894933, 3649726105, 1072204487, 4085036346, 1015649474,
+ 3643909174, 1072200138, 3537586109, 1014354647, 2604962541, 1072195801,
+ 2614425274, 3163539192, 396319521, 1072191476, 4172420816, 3159074632,
+ 1176749997, 1072187162, 2738998779, 3162035844, 515457527, 1072182860,
+ 836709333, 1015651226, 2571947539, 1072178569, 3558159064, 3163376669,
+ 2916157145, 1072174290, 219487565, 1015309367, 1413356050, 1072170023,
+ 1651349291, 3162668166, 2224145553, 1072165767, 3482522030, 3161489169,
+ 919555682, 1072161523, 3121969534, 1012948226, 1660913392, 1072157290,
+ 4218599604, 1015135707, 19972402, 1072153069, 3507899862, 1016009292,
+ 158781403, 1072148859, 2221464712, 3163286453, 1944781191, 1072144660,
+ 3993278767, 3161724279, 950803702, 1072140473, 1655364926, 1015237032,
+ 1339972927, 1072136297, 167908909, 1015572152, 2980802057, 1072132132,
+ 378619896, 1015773303, 1447192521, 1072127979, 1462857171, 3162514521,
+ 903334909, 1072123837, 1636462108, 1015039997, 1218806132, 1072119706,
+ 1818613052, 3162548441, 2263535754, 1072115586, 752233586, 3162639008,
+ 3907805044, 1072111477, 2257091225, 3161550407, 1727278727, 1072107380,
+ 3562710623, 1011471940, 4182873220, 1072103293, 629542646, 3161996303,
+ 2555984613, 1072099218, 2652555442, 3162552692, 1013258799, 1072095154,
+ 1748797611, 3160129082, 3721688645, 1072091100, 3069276937, 1015839401,
+ 1963711167, 1072087058, 1744767757, 3160574294, 4201977662, 1072083026,
+ 748330254, 1013594357, 1719614413, 1072079006, 330458198, 3163282740,
+ 2979960120, 1072074996, 2599109725, 1014498493, 3561793907, 1072070997,
+ 1157054053, 1011890350, 3339203574, 1072067009, 1483497780, 3162408754,
+ 2186617381, 1072063032, 2270764084, 3163272713, 4273770423, 1072059065,
+ 3383180809, 3163218901, 885834528, 1072055110, 1973258547, 3162261564,
+ 488188413, 1072051165, 3199821029, 1015564048, 2956612997, 1072047230,
+ 2118169751, 3162735553, 3872257780, 1072043306, 1253592103, 1015958334,
+ 3111574537, 1072039393, 2606161479, 3162759746, 551349105, 1072035491,
+ 3821916050, 3162106589, 363667784, 1072031599, 813753950, 1015785209,
+ 2425981843, 1072027717, 2830390851, 3163346599, 2321106615, 1072023846,
+ 2171176610, 1009535771, 4222122499, 1072019985, 1277378074, 3163256737,
+ 3712504873, 1072016135, 88491949, 1015427660, 671025100, 1072012296,
+ 3832014351, 3163022030, 3566716925, 1072008466, 1536826856, 1014142433,
+ 3689071823, 1072004647, 2321004996, 3162552716, 917841882, 1072000839,
+ 18715565, 1015659308, 3723038930, 1071997040, 378465264, 3162569582,
+ 3395129871, 1071993252, 4025345435, 3162335388, 4109806887, 1071989474,
+ 422403966, 1014469229, 1453150082, 1071985707, 498154669, 3161488062,
+ 3896463087, 1071981949, 1139797873, 3161233805, 2731501122, 1071978202,
+ 1774031855, 3162470021, 2135241198, 1071974465, 1236747871, 1013589147,
+ 1990012071, 1071970738, 3529070563, 3162813193, 2178460671, 1071967021,
+ 777878098, 3162842493, 2583551245, 1071963314, 3161094195, 1015606491,
+ 3088564500, 1071959617, 1762311517, 1015045673, 3577096743, 1071955930,
+ 2951496418, 1013793687, 3933059031, 1071952253, 2133366768, 3161531832,
+ 4040676318, 1071948586, 4090609238, 1015663458, 3784486610, 1071944929,
+ 1581883040, 3161698953, 3049340112, 1071941282, 3062915824, 1013170595,
+ 1720398391, 1071937645, 3980678963, 3163300080, 3978100823, 1071934017,
+ 3513027190, 1015845963, 1118294578, 1071930400, 2197495694, 3159909401,
+ 1617004845, 1071926792, 82804944, 1010342778, 1065662932, 1071923194,
+ 2533670915, 1014530238, 3645941911, 1071919605, 3814685081, 3161573341,
+ 654919306, 1071916027, 3232961757, 3163047469, 569847338, 1071912458,
+ 472945272, 3159290729, 3278348324, 1071908898, 3069497416, 1014750712,
+ 78413852, 1071905349, 4183226867, 3163017251, 3743175029, 1071901808,
+ 2072812490, 3162175075, 1276261410, 1071898278, 300981948, 1014684169,
+ 1156440435, 1071894757, 2351451249, 1013967056, 3272845541, 1071891245,
+ 928852419, 3163488248, 3219942644, 1071887743, 3798990616, 1015368806,
+ 887463927, 1071884251, 3596744163, 3160794166, 460407023, 1071880768,
+ 4237175092, 3163138469, 1829099622, 1071877294, 1016661181, 3163461005,
+ 589198666, 1071873830, 2664346172, 3163157962, 926591435, 1071870375,
+ 3208833762, 3162913514, 2732492859, 1071866929, 2691479646, 3162255684,
+ 1603444721, 1071863493, 1548633640, 3162201326, 1726216749, 1071860066,
+ 2466808228, 3161676405, 2992903935, 1071856648, 2218154406, 1015228193,
+ 1000925746, 1071853240, 1018491672, 3163309544, 4232894513, 1071849840,
+ 2383938684, 1014668519, 3991843581, 1071846450, 4092853457, 1014585763,
+ 171030293, 1071843070, 3526460132, 1014428778, 1253935211, 1071839698,
+ 1395382931, 3159702613, 2839424854, 1071836335, 1171596163, 1013041679,
+ 526652809, 1071832982, 4223459736, 1015879375, 2799960843, 1071829637,
+ 1423655381, 1015022151, 964107055, 1071826302, 2800439588, 3162833221,
+ 3504003472, 1071822975, 3594001060, 3157330652, 1724976915, 1071819658,
+ 420909223, 3163117379, 4112506593, 1071816349, 2947355221, 1014371048,
+ 1972484976, 1071813050, 675290301, 3161640050, 3790955393, 1071809759,
+ 2352942462, 3163180090, 874372905, 1071806478, 100263788, 1015940732,
+ 1709341917, 1071803205, 2571168217, 1014152499, 1897844341, 1071799941,
+ 1254300460, 1015275938, 1337108031, 1071796686, 3203724452, 1014677845,
+ 4219606026, 1071793439, 2434574742, 1014681548, 1853186616, 1071790202,
+ 3066496371, 1015656574, 2725843665, 1071786973, 1433917087, 1014838523,
+ 2440944790, 1071783753, 2492769774, 1014147454, 897099801, 1071780542,
+ 754756297, 1015241005, 2288159958, 1071777339, 2169144469, 1014876021,
+ 2218315341, 1071774145, 2694295388, 3163288868, 586995997, 1071770960,
+ 41662348, 3162627992, 1588871207, 1071767783, 143439582, 3162963416,
+ 828946858, 1071764615, 10642492, 1015939438, 2502433899, 1071761455,
+ 2148595913, 1015023991, 2214878420, 1071758304, 892270087, 3163116422,
+ 4162030108, 1071755161, 2763428480, 1015529349, 3949972341, 1071752027,
+ 2068408548, 1014913868, 1480023343, 1071748902, 2247196168, 1015327453,
+ 948735466, 1071745785, 3516338028, 3162574883, 2257959872, 1071742676,
+ 3802946148, 1012964927, 1014845819, 1071739576, 3117910646, 3161559105,
+ 1416741826, 1071736484, 2196380210, 1011413563, 3366293073, 1071733400,
+ 3119426314, 1014120554, 2471440686, 1071730325, 968836267, 3162214888,
+ 2930322912, 1071727258, 2599499422, 3162714047, 351405227, 1071724200,
+ 3125337328, 3159822479, 3228316108, 1071721149, 3010241991, 3158422804,
+ 2875075254, 1071718107, 4144233330, 3163333716, 3490863953, 1071715073,
+ 960797498, 3162948880, 685187902, 1071712048, 378731989, 1014843115,
+ 2952712987, 1071709030, 3293494651, 3160120301, 1608493509, 1071706021,
+ 3159622171, 3162807737, 852742562, 1071703020, 667253586, 1009793559,
+ 590962156, 1071700027, 3829346666, 3163275597, 728909815, 1071697042,
+ 383930225, 1015029468, 1172597893, 1071694065, 114433263, 1015347593,
+ 1828292879, 1071691096, 1255956747, 1015588398, 2602514713, 1071688135,
+ 2268929336, 1014354284, 3402036099, 1071685182, 405889334, 1015105656,
+ 4133881824, 1071682237, 2148155345, 3162931299, 410360776, 1071679301,
+ 1269990655, 1011975870, 728934454, 1071676372, 1413842688, 1014178612,
+ 702412510, 1071673451, 3803266087, 3162280415, 238821257, 1071670538,
+ 1469694871, 3162884987, 3541402996, 1071667632, 2759177317, 1014854626,
+ 1928746161, 1071664735, 983617676, 1014285177, 3899555717, 1071661845,
+ 427280750, 3162546972, 772914124, 1071658964, 4004372762, 1012230161,
+ 1048019041, 1071656090, 1398474845, 3160510595, 339411585, 1071653224,
+ 264588982, 3161636657, 2851812149, 1071650365, 2595802551, 1015767337,
+ 4200250559, 1071647514, 2808127345, 3161781938
+};
+
+#define __ _masm->
+
+address StubGenerator::generate_libmTanh() {
+ StubCodeMark mark(this, "StubRoutines", "libmTanh");
+ address start = __ pc();
+
+ Label L_2TAG_PACKET_0_0_1, L_2TAG_PACKET_1_0_1, L_2TAG_PACKET_2_0_1, L_2TAG_PACKET_3_0_1;
+ Label L_2TAG_PACKET_4_0_1, L_2TAG_PACKET_5_0_1;
+ Label B1_2, B1_4;
+
+ address HALFMASK = (address)_HALFMASK;
+ address ONEMASK = (address)_ONEMASK;
+ address TWOMASK = (address)_TWOMASK;
+ address MASK3 = (address)_MASK3;
+ address RMASK = (address)_RMASK;
+ address L2E = (address)_L2E;
+ address Shifter = (address)_Shifter;
+ address cv = (address)_cv;
+ address pv = (address)_pv;
+ address T2_neg_f = (address) _T2_neg_f;
+
+ __ enter(); // required for proper stackwalking of RuntimeStub frame
+
+ __ bind(B1_2);
+ __ movsd(xmm3, ExternalAddress(HALFMASK), r11 /*rscratch*/);
+ __ xorpd(xmm4, xmm4);
+ __ movsd(xmm1, ExternalAddress(L2E), r11 /*rscratch*/);
+ __ movsd(xmm2, ExternalAddress(L2E + 8), r11 /*rscratch*/);
+ __ movl(rax, 32768);
+ __ pinsrw(xmm4, rax, 3);
+ __ movsd(xmm6, ExternalAddress(Shifter), r11 /*rscratch*/);
+ __ pextrw(rcx, xmm0, 3);
+ __ andpd(xmm3, xmm0);
+ __ andnpd(xmm4, xmm0);
+ __ pshufd(xmm5, xmm4, 68);
+ __ movl(rdx, 32768);
+ __ andl(rdx, rcx);
+ __ andl(rcx, 32767);
+ __ subl(rcx, 16304);
+ __ cmpl(rcx, 144);
+ __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_0_0_1);
+ __ subsd(xmm4, xmm3);
+ __ mulsd(xmm3, xmm1);
+ __ mulsd(xmm2, xmm5);
+ __ cvtsd2siq(rax, xmm3);
+ __ movq(xmm7, xmm3);
+ __ addsd(xmm3, xmm6);
+ __ mulsd(xmm1, xmm4);
+ __ movsd(xmm4, ExternalAddress(ONEMASK), r11 /*rscratch*/);
+ __ subsd(xmm3, xmm6);
+ __ xorpd(xmm0, xmm0);
+ __ addsd(xmm2, xmm1);
+ __ subsd(xmm7, xmm3);
+ __ movdqu(xmm6, ExternalAddress(cv), r11 /*rscratch*/);
+ __ addsd(xmm2, xmm7);
+ __ movl(rcx, 255);
+ __ andl(rcx, rax);
+ __ addl(rcx, rcx);
+ __ lea(r8, ExternalAddress(T2_neg_f));
+ __ movdqu(xmm5, Address(r8, rcx, Address::times(8)));
+ __ shrl(rax, 4);
+ __ andl(rax, 65520);
+ __ subl(rax, 16368);
+ __ negl(rax);
+ __ pinsrw(xmm0, rax, 3);
+ __ movdqu(xmm1, ExternalAddress(cv + 16), r11 /*rscratch*/);
+ __ pshufd(xmm0, xmm0, 68);
+ __ mulpd(xmm0, xmm5);
+ __ movsd(xmm7, ExternalAddress(cv + 32), r11 /*rscratch*/);
+ __ pshufd(xmm2, xmm2, 68);
+ __ movq(xmm5, xmm4);
+ __ addsd(xmm4, xmm0);
+ __ mulpd(xmm6, xmm2);
+ __ mulsd(xmm7, xmm2);
+ __ mulpd(xmm2, xmm2);
+ __ addpd(xmm1, xmm6);
+ __ mulsd(xmm2, xmm2);
+ __ movsd(xmm3, ExternalAddress(ONEMASK), r11 /*rscratch*/);
+ __ mulpd(xmm1, xmm2);
+ __ pshufd(xmm6, xmm1, 78);
+ __ addsd(xmm1, xmm6);
+ __ movq(xmm6, xmm1);
+ __ addsd(xmm1, xmm7);
+ __ mulsd(xmm1, xmm0);
+ __ addsd(xmm1, xmm4);
+ __ andpd(xmm4, ExternalAddress(MASK3), r11 /*rscratch*/);
+ __ divsd(xmm5, xmm1);
+ __ subsd(xmm3, xmm4);
+ __ pshufd(xmm1, xmm0, 238);
+ __ addsd(xmm3, xmm0);
+ __ movq(xmm2, xmm4);
+ __ addsd(xmm3, xmm1);
+ __ mulsd(xmm1, xmm7);
+ __ mulsd(xmm7, xmm0);
+ __ addsd(xmm3, xmm1);
+ __ addsd(xmm4, xmm7);
+ __ movsd(xmm1, ExternalAddress(RMASK), r11 /*rscratch*/);
+ __ mulsd(xmm6, xmm0);
+ __ andpd(xmm4, ExternalAddress(MASK3), r11 /*rscratch*/);
+ __ addsd(xmm3, xmm6);
+ __ movq(xmm6, xmm4);
+ __ subsd(xmm2, xmm4);
+ __ addsd(xmm2, xmm7);
+ __ movsd(xmm7, ExternalAddress(ONEMASK), r11 /*rscratch*/);
+ __ andpd(xmm5, xmm1);
+ __ addsd(xmm3, xmm2);
+ __ mulsd(xmm4, xmm5);
+ __ xorpd(xmm2, xmm2);
+ __ mulsd(xmm3, xmm5);
+ __ subsd(xmm6, ExternalAddress(TWOMASK), r11 /*rscratch*/);
+ __ subsd(xmm4, xmm7);
+ __ xorl(rdx, 32768);
+ __ pinsrw(xmm2, rdx, 3);
+ __ addsd(xmm4, xmm3);
+ __ mulsd(xmm6, xmm5);
+ __ movq(xmm1, xmm3);
+ __ mulsd(xmm3, xmm4);
+ __ movq(xmm0, xmm6);
+ __ mulsd(xmm6, xmm4);
+ __ subsd(xmm1, xmm3);
+ __ subsd(xmm1, xmm6);
+ __ addsd(xmm0, xmm1);
+ __ xorpd(xmm0, xmm2);
+ __ jmp(B1_4);
+
+ __ bind(L_2TAG_PACKET_0_0_1);
+ __ addl(rcx, 960);
+ __ cmpl(rcx, 1104);
+ __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_1_0_1);
+ __ movdqu(xmm2, ExternalAddress(pv), r11 /*rscratch*/);
+ __ pshufd(xmm1, xmm0, 68);
+ __ movdqu(xmm3, ExternalAddress(pv + 16), r11 /*rscratch*/);
+ __ mulpd(xmm1, xmm1);
+ __ movdqu(xmm4, ExternalAddress(pv + 32), r11 /*rscratch*/);
+ __ mulpd(xmm2, xmm1);
+ __ pshufd(xmm5, xmm1, 68);
+ __ addpd(xmm2, xmm3);
+ __ mulsd(xmm5, xmm5);
+ __ mulpd(xmm2, xmm1);
+ __ mulsd(xmm5, xmm5);
+ __ addpd(xmm2, xmm4);
+ __ mulpd(xmm2, xmm5);
+ __ pshufd(xmm5, xmm2, 238);
+ __ addsd(xmm2, xmm5);
+ __ mulsd(xmm2, xmm0);
+ __ addsd(xmm0, xmm2);
+ __ jmp(B1_4);
+
+ __ bind(L_2TAG_PACKET_1_0_1);
+ __ addl(rcx, 15344);
+ __ cmpl(rcx, 16448);
+ __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_2_0_1);
+ __ cmpl(rcx, 16);
+ __ jcc(Assembler::below, L_2TAG_PACKET_3_0_1);
+ __ xorpd(xmm2, xmm2);
+ __ movl(rax, 17392);
+ __ pinsrw(xmm2, rax, 3);
+ __ mulsd(xmm2, xmm0);
+ __ addsd(xmm2, xmm0);
+ __ jmp(B1_4);
+
+ __ bind(L_2TAG_PACKET_3_0_1);
+ __ movq(xmm2, xmm0);
+ __ mulsd(xmm2, xmm2);
+ __ jmp(B1_4);
+
+ __ bind(L_2TAG_PACKET_2_0_1);
+ __ cmpl(rcx, 32752);
+ __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_4_0_1);
+ __ xorpd(xmm2, xmm2);
+ __ movl(rcx, 15344);
+ __ pinsrw(xmm2, rcx, 3);
+ __ movq(xmm3, xmm2);
+ __ mulsd(xmm2, xmm2);
+ __ addsd(xmm2, xmm3);
+
+ __ bind(L_2TAG_PACKET_5_0_1);
+ __ xorpd(xmm0, xmm0);
+ __ orl(rdx, 16368);
+ __ pinsrw(xmm0, rdx, 3);
+ __ jmp(B1_4);
+
+ __ bind(L_2TAG_PACKET_4_0_1);
+ __ movq(xmm2, xmm0);
+ __ movdl(rax, xmm0);
+ __ psrlq(xmm2, 20);
+ __ movdl(rcx, xmm2);
+ __ orl(rcx, rax);
+ __ cmpl(rcx, 0);
+ __ jcc(Assembler::equal, L_2TAG_PACKET_5_0_1);
+ __ addsd(xmm0, xmm0);
+
+ __ bind(B1_4);
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+ __ ret(0);
+
+ return start;
+}
+
+#undef __
diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp
index fe2bf67afc9..76ad498be0e 100644
--- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp
+++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.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
@@ -178,7 +178,7 @@ address TemplateInterpreterGenerator::generate_exception_handler_common(
rarg, rarg2);
}
// throw exception
- __ jump(ExternalAddress(Interpreter::throw_exception_entry()));
+ __ jump(RuntimeAddress(Interpreter::throw_exception_entry()));
return entry;
}
@@ -545,8 +545,8 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) {
// Note: the restored frame is not necessarily interpreted.
// Use the shared runtime version of the StackOverflowError.
- assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "stub not yet generated");
- __ jump(ExternalAddress(StubRoutines::throw_StackOverflowError_entry()));
+ assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "stub not yet generated");
+ __ jump(RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry()));
// all done with frame size check
__ bind(after_frame_check_pop);
NOT_LP64(__ pop(rsi));
diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_32.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_32.cpp
index ba9eb32e8c1..75611524e3b 100644
--- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_32.cpp
+++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_32.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
@@ -373,6 +373,10 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
// [ lo(arg) ]
// [ hi(arg) ]
//
+ if (kind == Interpreter::java_lang_math_tanh) {
+ return nullptr;
+ }
+
if (kind == Interpreter::java_lang_math_fmaD) {
if (!UseFMA) {
return nullptr; // Generate a vanilla entry
diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp
index 26eea4c1d6a..5ea2d8eba25 100644
--- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp
+++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_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
@@ -465,6 +465,10 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
} else {
__ call_VM_leaf0(CAST_FROM_FN_PTR(address, SharedRuntime::dtan));
}
+ } else if (kind == Interpreter::java_lang_math_tanh) {
+ assert(StubRoutines::dtanh() != nullptr, "not initialized");
+ __ movdbl(xmm0, Address(rsp, wordSize));
+ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dtanh())));
} else if (kind == Interpreter::java_lang_math_abs) {
assert(StubRoutines::x86::double_sign_mask() != nullptr, "not initialized");
__ movdbl(xmm0, Address(rsp, wordSize));
diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp
index 6446ec65987..527d961259e 100644
--- a/src/hotspot/cpu/x86/templateTable_x86.cpp
+++ b/src/hotspot/cpu/x86/templateTable_x86.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
@@ -774,7 +774,7 @@ void TemplateTable::index_check_without_pop(Register array, Register index) {
__ jccb(Assembler::below, skip);
// Pass array to create more detailed exceptions.
__ mov(NOT_LP64(rax) LP64_ONLY(c_rarg1), array);
- __ jump(ExternalAddress(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry));
+ __ jump(RuntimeAddress(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry));
__ bind(skip);
}
@@ -1152,7 +1152,7 @@ void TemplateTable::aastore() {
// Come here on failure
// object is at TOS
- __ jump(ExternalAddress(Interpreter::_throw_ArrayStoreException_entry));
+ __ jump(RuntimeAddress(Interpreter::_throw_ArrayStoreException_entry));
// Come here on success
__ bind(ok_is_subtype);
@@ -1432,7 +1432,7 @@ void TemplateTable::ldiv() {
// generate explicit div0 check
__ testq(rcx, rcx);
__ jump_cc(Assembler::zero,
- ExternalAddress(Interpreter::_throw_ArithmeticException_entry));
+ RuntimeAddress(Interpreter::_throw_ArithmeticException_entry));
// Note: could xor rax and rcx and compare with (-1 ^ min_int). If
// they are not equal, one could do a normal division (no correction
// needed), which may speed up this implementation for the common case.
@@ -1445,7 +1445,7 @@ void TemplateTable::ldiv() {
// check if y = 0
__ orl(rax, rdx);
__ jump_cc(Assembler::zero,
- ExternalAddress(Interpreter::_throw_ArithmeticException_entry));
+ RuntimeAddress(Interpreter::_throw_ArithmeticException_entry));
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::ldiv));
__ addptr(rsp, 4 * wordSize); // take off temporaries
#endif
@@ -1458,7 +1458,7 @@ void TemplateTable::lrem() {
__ pop_l(rax);
__ testq(rcx, rcx);
__ jump_cc(Assembler::zero,
- ExternalAddress(Interpreter::_throw_ArithmeticException_entry));
+ RuntimeAddress(Interpreter::_throw_ArithmeticException_entry));
// Note: could xor rax and rcx and compare with (-1 ^ min_int). If
// they are not equal, one could do a normal division (no correction
// needed), which may speed up this implementation for the common case.
@@ -1472,7 +1472,7 @@ void TemplateTable::lrem() {
// check if y = 0
__ orl(rax, rdx);
__ jump_cc(Assembler::zero,
- ExternalAddress(Interpreter::_throw_ArithmeticException_entry));
+ RuntimeAddress(Interpreter::_throw_ArithmeticException_entry));
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::lrem));
__ addptr(rsp, 4 * wordSize);
#endif
@@ -2579,8 +2579,7 @@ void TemplateTable::_return(TosState state) {
Register robj = LP64_ONLY(c_rarg1) NOT_LP64(rax);
__ movptr(robj, aaddress(0));
__ load_klass(rdi, robj, rscratch1);
- __ movl(rdi, Address(rdi, Klass::access_flags_offset()));
- __ testl(rdi, JVM_ACC_HAS_FINALIZER);
+ __ testb(Address(rdi, Klass::misc_flags_offset()), KlassFlags::_misc_has_finalizer);
Label skip_register_finalizer;
__ jcc(Assembler::zero, skip_register_finalizer);
@@ -4049,6 +4048,7 @@ void TemplateTable::_new() {
__ push(rcx); // save the contexts of klass for initializing the header
// make sure klass is initialized
+ // init_state needs acquire, but x86 is TSO, and so we are already good.
#ifdef _LP64
assert(VM_Version::supports_fast_class_init_checks(), "must support fast class initialization checks");
__ clinit_barrier(rcx, r15_thread, nullptr /*L_fast_path*/, &slow_case);
@@ -4222,7 +4222,7 @@ void TemplateTable::checkcast() {
// Come here on failure
__ push_ptr(rdx);
// object is at TOS
- __ jump(ExternalAddress(Interpreter::_throw_ClassCastException_entry));
+ __ jump(RuntimeAddress(Interpreter::_throw_ClassCastException_entry));
// Come here on success
__ bind(ok_is_subtype);
@@ -4340,7 +4340,7 @@ void TemplateTable::_breakpoint() {
void TemplateTable::athrow() {
transition(atos, vtos);
__ null_check(rax);
- __ jump(ExternalAddress(Interpreter::throw_exception_entry()));
+ __ jump(RuntimeAddress(Interpreter::throw_exception_entry()));
}
//-----------------------------------------------------------------------------
diff --git a/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp b/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp
index e5075e180d9..d795c751d02 100644
--- a/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp
+++ b/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "prims/upcallLinker.hpp"
-address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
+address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
diff --git a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp
index 82179f9022e..bc261bfd93f 100644
--- a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp
+++ b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp
@@ -23,7 +23,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
-#include "code/codeBlob.hpp"
+#include "classfile/javaClasses.hpp"
#include "code/codeBlob.hpp"
#include "code/vmreg.inline.hpp"
#include "compiler/disassembler.hpp"
@@ -169,10 +169,10 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr
__ block_comment("} restore_callee_saved_regs ");
}
-static const int upcall_stub_code_base_size = 1024;
+static const int upcall_stub_code_base_size = 1200;
static const int upcall_stub_size_per_arg = 16;
-address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
+address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
@@ -281,7 +281,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
__ block_comment("{ on_entry");
__ vzeroupper();
__ lea(c_rarg0, Address(rsp, frame_data_offset));
- __ movptr(c_rarg1, (intptr_t)receiver);
// stack already aligned
__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, UpcallLinker::on_entry)));
__ movptr(r15_thread, rax);
@@ -297,12 +296,10 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
arg_shuffle.generate(_masm, shuffle_reg, abi._shadow_space_bytes, 0);
__ block_comment("} argument shuffle");
- __ block_comment("{ receiver ");
- __ get_vm_result(j_rarg0, r15_thread);
- __ block_comment("} receiver ");
-
- __ mov_metadata(rbx, entry);
- __ movptr(Address(r15_thread, JavaThread::callee_target_offset()), rbx); // just in case callee is deoptimized
+ __ block_comment("{ load target ");
+ __ movptr(j_rarg0, (intptr_t)receiver);
+ __ call(RuntimeAddress(StubRoutines::upcall_stub_load_target())); // puts target Method* in rbx
+ __ block_comment("} load target ");
__ push_cont_fastpath();
@@ -377,7 +374,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
#ifndef PRODUCT
stringStream ss;
- ss.print("upcall_stub_%s", entry->signature()->as_C_string());
+ ss.print("upcall_stub_%s", signature->as_C_string());
const char* name = _masm->code_string(ss.freeze());
#else // PRODUCT
const char* name = "upcall_stub";
diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp
index 02e147743cb..63347c51d60 100644
--- a/src/hotspot/cpu/x86/vm_version_x86.cpp
+++ b/src/hotspot/cpu/x86/vm_version_x86.cpp
@@ -53,13 +53,13 @@ const char* VM_Version::_features_names[] = { CPU_FEATURE_FLAGS(DECLARE_CPU_FEAT
#undef DECLARE_CPU_FEATURE_FLAG
// Address of instruction which causes SEGV
-address VM_Version::_cpuinfo_segv_addr = 0;
+address VM_Version::_cpuinfo_segv_addr = nullptr;
// Address of instruction after the one which causes SEGV
-address VM_Version::_cpuinfo_cont_addr = 0;
+address VM_Version::_cpuinfo_cont_addr = nullptr;
// Address of instruction which causes APX specific SEGV
-address VM_Version::_cpuinfo_segv_addr_apx = 0;
+address VM_Version::_cpuinfo_segv_addr_apx = nullptr;
// Address of instruction after the one which causes APX specific SEGV
-address VM_Version::_cpuinfo_cont_addr_apx = 0;
+address VM_Version::_cpuinfo_cont_addr_apx = nullptr;
static BufferBlob* stub_blob;
static const int stub_size = 2000;
@@ -437,6 +437,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
__ cmpl(rax, 0x80000);
__ jcc(Assembler::notEqual, vector_save_restore);
+#ifndef PRODUCT
bool save_apx = UseAPX;
VM_Version::set_apx_cpuFeatures();
UseAPX = true;
@@ -453,6 +454,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
__ movq(Address(rsi, 8), r31);
UseAPX = save_apx;
+#endif
#endif
__ bind(vector_save_restore);
//
@@ -1045,6 +1047,10 @@ void VM_Version::get_processor_features() {
FLAG_SET_DEFAULT(UseAPX, apx_supported ? true : false);
}
+ if (!UseAPX) {
+ _features &= ~CPU_APX_F;
+ }
+
if (UseAVX < 2) {
_features &= ~CPU_AVX2;
_features &= ~CPU_AVX_IFMA;
@@ -1054,6 +1060,7 @@ void VM_Version::get_processor_features() {
_features &= ~CPU_AVX;
_features &= ~CPU_VZEROUPPER;
_features &= ~CPU_F16C;
+ _features &= ~CPU_SHA512;
}
if (logical_processors_per_package() == 1) {
@@ -1298,7 +1305,7 @@ void VM_Version::get_processor_features() {
#ifdef _LP64
// These are only supported on 64-bit
- if (UseSHA && supports_avx2() && supports_bmi2()) {
+ if (UseSHA && supports_avx2() && (supports_bmi2() || supports_sha512())) {
if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) {
FLAG_SET_DEFAULT(UseSHA512Intrinsics, true);
}
@@ -3001,6 +3008,8 @@ uint64_t VM_Version::CpuidInfo::feature_flags() const {
xem_xcr0_eax.bits.ymm != 0) {
result |= CPU_AVX;
result |= CPU_VZEROUPPER;
+ if (sefsl1_cpuid7_eax.bits.sha512 != 0)
+ result |= CPU_SHA512;
if (std_cpuid1_ecx.bits.f16c != 0)
result |= CPU_F16C;
if (sef_cpuid7_ebx.bits.avx2 != 0) {
diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp
index d58b5a9c099..791f4a1fec7 100644
--- a/src/hotspot/cpu/x86/vm_version_x86.hpp
+++ b/src/hotspot/cpu/x86/vm_version_x86.hpp
@@ -283,7 +283,8 @@ class VM_Version : public Abstract_VM_Version {
union SefCpuid7SubLeaf1Eax {
uint32_t value;
struct {
- uint32_t : 23,
+ uint32_t sha512 : 1,
+ : 22,
avx_ifma : 1,
: 8;
} bits;
@@ -415,7 +416,8 @@ class VM_Version : public Abstract_VM_Version {
decl(CET_SS, "cet_ss", 57) /* Control Flow Enforcement - Shadow Stack */ \
decl(AVX512_IFMA, "avx512_ifma", 58) /* Integer Vector FMA instructions*/ \
decl(AVX_IFMA, "avx_ifma", 59) /* 256-bit VEX-coded variant of AVX512-IFMA*/ \
- decl(APX_F, "apx_f", 60) /* Intel Advanced Performance Extensions*/
+ decl(APX_F, "apx_f", 60) /* Intel Advanced Performance Extensions*/\
+ decl(SHA512, "sha512", 61) /* SHA512 instructions*/
#define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = (1ULL << bit),
CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_FLAG)
@@ -638,9 +640,10 @@ class VM_Version : public Abstract_VM_Version {
LP64_ONLY(static void clear_apx_test_state());
static void clean_cpuFeatures() { _features = 0; }
- static void set_avx_cpuFeatures() { _features = (CPU_SSE | CPU_SSE2 | CPU_AVX | CPU_VZEROUPPER ); }
- static void set_evex_cpuFeatures() { _features = (CPU_AVX512F | CPU_SSE | CPU_SSE2 | CPU_VZEROUPPER ); }
+ static void set_avx_cpuFeatures() { _features |= (CPU_SSE | CPU_SSE2 | CPU_AVX | CPU_VZEROUPPER ); }
+ static void set_evex_cpuFeatures() { _features |= (CPU_AVX512F | CPU_SSE | CPU_SSE2 | CPU_VZEROUPPER ); }
static void set_apx_cpuFeatures() { _features |= CPU_APX_F; }
+ static void set_bmi_cpuFeatures() { _features |= (CPU_BMI1 | CPU_BMI2 | CPU_LZCNT); }
// Initialization
static void initialize();
@@ -757,6 +760,7 @@ class VM_Version : public Abstract_VM_Version {
static bool supports_ospke() { return (_features & CPU_OSPKE) != 0; }
static bool supports_cet_ss() { return (_features & CPU_CET_SS) != 0; }
static bool supports_cet_ibt() { return (_features & CPU_CET_IBT) != 0; }
+ static bool supports_sha512() { return (_features & CPU_SHA512) != 0; }
//
// Feature identification not affected by VM flags
diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad
index d90ba901ac0..43c959bb917 100644
--- a/src/hotspot/cpu/x86/x86.ad
+++ b/src/hotspot/cpu/x86/x86.ad
@@ -1935,6 +1935,20 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) {
return false;
}
break;
+ case Op_SelectFromTwoVector:
+ if (size_in_bits < 128 || (size_in_bits < 512 && !VM_Version::supports_avx512vl())) {
+ return false;
+ }
+ if (bt == T_SHORT && !VM_Version::supports_avx512bw()) {
+ return false;
+ }
+ if (bt == T_BYTE && !VM_Version::supports_avx512_vbmi()) {
+ return false;
+ }
+ if ((bt == T_INT || bt == T_FLOAT || bt == T_DOUBLE) && !VM_Version::supports_evex()) {
+ return false;
+ }
+ break;
case Op_MaskAll:
if (!VM_Version::supports_evex()) {
return false;
@@ -2231,10 +2245,6 @@ const RegMask* Matcher::predicate_reg_mask(void) {
return &_VECTMASK_REG_mask;
}
-const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) {
- return new TypeVectMask(elemTy, length);
-}
-
// Max vector size in bytes. 0 if not supported.
int Matcher::vector_width_in_bytes(BasicType bt) {
assert(is_java_primitive(bt), "only primitive type vectors");
@@ -2457,6 +2467,10 @@ bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) {
mstack.push(m, Visit); // m = ShiftCntV
return true;
}
+ if (is_encode_and_store_pattern(n, m)) {
+ mstack.push(m, Visit);
+ return true;
+ }
return false;
}
@@ -3672,6 +3686,7 @@ instruct vconvF2HF(vec dst, vec src) %{
%}
instruct vconvF2HF_mem_reg(memory mem, vec src) %{
+ predicate(n->as_StoreVector()->memory_size() >= 16);
match(Set mem (StoreVector mem (VectorCastF2HF src)));
format %{ "vcvtps2ph $mem,$src" %}
ins_encode %{
@@ -5109,7 +5124,7 @@ instruct reductionL_avx512dq(rRegL dst, rRegL src1, vec src2, vec vtmp1, vec vtm
// =======================Float Reduction==========================================
instruct reductionF128(regF dst, vec src, vec vtmp) %{
- predicate(Matcher::vector_length(n->in(2)) <= 4); // src
+ predicate(n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) <= 4); // src
match(Set dst (AddReductionVF dst src));
match(Set dst (MulReductionVF dst src));
effect(TEMP dst, TEMP vtmp);
@@ -5123,7 +5138,7 @@ instruct reductionF128(regF dst, vec src, vec vtmp) %{
%}
instruct reduction8F(regF dst, vec src, vec vtmp1, vec vtmp2) %{
- predicate(Matcher::vector_length(n->in(2)) == 8); // src
+ predicate(n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 8); // src
match(Set dst (AddReductionVF dst src));
match(Set dst (MulReductionVF dst src));
effect(TEMP dst, TEMP vtmp1, TEMP vtmp2);
@@ -5137,7 +5152,7 @@ instruct reduction8F(regF dst, vec src, vec vtmp1, vec vtmp2) %{
%}
instruct reduction16F(regF dst, legVec src, legVec vtmp1, legVec vtmp2) %{
- predicate(Matcher::vector_length(n->in(2)) == 16); // src
+ predicate(n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 16); // src
match(Set dst (AddReductionVF dst src));
match(Set dst (MulReductionVF dst src));
effect(TEMP dst, TEMP vtmp1, TEMP vtmp2);
@@ -5150,10 +5165,79 @@ instruct reduction16F(regF dst, legVec src, legVec vtmp1, legVec vtmp2) %{
ins_pipe( pipe_slow );
%}
+
+instruct unordered_reduction2F(regF dst, regF src1, vec src2) %{
+ // Non-strictly ordered floating-point add/mul reduction for floats. This rule is
+ // intended for the VectorAPI (which allows for non-strictly ordered add/mul reduction).
+ // src1 contains reduction identity
+ predicate(!n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 2); // src2
+ match(Set dst (AddReductionVF src1 src2));
+ match(Set dst (MulReductionVF src1 src2));
+ effect(TEMP dst);
+ format %{ "vector_reduction_float $dst,$src1,$src2 ;" %}
+ ins_encode %{
+ int opcode = this->ideal_Opcode();
+ int vlen = Matcher::vector_length(this, $src2);
+ __ unordered_reduce_fp(opcode, vlen, $dst$$XMMRegister, $src2$$XMMRegister);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct unordered_reduction4F(regF dst, regF src1, vec src2, vec vtmp) %{
+ // Non-strictly ordered floating-point add/mul reduction for floats. This rule is
+ // intended for the VectorAPI (which allows for non-strictly ordered add/mul reduction).
+ // src1 contains reduction identity
+ predicate(!n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 4); // src2
+ match(Set dst (AddReductionVF src1 src2));
+ match(Set dst (MulReductionVF src1 src2));
+ effect(TEMP dst, TEMP vtmp);
+ format %{ "vector_reduction_float $dst,$src1,$src2 ; using $vtmp as TEMP" %}
+ ins_encode %{
+ int opcode = this->ideal_Opcode();
+ int vlen = Matcher::vector_length(this, $src2);
+ __ unordered_reduce_fp(opcode, vlen, $dst$$XMMRegister, $src2$$XMMRegister, $vtmp$$XMMRegister);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct unordered_reduction8F(regF dst, regF src1, vec src2, vec vtmp1, vec vtmp2) %{
+ // Non-strictly ordered floating-point add/mul reduction for floats. This rule is
+ // intended for the VectorAPI (which allows for non-strictly ordered add/mul reduction).
+ // src1 contains reduction identity
+ predicate(!n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 8); // src2
+ match(Set dst (AddReductionVF src1 src2));
+ match(Set dst (MulReductionVF src1 src2));
+ effect(TEMP dst, TEMP vtmp1, TEMP vtmp2);
+ format %{ "vector_reduction_float $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
+ ins_encode %{
+ int opcode = this->ideal_Opcode();
+ int vlen = Matcher::vector_length(this, $src2);
+ __ unordered_reduce_fp(opcode, vlen, $dst$$XMMRegister, $src2$$XMMRegister, $vtmp1$$XMMRegister, $vtmp2$$XMMRegister);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct unordered_reduction16F(regF dst, regF src1, legVec src2, legVec vtmp1, legVec vtmp2) %{
+ // Non-strictly ordered floating-point add/mul reduction for floats. This rule is
+ // intended for the VectorAPI (which allows for non-strictly ordered add/mul reduction).
+ // src1 contains reduction identity
+ predicate(!n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 16); // src2
+ match(Set dst (AddReductionVF src1 src2));
+ match(Set dst (MulReductionVF src1 src2));
+ effect(TEMP dst, TEMP vtmp1, TEMP vtmp2);
+ format %{ "vector_reduction_float $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
+ ins_encode %{
+ int opcode = this->ideal_Opcode();
+ int vlen = Matcher::vector_length(this, $src2);
+ __ unordered_reduce_fp(opcode, vlen, $dst$$XMMRegister, $src2$$XMMRegister, $vtmp1$$XMMRegister, $vtmp2$$XMMRegister);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
// =======================Double Reduction==========================================
instruct reduction2D(regD dst, vec src, vec vtmp) %{
- predicate(Matcher::vector_length(n->in(2)) == 2); // src
+ predicate(n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 2); // src
match(Set dst (AddReductionVD dst src));
match(Set dst (MulReductionVD dst src));
effect(TEMP dst, TEMP vtmp);
@@ -5167,7 +5251,7 @@ instruct reduction2D(regD dst, vec src, vec vtmp) %{
%}
instruct reduction4D(regD dst, vec src, vec vtmp1, vec vtmp2) %{
- predicate(Matcher::vector_length(n->in(2)) == 4); // src
+ predicate(n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 4); // src
match(Set dst (AddReductionVD dst src));
match(Set dst (MulReductionVD dst src));
effect(TEMP dst, TEMP vtmp1, TEMP vtmp2);
@@ -5181,7 +5265,7 @@ instruct reduction4D(regD dst, vec src, vec vtmp1, vec vtmp2) %{
%}
instruct reduction8D(regD dst, legVec src, legVec vtmp1, legVec vtmp2) %{
- predicate(Matcher::vector_length(n->in(2)) == 8); // src
+ predicate(n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 8); // src
match(Set dst (AddReductionVD dst src));
match(Set dst (MulReductionVD dst src));
effect(TEMP dst, TEMP vtmp1, TEMP vtmp2);
@@ -5194,6 +5278,57 @@ instruct reduction8D(regD dst, legVec src, legVec vtmp1, legVec vtmp2) %{
ins_pipe( pipe_slow );
%}
+instruct unordered_reduction2D(regD dst, regD src1, vec src2) %{
+ // Non-strictly ordered floating-point add/mul reduction for doubles. This rule is
+ // intended for the VectorAPI (which allows for non-strictly ordered add/mul reduction).
+ // src1 contains reduction identity
+ predicate(!n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 2); // src2
+ match(Set dst (AddReductionVD src1 src2));
+ match(Set dst (MulReductionVD src1 src2));
+ effect(TEMP dst);
+ format %{ "vector_reduction_double $dst,$src1,$src2 ;" %}
+ ins_encode %{
+ int opcode = this->ideal_Opcode();
+ int vlen = Matcher::vector_length(this, $src2);
+ __ unordered_reduce_fp(opcode, vlen, $dst$$XMMRegister, $src2$$XMMRegister);
+%}
+ ins_pipe( pipe_slow );
+%}
+
+instruct unordered_reduction4D(regD dst, regD src1, vec src2, vec vtmp) %{
+ // Non-strictly ordered floating-point add/mul reduction for doubles. This rule is
+ // intended for the VectorAPI (which allows for non-strictly ordered add/mul reduction).
+ // src1 contains reduction identity
+ predicate(!n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 4); // src2
+ match(Set dst (AddReductionVD src1 src2));
+ match(Set dst (MulReductionVD src1 src2));
+ effect(TEMP dst, TEMP vtmp);
+ format %{ "vector_reduction_double $dst,$src1,$src2 ; using $vtmp as TEMP" %}
+ ins_encode %{
+ int opcode = this->ideal_Opcode();
+ int vlen = Matcher::vector_length(this, $src2);
+ __ unordered_reduce_fp(opcode, vlen, $dst$$XMMRegister, $src2$$XMMRegister, $vtmp$$XMMRegister);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct unordered_reduction8D(regD dst, regD src1, legVec src2, legVec vtmp1, legVec vtmp2) %{
+ // Non-strictly ordered floating-point add/mul reduction for doubles. This rule is
+ // intended for the VectorAPI (which allows for non-strictly ordered add/mul reduction).
+ // src1 contains reduction identity
+ predicate(!n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 8); // src2
+ match(Set dst (AddReductionVD src1 src2));
+ match(Set dst (MulReductionVD src1 src2));
+ effect(TEMP dst, TEMP vtmp1, TEMP vtmp2);
+ format %{ "vector_reduction_double $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
+ ins_encode %{
+ int opcode = this->ideal_Opcode();
+ int vlen = Matcher::vector_length(this, $src2);
+ __ unordered_reduce_fp(opcode, vlen, $dst$$XMMRegister, $src2$$XMMRegister, $vtmp1$$XMMRegister, $vtmp2$$XMMRegister);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
// =======================Byte Reduction==========================================
#ifdef _LP64
@@ -10348,3 +10483,16 @@ instruct DoubleClassCheck_reg_reg_vfpclass(rRegI dst, regD src, kReg ktmp, rFlag
%}
ins_pipe(pipe_slow);
%}
+
+
+instruct vector_selectfrom_twovectors_reg_evex(vec index, vec src1, vec src2)
+%{
+ match(Set index (SelectFromTwoVector (Binary index src1) src2));
+ format %{ "select_from_two_vector $index, $src1, $src2 \t!" %}
+ ins_encode %{
+ int vlen_enc = vector_length_encoding(this);
+ BasicType bt = Matcher::vector_element_basic_type(this);
+ __ select_from_two_vectors_evex(bt, $index$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vlen_enc);
+ %}
+ ins_pipe(pipe_slow);
+%}
diff --git a/src/hotspot/cpu/x86/x86_32.ad b/src/hotspot/cpu/x86/x86_32.ad
index 49a3cad37df..7c9695571da 100644
--- a/src/hotspot/cpu/x86/x86_32.ad
+++ b/src/hotspot/cpu/x86/x86_32.ad
@@ -6322,17 +6322,6 @@ instruct storeImmB(memory mem, immI8 src) %{
ins_pipe( ialu_mem_imm );
%}
-// Store CMS card-mark Immediate
-instruct storeImmCM(memory mem, immI8 src) %{
- match(Set mem (StoreCM mem src));
-
- ins_cost(150);
- format %{ "MOV8 $mem,$src\t! CMS card-mark imm0" %}
- opcode(0xC6); /* C6 /0 */
- ins_encode( SetInstMark, OpcP, RMopc_Mem(0x00,mem), Con8or32(src), ClearInstMark);
- ins_pipe( ialu_mem_imm );
-%}
-
// Store Double
instruct storeDPR( memory mem, regDPR1 src) %{
predicate(UseSSE<=1);
@@ -13583,6 +13572,18 @@ instruct tailjmpInd(eRegP_no_EBP jump_target, eAXRegP ex_oop) %{
ins_pipe( pipe_jmp );
%}
+// Forward exception.
+instruct ForwardExceptionjmp()
+%{
+ match(ForwardException);
+
+ format %{ "JMP forward_exception_stub" %}
+ ins_encode %{
+ __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()), noreg);
+ %}
+ ins_pipe(pipe_jmp);
+%}
+
// Create exception oop: created by stack-crawling runtime code.
// Created exception is now available to this handler, and is setup
// just prior to jumping to this handler. No code emitted.
diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad
index 1490cfa60b3..c3fa4c16e55 100644
--- a/src/hotspot/cpu/x86/x86_64.ad
+++ b/src/hotspot/cpu/x86/x86_64.ad
@@ -657,8 +657,7 @@ static void emit_cmpfp3(MacroAssembler* masm, Register dst) {
__ movl(dst, -1);
__ jcc(Assembler::parity, done);
__ jcc(Assembler::below, done);
- __ setb(Assembler::notEqual, dst);
- __ movzbl(dst, dst);
+ __ setcc(Assembler::notEqual, dst);
__ bind(done);
}
@@ -4342,6 +4341,7 @@ instruct loadP(rRegP dst, memory mem)
// Load Compressed Pointer
instruct loadN(rRegN dst, memory mem)
%{
+ predicate(n->as_Load()->barrier_data() == 0);
match(Set dst (LoadN mem));
ins_cost(125); // XXX
@@ -5127,6 +5127,7 @@ instruct storeImmP(memory mem, immP31 src)
// Store Compressed Pointer
instruct storeN(memory mem, rRegN src)
%{
+ predicate(n->as_Store()->barrier_data() == 0);
match(Set mem (StoreN mem src));
ins_cost(125); // XXX
@@ -5151,7 +5152,7 @@ instruct storeNKlass(memory mem, rRegN src)
instruct storeImmN0(memory mem, immN0 zero)
%{
- predicate(CompressedOops::base() == nullptr);
+ predicate(CompressedOops::base() == nullptr && n->as_Store()->barrier_data() == 0);
match(Set mem (StoreN mem zero));
ins_cost(125); // XXX
@@ -5164,6 +5165,7 @@ instruct storeImmN0(memory mem, immN0 zero)
instruct storeImmN(memory mem, immN src)
%{
+ predicate(n->as_Store()->barrier_data() == 0);
match(Set mem (StoreN mem src));
ins_cost(150); // XXX
@@ -5296,32 +5298,6 @@ instruct storeImmB(memory mem, immI8 src)
ins_pipe(ialu_mem_imm);
%}
-// Store CMS card-mark Immediate
-instruct storeImmCM0_reg(memory mem, immI_0 zero)
-%{
- predicate(UseCompressedOops && (CompressedOops::base() == nullptr));
- match(Set mem (StoreCM mem zero));
-
- ins_cost(125); // XXX
- format %{ "movb $mem, R12\t# CMS card-mark byte 0 (R12_heapbase==0)" %}
- ins_encode %{
- __ movb($mem$$Address, r12);
- %}
- ins_pipe(ialu_mem_reg);
-%}
-
-instruct storeImmCM0(memory mem, immI_0 src)
-%{
- match(Set mem (StoreCM mem src));
-
- ins_cost(150); // XXX
- format %{ "movb $mem, $src\t# CMS card-mark byte 0" %}
- ins_encode %{
- __ movb($mem$$Address, $src$$constant);
- %}
- ins_pipe(ialu_mem_imm);
-%}
-
// Store Float
instruct storeF(memory mem, regF src)
%{
@@ -6388,7 +6364,7 @@ instruct cmovP_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src)
ins_pipe(pipe_cmov_reg);
%}
-instruct cmovL_imm_01(rRegL dst, immI_1 src, rFlagsReg cr, cmpOp cop)
+instruct cmovL_imm_01(rRegL dst, immL1 src, rFlagsReg cr, cmpOp cop)
%{
predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_long() == 0);
match(Set dst (CMoveL (Binary cop cr) (Binary src dst)));
@@ -6426,7 +6402,7 @@ instruct cmovL_mem(cmpOp cop, rFlagsReg cr, rRegL dst, memory src)
ins_pipe(pipe_cmov_mem); // XXX
%}
-instruct cmovL_imm_01U(rRegL dst, immI_1 src, rFlagsRegU cr, cmpOpU cop)
+instruct cmovL_imm_01U(rRegL dst, immL1 src, rFlagsRegU cr, cmpOpU cop)
%{
predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_long() == 0);
match(Set dst (CMoveL (Binary cop cr) (Binary src dst)));
@@ -6452,7 +6428,7 @@ instruct cmovL_regU(cmpOpU cop, rFlagsRegU cr, rRegL dst, rRegL src)
ins_pipe(pipe_cmov_reg); // XXX
%}
-instruct cmovL_imm_01UCF(rRegL dst, immI_1 src, rFlagsRegUCF cr, cmpOpUCF cop)
+instruct cmovL_imm_01UCF(rRegL dst, immL1 src, rFlagsRegUCF cr, cmpOpUCF cop)
%{
predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_long() == 0);
match(Set dst (CMoveL (Binary cop cr) (Binary src dst)));
@@ -7070,13 +7046,11 @@ instruct compareAndSwapP(rRegI res,
format %{ "cmpxchgq $mem_ptr,$newval\t# "
"If rax == $mem_ptr then store $newval into $mem_ptr\n\t"
- "sete $res\n\t"
- "movzbl $res, $res" %}
+ "setcc $res \t# emits sete + movzbl or setzue for APX" %}
ins_encode %{
__ lock();
__ cmpxchgq($newval$$Register, $mem_ptr$$Address);
- __ setb(Assembler::equal, $res$$Register);
- __ movzbl($res$$Register, $res$$Register);
+ __ setcc(Assembler::equal, $res$$Register);
%}
ins_pipe( pipe_cmpxchg );
%}
@@ -7092,13 +7066,11 @@ instruct compareAndSwapL(rRegI res,
format %{ "cmpxchgq $mem_ptr,$newval\t# "
"If rax == $mem_ptr then store $newval into $mem_ptr\n\t"
- "sete $res\n\t"
- "movzbl $res, $res" %}
+ "setcc $res \t# emits sete + movzbl or setzue for APX" %}
ins_encode %{
__ lock();
__ cmpxchgq($newval$$Register, $mem_ptr$$Address);
- __ setb(Assembler::equal, $res$$Register);
- __ movzbl($res$$Register, $res$$Register);
+ __ setcc(Assembler::equal, $res$$Register);
%}
ins_pipe( pipe_cmpxchg );
%}
@@ -7114,13 +7086,11 @@ instruct compareAndSwapI(rRegI res,
format %{ "cmpxchgl $mem_ptr,$newval\t# "
"If rax == $mem_ptr then store $newval into $mem_ptr\n\t"
- "sete $res\n\t"
- "movzbl $res, $res" %}
+ "setcc $res \t# emits sete + movzbl or setzue for APX" %}
ins_encode %{
__ lock();
__ cmpxchgl($newval$$Register, $mem_ptr$$Address);
- __ setb(Assembler::equal, $res$$Register);
- __ movzbl($res$$Register, $res$$Register);
+ __ setcc(Assembler::equal, $res$$Register);
%}
ins_pipe( pipe_cmpxchg );
%}
@@ -7136,13 +7106,11 @@ instruct compareAndSwapB(rRegI res,
format %{ "cmpxchgb $mem_ptr,$newval\t# "
"If rax == $mem_ptr then store $newval into $mem_ptr\n\t"
- "sete $res\n\t"
- "movzbl $res, $res" %}
+ "setcc $res \t# emits sete + movzbl or setzue for APX" %}
ins_encode %{
__ lock();
__ cmpxchgb($newval$$Register, $mem_ptr$$Address);
- __ setb(Assembler::equal, $res$$Register);
- __ movzbl($res$$Register, $res$$Register);
+ __ setcc(Assembler::equal, $res$$Register);
%}
ins_pipe( pipe_cmpxchg );
%}
@@ -7158,13 +7126,11 @@ instruct compareAndSwapS(rRegI res,
format %{ "cmpxchgw $mem_ptr,$newval\t# "
"If rax == $mem_ptr then store $newval into $mem_ptr\n\t"
- "sete $res\n\t"
- "movzbl $res, $res" %}
+ "setcc $res \t# emits sete + movzbl or setzue for APX" %}
ins_encode %{
__ lock();
__ cmpxchgw($newval$$Register, $mem_ptr$$Address);
- __ setb(Assembler::equal, $res$$Register);
- __ movzbl($res$$Register, $res$$Register);
+ __ setcc(Assembler::equal, $res$$Register);
%}
ins_pipe( pipe_cmpxchg );
%}
@@ -7173,19 +7139,18 @@ instruct compareAndSwapN(rRegI res,
memory mem_ptr,
rax_RegN oldval, rRegN newval,
rFlagsReg cr) %{
+ predicate(n->as_LoadStore()->barrier_data() == 0);
match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval)));
match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval)));
effect(KILL cr, KILL oldval);
format %{ "cmpxchgl $mem_ptr,$newval\t# "
"If rax == $mem_ptr then store $newval into $mem_ptr\n\t"
- "sete $res\n\t"
- "movzbl $res, $res" %}
+ "setcc $res \t# emits sete + movzbl or setzue for APX" %}
ins_encode %{
__ lock();
__ cmpxchgl($newval$$Register, $mem_ptr$$Address);
- __ setb(Assembler::equal, $res$$Register);
- __ movzbl($res$$Register, $res$$Register);
+ __ setcc(Assembler::equal, $res$$Register);
%}
ins_pipe( pipe_cmpxchg );
%}
@@ -7262,6 +7227,7 @@ instruct compareAndExchangeN(
memory mem_ptr,
rax_RegN oldval, rRegN newval,
rFlagsReg cr) %{
+ predicate(n->as_LoadStore()->barrier_data() == 0);
match(Set oldval (CompareAndExchangeN mem_ptr (Binary oldval newval)));
effect(KILL cr);
@@ -7483,6 +7449,7 @@ instruct xchgP( memory mem, rRegP newval) %{
%}
instruct xchgN( memory mem, rRegN newval) %{
+ predicate(n->as_LoadStore()->barrier_data() == 0);
match(Set newval (GetAndSetN mem newval));
format %{ "XCHGL $newval,$mem]" %}
ins_encode %{
@@ -9729,13 +9696,11 @@ instruct cmpLTMask(rRegI dst, rRegI p, rRegI q, rFlagsReg cr)
ins_cost(400);
format %{ "cmpl $p, $q\t# cmpLTMask\n\t"
- "setlt $dst\n\t"
- "movzbl $dst, $dst\n\t"
+ "setcc $dst \t# emits setlt + movzbl or setzul for APX"
"negl $dst" %}
ins_encode %{
__ cmpl($p$$Register, $q$$Register);
- __ setb(Assembler::less, $dst$$Register);
- __ movzbl($dst$$Register, $dst$$Register);
+ __ setcc(Assembler::less, $dst$$Register);
__ negl($dst$$Register);
%}
ins_pipe(pipe_slow);
@@ -11674,6 +11639,7 @@ instruct compN_rReg(rFlagsRegU cr, rRegN op1, rRegN op2)
instruct compN_rReg_mem(rFlagsRegU cr, rRegN src, memory mem)
%{
+ predicate(n->in(2)->as_Load()->barrier_data() == 0);
match(Set cr (CmpN src (LoadN mem)));
format %{ "cmpl $src, $mem\t# compressed ptr" %}
@@ -11695,6 +11661,7 @@ instruct compN_rReg_imm(rFlagsRegU cr, rRegN op1, immN op2) %{
instruct compN_mem_imm(rFlagsRegU cr, memory mem, immN src)
%{
+ predicate(n->in(2)->as_Load()->barrier_data() == 0);
match(Set cr (CmpN src (LoadN mem)));
format %{ "cmpl $mem, $src\t# compressed ptr" %}
@@ -11735,7 +11702,8 @@ instruct testN_reg(rFlagsReg cr, rRegN src, immN0 zero) %{
instruct testN_mem(rFlagsReg cr, memory mem, immN0 zero)
%{
- predicate(CompressedOops::base() != nullptr);
+ predicate(CompressedOops::base() != nullptr &&
+ n->in(1)->as_Load()->barrier_data() == 0);
match(Set cr (CmpN (LoadN mem) zero));
ins_cost(500); // XXX
@@ -11748,7 +11716,8 @@ instruct testN_mem(rFlagsReg cr, memory mem, immN0 zero)
instruct testN_mem_reg0(rFlagsReg cr, memory mem, immN0 zero)
%{
- predicate(CompressedOops::base() == nullptr);
+ predicate(CompressedOops::base() == nullptr &&
+ n->in(1)->as_Load()->barrier_data() == 0);
match(Set cr (CmpN (LoadN mem) zero));
format %{ "cmpl R12, $mem\t# compressed ptr (R12_heapbase==0)" %}
@@ -11860,16 +11829,14 @@ instruct cmpU3_reg_reg(rRegI dst, rRegI src1, rRegI src2, rFlagsReg flags)
format %{ "cmpl $src1, $src2\t# CmpL3\n\t"
"movl $dst, -1\n\t"
"jb,u done\n\t"
- "setne $dst\n\t"
- "movzbl $dst, $dst\n\t"
+ "setcc $dst \t# emits setne + movzbl or setzune for APX"
"done:" %}
ins_encode %{
Label done;
__ cmpl($src1$$Register, $src2$$Register);
__ movl($dst$$Register, -1);
__ jccb(Assembler::below, done);
- __ setb(Assembler::notZero, $dst$$Register);
- __ movzbl($dst$$Register, $dst$$Register);
+ __ setcc(Assembler::notZero, $dst$$Register);
__ bind(done);
%}
ins_pipe(pipe_slow);
@@ -11886,16 +11853,14 @@ instruct cmpL3_reg_reg(rRegI dst, rRegL src1, rRegL src2, rFlagsReg flags)
format %{ "cmpq $src1, $src2\t# CmpL3\n\t"
"movl $dst, -1\n\t"
"jl,s done\n\t"
- "setne $dst\n\t"
- "movzbl $dst, $dst\n\t"
+ "setcc $dst \t# emits setne + movzbl or setzune for APX"
"done:" %}
ins_encode %{
Label done;
__ cmpq($src1$$Register, $src2$$Register);
__ movl($dst$$Register, -1);
__ jccb(Assembler::less, done);
- __ setb(Assembler::notZero, $dst$$Register);
- __ movzbl($dst$$Register, $dst$$Register);
+ __ setcc(Assembler::notZero, $dst$$Register);
__ bind(done);
%}
ins_pipe(pipe_slow);
@@ -11912,16 +11877,14 @@ instruct cmpUL3_reg_reg(rRegI dst, rRegL src1, rRegL src2, rFlagsReg flags)
format %{ "cmpq $src1, $src2\t# CmpL3\n\t"
"movl $dst, -1\n\t"
"jb,u done\n\t"
- "setne $dst\n\t"
- "movzbl $dst, $dst\n\t"
+ "setcc $dst \t# emits setne + movzbl or setzune for APX"
"done:" %}
ins_encode %{
Label done;
__ cmpq($src1$$Register, $src2$$Register);
__ movl($dst$$Register, -1);
__ jccb(Assembler::below, done);
- __ setb(Assembler::notZero, $dst$$Register);
- __ movzbl($dst$$Register, $dst$$Register);
+ __ setcc(Assembler::notZero, $dst$$Register);
__ bind(done);
%}
ins_pipe(pipe_slow);
@@ -12592,6 +12555,18 @@ instruct tailjmpInd(no_rbp_RegP jump_target, rax_RegP ex_oop)
ins_pipe(pipe_jmp);
%}
+// Forward exception.
+instruct ForwardExceptionjmp()
+%{
+ match(ForwardException);
+
+ format %{ "jmp forward_exception_stub" %}
+ ins_encode %{
+ __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()), noreg);
+ %}
+ ins_pipe(pipe_jmp);
+%}
+
// Create exception oop: created by stack-crawling runtime code.
// Created exception is now available to this handler, and is setup
// just prior to jumping to this handler. No code emitted.
diff --git a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp
index 986cee68512..18ceb9514d3 100644
--- a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp
+++ b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp
@@ -89,7 +89,7 @@ JRT_LEAF(void, zero_stub())
ShouldNotCallThis();
JRT_END
-static RuntimeStub* generate_empty_runtime_stub(const char* name) {
+static RuntimeStub* generate_empty_runtime_stub() {
return CAST_FROM_FN_PTR(RuntimeStub*,zero_stub);
}
@@ -101,17 +101,20 @@ static DeoptimizationBlob* generate_empty_deopt_blob() {
return CAST_FROM_FN_PTR(DeoptimizationBlob*,zero_stub);
}
-
void SharedRuntime::generate_deopt_blob() {
_deopt_blob = generate_empty_deopt_blob();
}
-SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) {
+SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) {
return generate_empty_safepoint_blob();
}
-RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) {
- return generate_empty_runtime_stub("resolve_blob");
+RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) {
+ return generate_empty_runtime_stub();
+}
+
+RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) {
+ return generate_empty_runtime_stub();
}
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
@@ -127,3 +130,15 @@ int SharedRuntime::vector_calling_convention(VMRegPair *regs,
ShouldNotCallThis();
return 0;
}
+
+#if INCLUDE_JFR
+RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() {
+ return nullptr;
+}
+
+RuntimeStub* SharedRuntime::generate_jfr_return_lease() {
+ return nullptr;
+}
+
+#endif // INCLUDE_JFR
+
diff --git a/src/hotspot/cpu/zero/smallRegisterMap_zero.inline.hpp b/src/hotspot/cpu/zero/smallRegisterMap_zero.inline.hpp
index b85ead32fd2..51fb114f595 100644
--- a/src/hotspot/cpu/zero/smallRegisterMap_zero.inline.hpp
+++ b/src/hotspot/cpu/zero/smallRegisterMap_zero.inline.hpp
@@ -30,8 +30,15 @@
// Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap
class SmallRegisterMap {
+ constexpr SmallRegisterMap() = default;
+ ~SmallRegisterMap() = default;
+ NONCOPYABLE(SmallRegisterMap);
+
public:
- static constexpr SmallRegisterMap* instance = nullptr;
+ static const SmallRegisterMap* instance() {
+ static constexpr SmallRegisterMap the_instance{};
+ return &the_instance;
+ }
private:
static void assert_is_rfp(VMReg r) NOT_DEBUG_RETURN
DEBUG_ONLY({ Unimplemented(); })
@@ -46,12 +53,6 @@ class SmallRegisterMap {
return map;
}
- SmallRegisterMap() {}
-
- SmallRegisterMap(const RegisterMap* map) {
- Unimplemented();
- }
-
inline address location(VMReg reg, intptr_t* sp) const {
Unimplemented();
return nullptr;
diff --git a/src/hotspot/cpu/zero/stubGenerator_zero.cpp b/src/hotspot/cpu/zero/stubGenerator_zero.cpp
index 5c7772021ea..b6905791e98 100644
--- a/src/hotspot/cpu/zero/stubGenerator_zero.cpp
+++ b/src/hotspot/cpu/zero/stubGenerator_zero.cpp
@@ -203,22 +203,6 @@ class StubGenerator: public StubCodeGenerator {
void generate_final_stubs() {
// Generates all stubs and initializes the entry points
- // These entry points require SharedInfo::stack0 to be set up in
- // non-core builds and need to be relocatable, so they each
- // fabricate a RuntimeStub internally.
- StubRoutines::_throw_AbstractMethodError_entry =
- ShouldNotCallThisStub();
-
- StubRoutines::_throw_NullPointerException_at_call_entry =
- ShouldNotCallThisStub();
-
- StubRoutines::_throw_StackOverflowError_entry =
- ShouldNotCallThisStub();
-
- // support for verify_oop (must happen after universe_init)
- StubRoutines::_verify_oop_subroutine_entry =
- ShouldNotCallThisStub();
-
// arraycopy stubs used by compilers
generate_arraycopy_stubs();
diff --git a/src/hotspot/cpu/zero/upcallLinker_zero.cpp b/src/hotspot/cpu/zero/upcallLinker_zero.cpp
index 6447dac86c9..408ebc32820 100644
--- a/src/hotspot/cpu/zero/upcallLinker_zero.cpp
+++ b/src/hotspot/cpu/zero/upcallLinker_zero.cpp
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "prims/upcallLinker.hpp"
-address UpcallLinker::make_upcall_stub(jobject mh, Method* entry,
+address UpcallLinker::make_upcall_stub(jobject mh, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
diff --git a/src/hotspot/cpu/zero/vm_version_zero.cpp b/src/hotspot/cpu/zero/vm_version_zero.cpp
index 1fcf4b10862..7312dd11646 100644
--- a/src/hotspot/cpu/zero/vm_version_zero.cpp
+++ b/src/hotspot/cpu/zero/vm_version_zero.cpp
@@ -116,11 +116,6 @@ void VM_Version::initialize() {
FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false);
}
- if ((LockingMode != LM_LEGACY) && (LockingMode != LM_MONITOR)) {
- warning("Unsupported locking mode for this CPU.");
- FLAG_SET_DEFAULT(LockingMode, LM_LEGACY);
- }
-
// Enable error context decoding on known platforms
#if defined(IA32) || defined(AMD64) || defined(ARM) || \
defined(AARCH64) || defined(PPC) || defined(RISCV) || \
diff --git a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp
index 9e00b1c5b04..aab43e73396 100644
--- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp
+++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp
@@ -37,6 +37,7 @@
#include "oops/method.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
+#include "runtime/basicLock.inline.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
@@ -44,6 +45,7 @@
#include "runtime/timer.hpp"
#include "runtime/timerTrace.hpp"
#include "utilities/debug.hpp"
+#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
#include "entry_zero.hpp"
@@ -331,23 +333,27 @@ int ZeroInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) {
if (method->is_synchronized()) {
monitor = (BasicObjectLock*) istate->stack_base();
oop lockee = monitor->obj();
- markWord disp = lockee->mark().set_unlocked();
- monitor->lock()->set_displaced_header(disp);
- bool call_vm = (LockingMode == LM_MONITOR);
- bool inc_monitor_count = true;
- if (call_vm || lockee->cas_set_mark(markWord::from_pointer(monitor), disp) != disp) {
- // Is it simple recursive case?
- if (!call_vm && thread->is_lock_owned((address) disp.clear_lock_bits().to_pointer())) {
- monitor->lock()->set_displaced_header(markWord::from_pointer(nullptr));
- } else {
- inc_monitor_count = false;
- CALL_VM_NOCHECK(InterpreterRuntime::monitorenter(thread, monitor));
- if (HAS_PENDING_EXCEPTION)
- goto unwind_and_return;
+ bool success = false;
+ if (LockingMode == LM_LEGACY) {
+ markWord disp = lockee->mark().set_unlocked();
+ monitor->lock()->set_displaced_header(disp);
+ success = true;
+ if (lockee->cas_set_mark(markWord::from_pointer(monitor), disp) != disp) {
+ // Is it simple recursive case?
+ if (thread->is_lock_owned((address) disp.clear_lock_bits().to_pointer())) {
+ monitor->lock()->set_displaced_header(markWord::from_pointer(nullptr));
+ } else {
+ success = false;
+ }
+ }
+ if (success) {
+ THREAD->inc_held_monitor_count();
}
}
- if (inc_monitor_count) {
- THREAD->inc_held_monitor_count();
+ if (!success) {
+ CALL_VM_NOCHECK(InterpreterRuntime::monitorenter(thread, monitor));
+ if (HAS_PENDING_EXCEPTION)
+ goto unwind_and_return;
}
}
@@ -479,26 +485,30 @@ int ZeroInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) {
// Unlock if necessary
if (monitor) {
- BasicLock *lock = monitor->lock();
- markWord header = lock->displaced_header();
- oop rcvr = monitor->obj();
- monitor->set_obj(nullptr);
-
- bool dec_monitor_count = true;
- if (header.to_pointer() != nullptr) {
- markWord old_header = markWord::encode(lock);
- if (rcvr->cas_set_mark(header, old_header) != old_header) {
- monitor->set_obj(rcvr);
- dec_monitor_count = false;
- InterpreterRuntime::monitorexit(monitor);
+ bool success = false;
+ if (LockingMode == LM_LEGACY) {
+ BasicLock* lock = monitor->lock();
+ oop rcvr = monitor->obj();
+ monitor->set_obj(nullptr);
+ success = true;
+ markWord header = lock->displaced_header();
+ if (header.to_pointer() != nullptr) { // Check for recursive lock
+ markWord old_header = markWord::encode(lock);
+ if (rcvr->cas_set_mark(header, old_header) != old_header) {
+ monitor->set_obj(rcvr);
+ success = false;
+ }
+ }
+ if (success) {
+ THREAD->dec_held_monitor_count();
}
}
- if (dec_monitor_count) {
- THREAD->dec_held_monitor_count();
+ if (!success) {
+ InterpreterRuntime::monitorexit(monitor);
}
}
- unwind_and_return:
+ unwind_and_return:
// Unwind the current activation
thread->pop_zero_frame();
diff --git a/src/hotspot/os/aix/osThread_aix.cpp b/src/hotspot/os/aix/osThread_aix.cpp
index 4049d6b58b7..c424b044c09 100644
--- a/src/hotspot/os/aix/osThread_aix.cpp
+++ b/src/hotspot/os/aix/osThread_aix.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -23,32 +23,26 @@
*
*/
-// no precompiled headers
-
-#include "memory/allocation.inline.hpp"
-#include "runtime/handles.inline.hpp"
-#include "runtime/mutexLocker.hpp"
-#include "runtime/os.hpp"
+#include "precompiled.hpp"
+#include "memory/allocation.hpp"
+#include "runtime/mutex.hpp"
#include "runtime/osThread.hpp"
-#include "runtime/safepoint.hpp"
-#include "runtime/vmThread.hpp"
-
-void OSThread::pd_initialize() {
- _thread_id = 0;
- _kernel_thread_id = 0;
- _siginfo = nullptr;
- _ucontext = nullptr;
- _expanding_stack = 0;
- _alt_sig_stack = nullptr;
- _last_cpu_times.sys = _last_cpu_times.user = 0L;
+#include
+OSThread::OSThread()
+ : _thread_id(0),
+ _kernel_thread_id(0),
+ _caller_sigmask(),
+ sr(),
+ _siginfo(nullptr),
+ _ucontext(nullptr),
+ _expanding_stack(0),
+ _alt_sig_stack(nullptr),
+ _startThread_lock(new Monitor(Mutex::event, "startThread_lock")) {
sigemptyset(&_caller_sigmask);
-
- _startThread_lock = new Monitor(Mutex::event, "startThread_lock");
- assert(_startThread_lock != nullptr, "check");
}
-void OSThread::pd_destroy() {
+OSThread::~OSThread() {
delete _startThread_lock;
}
diff --git a/src/hotspot/os/aix/osThread_aix.hpp b/src/hotspot/os/aix/osThread_aix.hpp
index 5feb3c5799a..514e554101e 100644
--- a/src/hotspot/os/aix/osThread_aix.hpp
+++ b/src/hotspot/os/aix/osThread_aix.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -26,22 +26,16 @@
#ifndef OS_AIX_OSTHREAD_AIX_HPP
#define OS_AIX_OSTHREAD_AIX_HPP
- public:
- typedef pthread_t thread_id_t;
-
- private:
- int _thread_type;
+#include "runtime/osThreadBase.hpp"
+#include "suspendResume_posix.hpp"
+#include "utilities/globalDefinitions.hpp"
- public:
+class OSThread : public OSThreadBase {
+ friend class VMStructs;
- int thread_type() const {
- return _thread_type;
- }
- void set_thread_type(int type) {
- _thread_type = type;
- }
+ typedef pthread_t thread_id_t;
- private:
+ thread_id_t _thread_id;
// On AIX, we use the pthread id as OSThread::thread_id and keep the kernel thread id
// separately for diagnostic purposes.
@@ -54,15 +48,20 @@
sigset_t _caller_sigmask; // Caller's signal mask
public:
+ OSThread();
+ ~OSThread();
// Methods to save/restore caller's signal mask
sigset_t caller_sigmask() const { return _caller_sigmask; }
void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; }
-#ifndef PRODUCT
- // Used for debugging, return a unique integer for each thread.
- int thread_identifier() const { return _thread_id; }
-#endif
+ thread_id_t thread_id() const {
+ return _thread_id;
+ }
+ void set_thread_id(thread_id_t id) {
+ _thread_id = id;
+ }
+
tid_t kernel_thread_id() const {
return _kernel_thread_id;
}
@@ -71,7 +70,7 @@
}
pthread_t pthread_id() const {
- // Here: same as OSThread::thread_id()
+ // Here: same as thread_id()
return _thread_id;
}
@@ -79,7 +78,6 @@
// suspension support.
// ***************************************************************
- public:
// flags that support signal based suspend/resume on Aix are in a
// separate class to avoid confusion with many flags in OSThread that
// are used by VM level suspend/resume.
@@ -125,22 +123,10 @@
return _startThread_lock;
}
- // ***************************************************************
- // Platform dependent initialization and cleanup
- // ***************************************************************
-
- private:
-
- void pd_initialize();
- void pd_destroy();
-
- public:
-
- // The last measured values of cpu timing to prevent the "stale
- // value return" bug in thread_cpu_time.
- volatile struct {
- jlong sys;
- jlong user;
- } _last_cpu_times;
+ // Printing
+ uintx thread_id_for_printing() const override {
+ return (uintx)_thread_id;
+ }
+};
#endif // OS_AIX_OSTHREAD_AIX_HPP
diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp
index fd16a7984a6..842ab0c6eeb 100644
--- a/src/hotspot/os/aix/os_aix.cpp
+++ b/src/hotspot/os/aix/os_aix.cpp
@@ -698,9 +698,6 @@ bool os::create_thread(Thread* thread, ThreadType thr_type,
return false;
}
- // Set the correct thread state.
- osthread->set_thread_type(thr_type);
-
// Initial state is ALLOCATED but not INITIALIZED
osthread->set_state(ALLOCATED);
@@ -1293,7 +1290,7 @@ void os::jvm_path(char *buf, jint buflen) {
Dl_info dlinfo;
int ret = dladdr(CAST_FROM_FN_PTR(void *, os::jvm_path), &dlinfo);
assert(ret != 0, "cannot locate libjvm");
- char* rp = os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen);
+ char* rp = os::realpath((char *)dlinfo.dli_fname, buf, buflen);
assert(rp != nullptr, "error in realpath(): maybe the 'path' argument is too long?");
if (Arguments::sun_java_launcher_is_altjvm()) {
@@ -1324,7 +1321,7 @@ void os::jvm_path(char *buf, jint buflen) {
}
assert(strstr(p, "/libjvm") == p, "invalid library name");
- rp = os::Posix::realpath(java_home_var, buf, buflen);
+ rp = os::realpath(java_home_var, buf, buflen);
if (rp == nullptr) {
return;
}
@@ -1345,7 +1342,7 @@ void os::jvm_path(char *buf, jint buflen) {
snprintf(buf + len, buflen-len, "/hotspot/libjvm.so");
} else {
// Go back to path of .so
- rp = os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen);
+ rp = os::realpath((char *)dlinfo.dli_fname, buf, buflen);
if (rp == nullptr) {
return;
}
@@ -2483,16 +2480,6 @@ int os::open(const char *path, int oflag, int mode) {
return fd;
}
-// return current position of file pointer
-jlong os::current_file_offset(int fd) {
- return (jlong)::lseek(fd, (off_t)0, SEEK_CUR);
-}
-
-// move file pointer to the specified offset
-jlong os::seek_to_file_offset(int fd, jlong offset) {
- return (jlong)::lseek(fd, (off_t)offset, SEEK_SET);
-}
-
// current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool)
// are used by JVM M&M and JVMTI to get user+sys or user CPU time
// of a thread.
diff --git a/src/hotspot/os/aix/vmStructs_aix.hpp b/src/hotspot/os/aix/vmStructs_aix.hpp
index 1a2f4c4bf6e..f3bbc80e62c 100644
--- a/src/hotspot/os/aix/vmStructs_aix.hpp
+++ b/src/hotspot/os/aix/vmStructs_aix.hpp
@@ -29,9 +29,20 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-
-#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
+#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
+ \
+ /******************************/ \
+ /* Threads (NOTE: incomplete) */ \
+ /******************************/ \
+ nonstatic_field(OSThread, _thread_id, pthread_t) \
+
+#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
+ \
+ /**********************/ \
+ /* Posix Thread IDs */ \
+ /**********************/ \
+ \
+ declare_unsigned_integer_type(pthread_t)
#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp
index 29825a9eab2..2e56c092a79 100644
--- a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp
+++ b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp
@@ -22,10 +22,10 @@
*/
#include "precompiled.hpp"
-#include "gc/shared/gcLogPrecious.hpp"
#include "gc/z/zAddress.inline.hpp"
#include "gc/z/zErrno.hpp"
#include "gc/z/zGlobals.hpp"
+#include "gc/z/zInitialize.hpp"
#include "gc/z/zLargePages.inline.hpp"
#include "gc/z/zPhysicalMemory.inline.hpp"
#include "gc/z/zPhysicalMemoryBacking_bsd.hpp"
@@ -82,7 +82,7 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity)
_base = (uintptr_t)os::reserve_memory(max_capacity);
if (_base == 0) {
// Failed
- log_error_pd(gc)("Failed to reserve address space for backing memory");
+ ZInitialize::error("Failed to reserve address space for backing memory");
return;
}
diff --git a/src/hotspot/os/bsd/osThread_bsd.cpp b/src/hotspot/os/bsd/osThread_bsd.cpp
index 7b9ad1f76a8..d9624040bc7 100644
--- a/src/hotspot/os/bsd/osThread_bsd.cpp
+++ b/src/hotspot/os/bsd/osThread_bsd.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,30 +22,31 @@
*
*/
-// no precompiled headers
-#include "memory/allocation.inline.hpp"
-#include "runtime/mutexLocker.hpp"
+#include "precompiled.hpp"
+#include "memory/allocation.hpp"
+#include "runtime/mutex.hpp"
#include "runtime/osThread.hpp"
#include
-void OSThread::pd_initialize() {
+OSThread::OSThread()
+ : _thread_id(
#ifdef __APPLE__
- _thread_id = 0;
+ 0
#else
- _thread_id = nullptr;
+ nullptr
#endif
- _unique_thread_id = 0;
- _pthread_id = nullptr;
- _siginfo = nullptr;
- _ucontext = nullptr;
- _expanding_stack = 0;
- _alt_sig_stack = nullptr;
-
+ ),
+ _pthread_id(nullptr),
+ _unique_thread_id(0),
+ _caller_sigmask(),
+ sr(),
+ _siginfo(nullptr),
+ _ucontext(nullptr),
+ _expanding_stack(0),
+ _alt_sig_stack(nullptr),
+ _startThread_lock(new Monitor(Mutex::event, "startThread_lock")) {
sigemptyset(&_caller_sigmask);
-
- _startThread_lock = new Monitor(Mutex::event, "startThread_lock");
- assert(_startThread_lock !=nullptr, "check");
}
// Additional thread_id used to correlate threads in SA
@@ -64,6 +65,6 @@ void OSThread::set_unique_thread_id() {
#endif
}
-void OSThread::pd_destroy() {
+OSThread::~OSThread() {
delete _startThread_lock;
}
diff --git a/src/hotspot/os/bsd/osThread_bsd.hpp b/src/hotspot/os/bsd/osThread_bsd.hpp
index 11376835063..21bec3f3836 100644
--- a/src/hotspot/os/bsd/osThread_bsd.hpp
+++ b/src/hotspot/os/bsd/osThread_bsd.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,19 +25,12 @@
#ifndef OS_BSD_OSTHREAD_BSD_HPP
#define OS_BSD_OSTHREAD_BSD_HPP
- private:
- int _thread_type;
+#include "runtime/osThreadBase.hpp"
+#include "suspendResume_posix.hpp"
+#include "utilities/globalDefinitions.hpp"
- public:
-
- int thread_type() const {
- return _thread_type;
- }
- void set_thread_type(int type) {
- _thread_type = type;
- }
-
- private:
+class OSThread : public OSThreadBase {
+ friend class VMStructs;
#ifdef __APPLE__
typedef thread_t thread_id_t;
@@ -45,6 +38,8 @@
typedef pid_t thread_id_t;
#endif
+ thread_id_t _thread_id;
+
// _pthread_id is the pthread id, which is used by library calls
// (e.g. pthread_kill).
pthread_t _pthread_id;
@@ -57,15 +52,19 @@
sigset_t _caller_sigmask; // Caller's signal mask
public:
+ OSThread();
+ ~OSThread();
// Methods to save/restore caller's signal mask
sigset_t caller_sigmask() const { return _caller_sigmask; }
void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; }
-#ifndef PRODUCT
- // Used for debugging, return a unique integer for each thread.
- intptr_t thread_identifier() const { return (intptr_t)_pthread_id; }
-#endif
+ thread_id_t thread_id() const {
+ return _thread_id;
+ }
+ void set_thread_id(thread_id_t id) {
+ _thread_id = id;
+ }
pthread_t pthread_id() const {
return _pthread_id;
@@ -80,7 +79,6 @@
// suspension support.
// ***************************************************************
-public:
// flags that support signal based suspend/resume on Bsd are in a
// separate class to avoid confusion with many flags in OSThread that
// are used by VM level suspend/resume.
@@ -126,17 +124,9 @@
return _startThread_lock;
}
- // ***************************************************************
- // Platform dependent initialization and cleanup
- // ***************************************************************
-
-private:
-
- void pd_initialize();
- void pd_destroy();
-
-// Reconciliation History
-// osThread_solaris.hpp 1.24 99/08/27 13:11:54
-// End
+ uintx thread_id_for_printing() const override {
+ return (uintx)_thread_id;
+ }
+};
#endif // OS_BSD_OSTHREAD_BSD_HPP
diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp
index c9c6c4d3edf..b50ebf22203 100644
--- a/src/hotspot/os/bsd/os_bsd.cpp
+++ b/src/hotspot/os/bsd/os_bsd.cpp
@@ -473,9 +473,9 @@ void os::init_system_properties_values() {
if (pslash != nullptr) {
*pslash = '\0'; // Get rid of /{client|server|hotspot}.
}
-#ifdef STATIC_BUILD
- strcat(buf, "/lib");
-#endif
+ if (is_vm_statically_linked()) {
+ strcat(buf, "/lib");
+ }
Arguments::set_dll_dir(buf);
@@ -633,9 +633,6 @@ bool os::create_thread(Thread* thread, ThreadType thr_type,
return false;
}
- // set the correct thread state
- osthread->set_thread_type(thr_type);
-
// Initial state is ALLOCATED but not INITIALIZED
osthread->set_state(ALLOCATED);
@@ -1093,19 +1090,20 @@ void *os::Bsd::dlopen_helper(const char *filename, int mode, char *ebuf, int ebu
#ifdef __APPLE__
void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
-#ifdef STATIC_BUILD
- return os::get_default_process_handle();
-#else
+ if (is_vm_statically_linked()) {
+ return os::get_default_process_handle();
+ }
+
log_info(os)("attempting shared library load of %s", filename);
return os::Bsd::dlopen_helper(filename, RTLD_LAZY, ebuf, ebuflen);
-#endif // STATIC_BUILD
}
#else
void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
-#ifdef STATIC_BUILD
- return os::get_default_process_handle();
-#else
+ if (is_vm_statically_linked()) {
+ return os::get_default_process_handle();
+ }
+
log_info(os)("attempting shared library load of %s", filename);
void* result;
@@ -1269,7 +1267,6 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
}
return nullptr;
-#endif // STATIC_BUILD
}
#endif // !__APPLE__
@@ -1509,7 +1506,7 @@ void os::jvm_path(char *buf, jint buflen) {
assert(ret, "cannot locate libjvm");
char *rp = nullptr;
if (ret && dli_fname[0] != '\0') {
- rp = os::Posix::realpath(dli_fname, buf, buflen);
+ rp = os::realpath(dli_fname, buf, buflen);
}
if (rp == nullptr) {
return;
@@ -1541,7 +1538,7 @@ void os::jvm_path(char *buf, jint buflen) {
p = strrchr(buf, '/');
assert(strstr(p, "/libjvm") == p, "invalid library name");
- rp = os::Posix::realpath(java_home_var, buf, buflen);
+ rp = os::realpath(java_home_var, buf, buflen);
if (rp == nullptr) {
return;
}
@@ -1575,7 +1572,7 @@ void os::jvm_path(char *buf, jint buflen) {
snprintf(buf + len, buflen-len, "/libjvm%s", JNI_LIB_SUFFIX);
} else {
// Fall back to path of current library
- rp = os::Posix::realpath(dli_fname, buf, buflen);
+ rp = os::realpath(dli_fname, buf, buflen);
if (rp == nullptr) {
return;
}
@@ -2400,16 +2397,6 @@ int os::open(const char *path, int oflag, int mode) {
return fd;
}
-// return current position of file pointer
-jlong os::current_file_offset(int fd) {
- return (jlong)::lseek(fd, (off_t)0, SEEK_CUR);
-}
-
-// move file pointer to the specified offset
-jlong os::seek_to_file_offset(int fd, jlong offset) {
- return (jlong)::lseek(fd, (off_t)offset, SEEK_SET);
-}
-
// current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool)
// are used by JVM M&M and JVMTI to get user+sys or user CPU time
// of a thread.
diff --git a/src/hotspot/os/bsd/vmStructs_bsd.hpp b/src/hotspot/os/bsd/vmStructs_bsd.hpp
index 84c1be77374..8c9c132e1c2 100644
--- a/src/hotspot/os/bsd/vmStructs_bsd.hpp
+++ b/src/hotspot/os/bsd/vmStructs_bsd.hpp
@@ -31,9 +31,21 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-
-#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
+#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
+ \
+ /******************************/ \
+ /* Threads (NOTE: incomplete) */ \
+ /******************************/ \
+ nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
+ nonstatic_field(OSThread, _unique_thread_id, uint64_t)
+
+#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
+ \
+ /**********************/ \
+ /* Thread IDs */ \
+ /**********************/ \
+ \
+ declare_unsigned_integer_type(OSThread::thread_id_t)
#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp
index 1da0e44dbf4..d51499611a8 100644
--- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp
+++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp
@@ -609,7 +609,7 @@ jlong CgroupSubsystem::memory_limit_in_bytes() {
bool CgroupController::read_string(const char* filename, char* buf, size_t buf_size) {
assert(buf != nullptr, "buffer must not be null");
assert(filename != nullptr, "filename must be given");
- char* s_path = subsystem_path();
+ const char* s_path = subsystem_path();
if (s_path == nullptr) {
log_debug(os, container)("read_string: subsystem path is null");
return false;
@@ -679,7 +679,7 @@ bool CgroupController::read_numerical_key_value(const char* filename, const char
assert(key != nullptr, "key must be given");
assert(result != nullptr, "result pointer must not be null");
assert(filename != nullptr, "file to search in must be given");
- char* s_path = subsystem_path();
+ const char* s_path = subsystem_path();
if (s_path == nullptr) {
log_debug(os, container)("read_numerical_key_value: subsystem path is null");
return false;
diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
index 4d5fa5d4879..40948dc5e28 100644
--- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
+++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
@@ -103,9 +103,15 @@
}
class CgroupController: public CHeapObj {
+ protected:
+ char* _cgroup_path;
+ char* _mount_point;
public:
- virtual char* subsystem_path() = 0;
+ virtual const char* subsystem_path() = 0;
virtual bool is_read_only() = 0;
+ const char* cgroup_path() { return _cgroup_path; }
+ const char* mount_point() { return _mount_point; }
+ virtual bool needs_hierarchy_adjustment() { return false; }
/* Read a numerical value as unsigned long
*
@@ -202,7 +208,12 @@ class CgroupCpuController: public CHeapObj {
virtual int cpu_quota() = 0;
virtual int cpu_period() = 0;
virtual int cpu_shares() = 0;
+ virtual bool needs_hierarchy_adjustment() = 0;
virtual bool is_read_only() = 0;
+ virtual const char* subsystem_path() = 0;
+ virtual void set_subsystem_path(const char* cgroup_path) = 0;
+ virtual const char* mount_point() = 0;
+ virtual const char* cgroup_path() = 0;
};
// Pure virtual class representing version agnostic memory controllers
@@ -217,7 +228,12 @@ class CgroupMemoryController: public CHeapObj {
virtual jlong rss_usage_in_bytes() = 0;
virtual jlong cache_usage_in_bytes() = 0;
virtual void print_version_specific_info(outputStream* st, julong host_mem) = 0;
+ virtual bool needs_hierarchy_adjustment() = 0;
virtual bool is_read_only() = 0;
+ virtual const char* subsystem_path() = 0;
+ virtual void set_subsystem_path(const char* cgroup_path) = 0;
+ virtual const char* mount_point() = 0;
+ virtual const char* cgroup_path() = 0;
};
class CgroupSubsystem: public CHeapObj {
diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp
index 24046991905..bc0e018d6be 100644
--- a/src/hotspot/os/linux/cgroupUtil_linux.cpp
+++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp
@@ -22,6 +22,7 @@
*
*/
+#include "os_linux.hpp"
#include "cgroupUtil_linux.hpp"
int CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int host_cpus) {
@@ -46,3 +47,113 @@ int CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int host_cpus) {
log_trace(os, container)("OSContainer::active_processor_count: %d", result);
return result;
}
+
+void CgroupUtil::adjust_controller(CgroupMemoryController* mem) {
+ if (!mem->needs_hierarchy_adjustment()) {
+ // nothing to do
+ return;
+ }
+ log_trace(os, container)("Adjusting controller path for memory: %s", mem->subsystem_path());
+ assert(mem->cgroup_path() != nullptr, "invariant");
+ char* orig = os::strdup(mem->cgroup_path());
+ char* cg_path = os::strdup(orig);
+ char* last_slash;
+ assert(cg_path[0] == '/', "cgroup path must start with '/'");
+ julong phys_mem = os::Linux::physical_memory();
+ char* limit_cg_path = nullptr;
+ jlong limit = mem->read_memory_limit_in_bytes(phys_mem);
+ jlong lowest_limit = phys_mem;
+ while ((last_slash = strrchr(cg_path, '/')) != cg_path) {
+ *last_slash = '\0'; // strip path
+ // update to shortened path and try again
+ mem->set_subsystem_path(cg_path);
+ limit = mem->read_memory_limit_in_bytes(phys_mem);
+ if (limit >= 0 && limit < lowest_limit) {
+ lowest_limit = limit;
+ os::free(limit_cg_path); // handles nullptr
+ limit_cg_path = os::strdup(cg_path);
+ }
+ }
+ // need to check limit at mount point
+ mem->set_subsystem_path("/");
+ limit = mem->read_memory_limit_in_bytes(phys_mem);
+ if (limit >= 0 && limit < lowest_limit) {
+ lowest_limit = limit;
+ os::free(limit_cg_path); // handles nullptr
+ limit_cg_path = os::strdup("/");
+ }
+ assert(lowest_limit >= 0, "limit must be positive");
+ if ((julong)lowest_limit != phys_mem) {
+ // we've found a lower limit anywhere in the hierarchy,
+ // set the path to the limit path
+ assert(limit_cg_path != nullptr, "limit path must be set");
+ mem->set_subsystem_path(limit_cg_path);
+ log_trace(os, container)("Adjusted controller path for memory to: %s. "
+ "Lowest limit was: " JLONG_FORMAT,
+ mem->subsystem_path(),
+ lowest_limit);
+ } else {
+ log_trace(os, container)("No lower limit found for memory in hierarchy %s, "
+ "adjusting to original path %s",
+ mem->mount_point(), orig);
+ mem->set_subsystem_path(orig);
+ }
+ os::free(cg_path);
+ os::free(orig);
+ os::free(limit_cg_path);
+}
+
+void CgroupUtil::adjust_controller(CgroupCpuController* cpu) {
+ if (!cpu->needs_hierarchy_adjustment()) {
+ // nothing to do
+ return;
+ }
+ log_trace(os, container)("Adjusting controller path for cpu: %s", cpu->subsystem_path());
+ assert(cpu->cgroup_path() != nullptr, "invariant");
+ char* orig = os::strdup(cpu->cgroup_path());
+ char* cg_path = os::strdup(orig);
+ char* last_slash;
+ assert(cg_path[0] == '/', "cgroup path must start with '/'");
+ int host_cpus = os::Linux::active_processor_count();
+ int cpus = CgroupUtil::processor_count(cpu, host_cpus);
+ int lowest_limit = host_cpus;
+ char* limit_cg_path = nullptr;
+ while ((last_slash = strrchr(cg_path, '/')) != cg_path) {
+ *last_slash = '\0'; // strip path
+ // update to shortened path and try again
+ cpu->set_subsystem_path(cg_path);
+ cpus = CgroupUtil::processor_count(cpu, host_cpus);
+ if (cpus != host_cpus && cpus < lowest_limit) {
+ lowest_limit = cpus;
+ os::free(limit_cg_path); // handles nullptr
+ limit_cg_path = os::strdup(cg_path);
+ }
+ }
+ // need to check limit at mount point
+ cpu->set_subsystem_path("/");
+ cpus = CgroupUtil::processor_count(cpu, host_cpus);
+ if (cpus != host_cpus && cpus < lowest_limit) {
+ lowest_limit = cpus;
+ os::free(limit_cg_path); // handles nullptr
+ limit_cg_path = os::strdup(cg_path);
+ }
+ assert(lowest_limit >= 0, "limit must be positive");
+ if (lowest_limit != host_cpus) {
+ // we've found a lower limit anywhere in the hierarchy,
+ // set the path to the limit path
+ assert(limit_cg_path != nullptr, "limit path must be set");
+ cpu->set_subsystem_path(limit_cg_path);
+ log_trace(os, container)("Adjusted controller path for cpu to: %s. "
+ "Lowest limit was: %d",
+ cpu->subsystem_path(),
+ lowest_limit);
+ } else {
+ log_trace(os, container)("No lower limit found for cpu in hierarchy %s, "
+ "adjusting to original path %s",
+ cpu->mount_point(), orig);
+ cpu->set_subsystem_path(orig);
+ }
+ os::free(cg_path);
+ os::free(orig);
+ os::free(limit_cg_path);
+}
diff --git a/src/hotspot/os/linux/cgroupUtil_linux.hpp b/src/hotspot/os/linux/cgroupUtil_linux.hpp
index fdcc4806c3b..19220af3177 100644
--- a/src/hotspot/os/linux/cgroupUtil_linux.hpp
+++ b/src/hotspot/os/linux/cgroupUtil_linux.hpp
@@ -32,6 +32,12 @@ class CgroupUtil: AllStatic {
public:
static int processor_count(CgroupCpuController* cpu, int host_cpus);
+ // Given a memory controller, adjust its path to a point in the hierarchy
+ // that represents the closest memory limit.
+ static void adjust_controller(CgroupMemoryController* m);
+ // Given a cpu controller, adjust its path to a point in the hierarchy
+ // that represents the closest cpu limit.
+ static void adjust_controller(CgroupCpuController* c);
};
#endif // CGROUP_UTIL_LINUX_HPP
diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
index d7f9918afda..388ee5c6ea0 100644
--- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
+++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
@@ -38,7 +38,15 @@
* Set directory to subsystem specific files based
* on the contents of the mountinfo and cgroup files.
*/
-void CgroupV1Controller::set_subsystem_path(char *cgroup_path) {
+void CgroupV1Controller::set_subsystem_path(const char* cgroup_path) {
+ if (_cgroup_path != nullptr) {
+ os::free(_cgroup_path);
+ }
+ if (_path != nullptr) {
+ os::free(_path);
+ _path = nullptr;
+ }
+ _cgroup_path = os::strdup(cgroup_path);
stringStream ss;
if (_root != nullptr && cgroup_path != nullptr) {
if (strcmp(_root, "/") == 0) {
@@ -52,7 +60,7 @@ void CgroupV1Controller::set_subsystem_path(char *cgroup_path) {
ss.print_raw(_mount_point);
_path = os::strdup(ss.base());
} else {
- char *p = strstr(cgroup_path, _root);
+ char *p = strstr((char*)cgroup_path, _root);
if (p != nullptr && p == _root) {
if (strlen(cgroup_path) > strlen(_root)) {
ss.print_raw(_mount_point);
@@ -66,27 +74,15 @@ void CgroupV1Controller::set_subsystem_path(char *cgroup_path) {
}
}
-/* uses_mem_hierarchy
- *
- * Return whether or not hierarchical cgroup accounting is being
- * done.
- *
- * return:
- * A number > 0 if true, or
- * OSCONTAINER_ERROR for not supported
+/*
+ * The common case, containers, we have _root == _cgroup_path, and thus set the
+ * controller path to the _mount_point. This is where the limits are exposed in
+ * the cgroup pseudo filesystem (at the leaf) and adjustment of the path won't
+ * be needed for that reason.
*/
-jlong CgroupV1MemoryController::uses_mem_hierarchy() {
- julong use_hierarchy;
- CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.use_hierarchy", "Use Hierarchy", use_hierarchy);
- return (jlong)use_hierarchy;
-}
-
-void CgroupV1MemoryController::set_subsystem_path(char *cgroup_path) {
- reader()->set_subsystem_path(cgroup_path);
- jlong hierarchy = uses_mem_hierarchy();
- if (hierarchy > 0) {
- set_hierarchical(true);
- }
+bool CgroupV1Controller::needs_hierarchy_adjustment() {
+ assert(_cgroup_path != nullptr, "sanity");
+ return strcmp(_root, _cgroup_path) != 0;
}
static inline
@@ -115,20 +111,6 @@ jlong CgroupV1MemoryController::read_memory_limit_in_bytes(julong phys_mem) {
julong memlimit;
CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.limit_in_bytes", "Memory Limit", memlimit);
if (memlimit >= phys_mem) {
- log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited");
- if (is_hierarchical()) {
- julong hier_memlimit;
- bool is_ok = reader()->read_numerical_key_value("/memory.stat", "hierarchical_memory_limit", &hier_memlimit);
- if (!is_ok) {
- return OSCONTAINER_ERROR;
- }
- log_trace(os, container)("Hierarchical Memory Limit is: " JULONG_FORMAT, hier_memlimit);
- if (hier_memlimit < phys_mem) {
- verbose_log(hier_memlimit, phys_mem);
- return (jlong)hier_memlimit;
- }
- log_trace(os, container)("Hierarchical Memory Limit is: Unlimited");
- }
verbose_log(memlimit, phys_mem);
return (jlong)-1;
} else {
@@ -150,26 +132,10 @@ jlong CgroupV1MemoryController::read_memory_limit_in_bytes(julong phys_mem) {
* upper bound)
*/
jlong CgroupV1MemoryController::read_mem_swap(julong host_total_memsw) {
- julong hier_memswlimit;
julong memswlimit;
CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.memsw.limit_in_bytes", "Memory and Swap Limit", memswlimit);
if (memswlimit >= host_total_memsw) {
- log_trace(os, container)("Non-Hierarchical Memory and Swap Limit is: Unlimited");
- if (is_hierarchical()) {
- const char* matchline = "hierarchical_memsw_limit";
- bool is_ok = reader()->read_numerical_key_value("/memory.stat",
- matchline,
- &hier_memswlimit);
- if (!is_ok) {
- return OSCONTAINER_ERROR;
- }
- log_trace(os, container)("Hierarchical Memory and Swap Limit is: " JULONG_FORMAT, hier_memswlimit);
- if (hier_memswlimit >= host_total_memsw) {
- log_trace(os, container)("Hierarchical Memory and Swap Limit is: Unlimited");
- } else {
- return (jlong)hier_memswlimit;
- }
- }
+ log_trace(os, container)("Memory and Swap Limit is: Unlimited");
return (jlong)-1;
} else {
return (jlong)memswlimit;
@@ -233,6 +199,21 @@ jlong CgroupV1MemoryController::memory_soft_limit_in_bytes(julong phys_mem) {
}
}
+// Constructor
+CgroupV1Subsystem::CgroupV1Subsystem(CgroupV1Controller* cpuset,
+ CgroupV1CpuController* cpu,
+ CgroupV1Controller* cpuacct,
+ CgroupV1Controller* pids,
+ CgroupV1MemoryController* memory) :
+ _cpuset(cpuset),
+ _cpuacct(cpuacct),
+ _pids(pids) {
+ CgroupUtil::adjust_controller(memory);
+ CgroupUtil::adjust_controller(cpu);
+ _memory = new CachingCgroupController(memory);
+ _cpu = new CachingCgroupController(cpu);
+}
+
bool CgroupV1Subsystem::is_containerized() {
// containerized iff all required controllers are mounted
// read-only. See OSContainer::is_containerized() for
diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp
index 251fbde85f0..0c191ab91c7 100644
--- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp
+++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
#include "runtime/os.hpp"
#include "memory/allocation.hpp"
#include "cgroupSubsystem_linux.hpp"
+#include "cgroupUtil_linux.hpp"
// Cgroups version 1 specific implementation
@@ -35,7 +36,6 @@ class CgroupV1Controller: public CgroupController {
private:
/* mountinfo contents */
char* _root;
- char* _mount_point;
bool _read_only;
/* Constructed subsystem directory */
@@ -45,24 +45,27 @@ class CgroupV1Controller: public CgroupController {
CgroupV1Controller(char *root,
char *mountpoint,
bool ro) : _root(os::strdup(root)),
- _mount_point(os::strdup(mountpoint)),
_read_only(ro),
_path(nullptr) {
+ _cgroup_path = nullptr;
+ _mount_point = os::strdup(mountpoint);
}
// Shallow copy constructor
CgroupV1Controller(const CgroupV1Controller& o) : _root(o._root),
- _mount_point(o._mount_point),
_read_only(o._read_only),
_path(o._path) {
+ _cgroup_path = o._cgroup_path;
+ _mount_point = o._mount_point;
}
~CgroupV1Controller() {
// At least one subsystem controller exists with paths to malloc'd path
// names
}
- void set_subsystem_path(char *cgroup_path);
- char *subsystem_path() override { return _path; }
- bool is_read_only() { return _read_only; }
+ void set_subsystem_path(const char *cgroup_path);
+ const char* subsystem_path() override { return _path; }
+ bool is_read_only() override { return _read_only; }
+ bool needs_hierarchy_adjustment() override;
};
class CgroupV1MemoryController final : public CgroupMemoryController {
@@ -71,8 +74,9 @@ class CgroupV1MemoryController final : public CgroupMemoryController {
CgroupV1Controller _reader;
CgroupV1Controller* reader() { return &_reader; }
public:
- bool is_hierarchical() { return _uses_mem_hierarchy; }
- void set_subsystem_path(char *cgroup_path);
+ void set_subsystem_path(const char *cgroup_path) override {
+ reader()->set_subsystem_path(cgroup_path);
+ }
jlong read_memory_limit_in_bytes(julong upper_bound) override;
jlong memory_usage_in_bytes() override;
jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) override;
@@ -85,23 +89,22 @@ class CgroupV1MemoryController final : public CgroupMemoryController {
jlong kernel_memory_limit_in_bytes(julong host_mem);
jlong kernel_memory_max_usage_in_bytes();
void print_version_specific_info(outputStream* st, julong host_mem) override;
+ bool needs_hierarchy_adjustment() override {
+ return reader()->needs_hierarchy_adjustment();
+ }
bool is_read_only() override {
return reader()->is_read_only();
}
+ const char* subsystem_path() override { return reader()->subsystem_path(); }
+ const char* mount_point() override { return reader()->mount_point(); }
+ const char* cgroup_path() override { return reader()->cgroup_path(); }
private:
- /* Some container runtimes set limits via cgroup
- * hierarchy. If set to true consider also memory.stat
- * file if everything else seems unlimited */
- bool _uses_mem_hierarchy;
- jlong uses_mem_hierarchy();
- void set_hierarchical(bool value) { _uses_mem_hierarchy = value; }
jlong read_mem_swappiness();
jlong read_mem_swap(julong host_total_memsw);
public:
CgroupV1MemoryController(const CgroupV1Controller& reader)
- : _reader(reader),
- _uses_mem_hierarchy(false) {
+ : _reader(reader) {
}
};
@@ -115,12 +118,22 @@ class CgroupV1CpuController final : public CgroupCpuController {
int cpu_quota() override;
int cpu_period() override;
int cpu_shares() override;
- void set_subsystem_path(char *cgroup_path) {
+ void set_subsystem_path(const char *cgroup_path) override {
reader()->set_subsystem_path(cgroup_path);
}
bool is_read_only() override {
return reader()->is_read_only();
}
+ const char* subsystem_path() override {
+ return reader()->subsystem_path();
+ }
+ const char* mount_point() override {
+ return reader()->mount_point();
+ }
+ bool needs_hierarchy_adjustment() override {
+ return reader()->needs_hierarchy_adjustment();
+ }
+ const char* cgroup_path() override { return reader()->cgroup_path(); }
public:
CgroupV1CpuController(const CgroupV1Controller& reader) : _reader(reader) {
@@ -130,6 +143,12 @@ class CgroupV1CpuController final : public CgroupCpuController {
class CgroupV1Subsystem: public CgroupSubsystem {
public:
+ CgroupV1Subsystem(CgroupV1Controller* cpuset,
+ CgroupV1CpuController* cpu,
+ CgroupV1Controller* cpuacct,
+ CgroupV1Controller* pids,
+ CgroupV1MemoryController* memory);
+
jlong kernel_memory_usage_in_bytes();
jlong kernel_memory_limit_in_bytes();
jlong kernel_memory_max_usage_in_bytes();
@@ -155,18 +174,6 @@ class CgroupV1Subsystem: public CgroupSubsystem {
CgroupV1Controller* _cpuacct = nullptr;
CgroupV1Controller* _pids = nullptr;
- public:
- CgroupV1Subsystem(CgroupV1Controller* cpuset,
- CgroupV1CpuController* cpu,
- CgroupV1Controller* cpuacct,
- CgroupV1Controller* pids,
- CgroupV1MemoryController* memory) :
- _memory(new CachingCgroupController(memory)),
- _cpuset(cpuset),
- _cpu(new CachingCgroupController(cpu)),
- _cpuacct(cpuacct),
- _pids(pids) {
- }
};
#endif // CGROUP_V1_SUBSYSTEM_LINUX_HPP
diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
index 8f7e12d0954..62e8cac3a62 100644
--- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
+++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
@@ -25,6 +25,22 @@
#include "cgroupV2Subsystem_linux.hpp"
#include "cgroupUtil_linux.hpp"
+// Constructor
+CgroupV2Controller::CgroupV2Controller(char* mount_path,
+ char *cgroup_path,
+ bool ro) : _read_only(ro),
+ _path(construct_path(mount_path, cgroup_path)) {
+ _cgroup_path = os::strdup(cgroup_path);
+ _mount_point = os::strdup(mount_path);
+}
+// Shallow copy constructor
+CgroupV2Controller::CgroupV2Controller(const CgroupV2Controller& o) :
+ _read_only(o._read_only),
+ _path(o._path) {
+ _cgroup_path = o._cgroup_path;
+ _mount_point = o._mount_point;
+}
+
/* cpu_shares
*
* Return the amount of cpu shares available to the process
@@ -95,6 +111,17 @@ int CgroupV2CpuController::cpu_quota() {
return limit;
}
+// Constructor
+CgroupV2Subsystem::CgroupV2Subsystem(CgroupV2MemoryController * memory,
+ CgroupV2CpuController* cpu,
+ CgroupV2Controller unified) :
+ _unified(unified) {
+ CgroupUtil::adjust_controller(memory);
+ CgroupUtil::adjust_controller(cpu);
+ _memory = new CachingCgroupController(memory);
+ _cpu = new CachingCgroupController(cpu);
+}
+
bool CgroupV2Subsystem::is_containerized() {
return _unified.is_read_only() &&
_memory->controller()->is_read_only() &&
@@ -264,6 +291,18 @@ jlong memory_swap_limit_value(CgroupV2Controller* ctrl) {
return swap_limit;
}
+void CgroupV2Controller::set_subsystem_path(const char* cgroup_path) {
+ if (_path != nullptr) {
+ os::free(_path);
+ }
+ _path = construct_path(_mount_point, cgroup_path);
+}
+
+// For cgv2 we only need hierarchy walk if the cgroup path isn't '/' (root)
+bool CgroupV2Controller::needs_hierarchy_adjustment() {
+ return strcmp(_cgroup_path, "/") != 0;
+}
+
void CgroupV2MemoryController::print_version_specific_info(outputStream* st, julong phys_mem) {
jlong swap_current = memory_swap_current_value(reader());
jlong swap_limit = memory_swap_limit_value(reader());
@@ -272,7 +311,7 @@ void CgroupV2MemoryController::print_version_specific_info(outputStream* st, jul
OSContainer::print_container_helper(st, swap_limit, "memory_swap_max_limit_in_bytes");
}
-char* CgroupV2Controller::construct_path(char* mount_path, char *cgroup_path) {
+char* CgroupV2Controller::construct_path(char* mount_path, const char* cgroup_path) {
stringStream ss;
ss.print_raw(mount_path);
if (strcmp(cgroup_path, "/") != 0) {
diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp
index 02774fb70ae..56dcadd670f 100644
--- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp
+++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2022, 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
@@ -26,39 +26,28 @@
#define CGROUP_V2_SUBSYSTEM_LINUX_HPP
#include "cgroupSubsystem_linux.hpp"
+#include "cgroupUtil_linux.hpp"
class CgroupV2Controller: public CgroupController {
private:
- /* the mount path of the cgroup v2 hierarchy */
- char *_mount_path;
- /* The cgroup path for the controller */
- char *_cgroup_path;
bool _read_only;
/* Constructed full path to the subsystem directory */
char *_path;
- static char* construct_path(char* mount_path, char *cgroup_path);
+ static char* construct_path(char* mount_path, const char *cgroup_path);
public:
- CgroupV2Controller(char* mount_path,
- char *cgroup_path,
- bool ro) : _mount_path(os::strdup(mount_path)),
- _cgroup_path(os::strdup(cgroup_path)),
- _read_only(ro),
- _path(construct_path(mount_path, cgroup_path)) {
- }
+ CgroupV2Controller(char* mount_path, char *cgroup_path, bool ro);
// Shallow copy constructor
- CgroupV2Controller(const CgroupV2Controller& o) :
- _mount_path(o._mount_path),
- _cgroup_path(o._cgroup_path),
- _read_only(o._read_only),
- _path(o._path) {
- }
+ CgroupV2Controller(const CgroupV2Controller& o);
~CgroupV2Controller() {
// At least one controller exists with references to the paths
}
- char *subsystem_path() override { return _path; }
+ const char* subsystem_path() override { return _path; }
+ bool needs_hierarchy_adjustment() override;
+ // Allow for optional updates of the subsystem path
+ void set_subsystem_path(const char* cgroup_path);
bool is_read_only() override { return _read_only; }
};
@@ -75,6 +64,17 @@ class CgroupV2CpuController: public CgroupCpuController {
bool is_read_only() override {
return reader()->is_read_only();
}
+ const char* subsystem_path() override {
+ return reader()->subsystem_path();
+ }
+ bool needs_hierarchy_adjustment() override {
+ return reader()->needs_hierarchy_adjustment();
+ }
+ void set_subsystem_path(const char* cgroup_path) override {
+ reader()->set_subsystem_path(cgroup_path);
+ }
+ const char* mount_point() override { return reader()->mount_point(); }
+ const char* cgroup_path() override { return reader()->cgroup_path(); }
};
class CgroupV2MemoryController final: public CgroupMemoryController {
@@ -97,6 +97,17 @@ class CgroupV2MemoryController final: public CgroupMemoryController {
bool is_read_only() override {
return reader()->is_read_only();
}
+ const char* subsystem_path() override {
+ return reader()->subsystem_path();
+ }
+ bool needs_hierarchy_adjustment() override {
+ return reader()->needs_hierarchy_adjustment();
+ }
+ void set_subsystem_path(const char* cgroup_path) override {
+ reader()->set_subsystem_path(cgroup_path);
+ }
+ const char* mount_point() override { return reader()->mount_point(); }
+ const char* cgroup_path() override { return reader()->cgroup_path(); }
};
class CgroupV2Subsystem: public CgroupSubsystem {
@@ -110,13 +121,9 @@ class CgroupV2Subsystem: public CgroupSubsystem {
CgroupV2Controller* unified() { return &_unified; }
public:
- CgroupV2Subsystem(CgroupV2MemoryController* memory,
+ CgroupV2Subsystem(CgroupV2MemoryController * memory,
CgroupV2CpuController* cpu,
- CgroupV2Controller unified) :
- _unified(unified),
- _memory(new CachingCgroupController(memory)),
- _cpu(new CachingCgroupController(cpu)) {
- }
+ CgroupV2Controller unified);
char * cpu_cpuset_cpus() override;
char * cpu_cpuset_memory_nodes() override;
@@ -128,8 +135,8 @@ class CgroupV2Subsystem: public CgroupSubsystem {
const char * container_type() override {
return "cgroupv2";
}
- CachingCgroupController* memory_controller() { return _memory; }
- CachingCgroupController* cpu_controller() { return _cpu; }
+ CachingCgroupController* memory_controller() override { return _memory; }
+ CachingCgroupController* cpu_controller() override { return _cpu; }
};
#endif // CGROUP_V2_SUBSYSTEM_LINUX_HPP
diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp
index b80124cc34e..b648876ac60 100644
--- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp
+++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp
@@ -27,6 +27,7 @@
#include "gc/z/zArray.inline.hpp"
#include "gc/z/zErrno.hpp"
#include "gc/z/zGlobals.hpp"
+#include "gc/z/zInitialize.hpp"
#include "gc/z/zLargePages.inline.hpp"
#include "gc/z/zMountPoint_linux.hpp"
#include "gc/z/zNUMA.inline.hpp"
@@ -103,14 +104,14 @@
#define ZFILENAME_HEAP "java_heap"
// Preferred tmpfs mount points, ordered by priority
-static const char* z_preferred_tmpfs_mountpoints[] = {
+static const char* ZPreferredTmpfsMountpoints[] = {
"/dev/shm",
"/run/shm",
nullptr
};
// Preferred hugetlbfs mount points, ordered by priority
-static const char* z_preferred_hugetlbfs_mountpoints[] = {
+static const char* ZPreferredHugetlbfsMountpoints[] = {
"/dev/hugepages",
"/hugepages",
nullptr
@@ -129,6 +130,7 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity)
// Create backing file
_fd = create_fd(ZFILENAME_HEAP);
if (_fd == -1) {
+ ZInitialize::error("Failed to create heap backing file");
return;
}
@@ -136,7 +138,7 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity)
while (ftruncate(_fd, max_capacity) == -1) {
if (errno != EINTR) {
ZErrno err;
- log_error_p(gc)("Failed to truncate backing file (%s)", err.to_string());
+ ZInitialize::error("Failed to truncate backing file (%s)", err.to_string());
return;
}
}
@@ -145,7 +147,7 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity)
struct statfs buf;
if (fstatfs(_fd, &buf) == -1) {
ZErrno err;
- log_error_p(gc)("Failed to determine filesystem type for backing file (%s)", err.to_string());
+ ZInitialize::error("Failed to determine filesystem type for backing file (%s)", err.to_string());
return;
}
@@ -158,39 +160,39 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity)
// Make sure the filesystem type matches requested large page type
if (ZLargePages::is_transparent() && !is_tmpfs()) {
- log_error_p(gc)("-XX:+UseTransparentHugePages can only be enabled when using a %s filesystem",
- ZFILESYSTEM_TMPFS);
+ ZInitialize::error("-XX:+UseTransparentHugePages can only be enabled when using a %s filesystem",
+ ZFILESYSTEM_TMPFS);
return;
}
if (ZLargePages::is_transparent() && !tmpfs_supports_transparent_huge_pages()) {
- log_error_p(gc)("-XX:+UseTransparentHugePages on a %s filesystem not supported by kernel",
- ZFILESYSTEM_TMPFS);
+ ZInitialize::error("-XX:+UseTransparentHugePages on a %s filesystem not supported by kernel",
+ ZFILESYSTEM_TMPFS);
return;
}
if (ZLargePages::is_explicit() && !is_hugetlbfs()) {
- log_error_p(gc)("-XX:+UseLargePages (without -XX:+UseTransparentHugePages) can only be enabled "
- "when using a %s filesystem", ZFILESYSTEM_HUGETLBFS);
+ ZInitialize::error("-XX:+UseLargePages (without -XX:+UseTransparentHugePages) can only be enabled "
+ "when using a %s filesystem", ZFILESYSTEM_HUGETLBFS);
return;
}
if (!ZLargePages::is_explicit() && is_hugetlbfs()) {
- log_error_p(gc)("-XX:+UseLargePages must be enabled when using a %s filesystem",
- ZFILESYSTEM_HUGETLBFS);
+ ZInitialize::error("-XX:+UseLargePages must be enabled when using a %s filesystem",
+ ZFILESYSTEM_HUGETLBFS);
return;
}
// Make sure the filesystem block size is compatible
if (ZGranuleSize % _block_size != 0) {
- log_error_p(gc)("Filesystem backing the heap has incompatible block size (" SIZE_FORMAT ")",
- _block_size);
+ ZInitialize::error("Filesystem backing the heap has incompatible block size (" SIZE_FORMAT ")",
+ _block_size);
return;
}
if (is_hugetlbfs() && _block_size != ZGranuleSize) {
- log_error_p(gc)("%s filesystem has unexpected block size " SIZE_FORMAT " (expected " SIZE_FORMAT ")",
- ZFILESYSTEM_HUGETLBFS, _block_size, ZGranuleSize);
+ ZInitialize::error("%s filesystem has unexpected block size " SIZE_FORMAT " (expected " SIZE_FORMAT ")",
+ ZFILESYSTEM_HUGETLBFS, _block_size, ZGranuleSize);
return;
}
@@ -226,8 +228,8 @@ int ZPhysicalMemoryBacking::create_file_fd(const char* name) const {
? ZFILESYSTEM_HUGETLBFS
: ZFILESYSTEM_TMPFS;
const char** const preferred_mountpoints = ZLargePages::is_explicit()
- ? z_preferred_hugetlbfs_mountpoints
- : z_preferred_tmpfs_mountpoints;
+ ? ZPreferredHugetlbfsMountpoints
+ : ZPreferredTmpfsMountpoints;
// Find mountpoint
ZMountPoint mountpoint(filesystem, preferred_mountpoints);
diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp
index 1cb0b553c52..90cb00fb7e6 100644
--- a/src/hotspot/os/linux/globals_linux.hpp
+++ b/src/hotspot/os/linux/globals_linux.hpp
@@ -38,10 +38,8 @@
product(bool, UseOprofile, false, \
"enable support for Oprofile profiler") \
\
- /* NB: The default value of UseLinuxPosixThreadCPUClocks may be */ \
- /* overridden in Arguments::parse_each_vm_init_arg. */ \
product(bool, UseLinuxPosixThreadCPUClocks, true, \
- "enable fast Linux Posix clocks where available") \
+ "(Deprecated) enable fast Linux Posix clocks where available") \
\
product(bool, UseTransparentHugePages, false, \
"Use MADV_HUGEPAGE for large pages") \
diff --git a/src/hotspot/os/linux/osThread_linux.cpp b/src/hotspot/os/linux/osThread_linux.cpp
index 9c77cb32f6d..c9a44eb413f 100644
--- a/src/hotspot/os/linux/osThread_linux.cpp
+++ b/src/hotspot/os/linux/osThread_linux.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,27 +22,26 @@
*
*/
-// no precompiled headers
-#include "memory/allocation.inline.hpp"
+#include "precompiled.hpp"
+#include "memory/allocation.hpp"
#include "runtime/mutex.hpp"
#include "runtime/osThread.hpp"
#include
-void OSThread::pd_initialize() {
- _thread_id = 0;
- _pthread_id = 0;
- _siginfo = nullptr;
- _ucontext = nullptr;
- _expanding_stack = 0;
- _alt_sig_stack = nullptr;
-
+OSThread::OSThread()
+ : _thread_id(0),
+ _pthread_id(0),
+ _caller_sigmask(),
+ sr(),
+ _siginfo(nullptr),
+ _ucontext(nullptr),
+ _expanding_stack(0),
+ _alt_sig_stack(nullptr),
+ _startThread_lock(new Monitor(Mutex::event, "startThread_lock")) {
sigemptyset(&_caller_sigmask);
-
- _startThread_lock = new Monitor(Mutex::event, "startThread_lock");
- assert(_startThread_lock !=nullptr, "check");
}
-void OSThread::pd_destroy() {
+OSThread::~OSThread() {
delete _startThread_lock;
}
diff --git a/src/hotspot/os/linux/osThread_linux.hpp b/src/hotspot/os/linux/osThread_linux.hpp
index a849673af62..5ed2d07850a 100644
--- a/src/hotspot/os/linux/osThread_linux.hpp
+++ b/src/hotspot/os/linux/osThread_linux.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,20 +24,17 @@
#ifndef OS_LINUX_OSTHREAD_LINUX_HPP
#define OS_LINUX_OSTHREAD_LINUX_HPP
- public:
- typedef pid_t thread_id_t;
- private:
- int _thread_type;
+#include "runtime/osThreadBase.hpp"
+#include "suspendResume_posix.hpp"
+#include "utilities/globalDefinitions.hpp"
- public:
+class OSThread : public OSThreadBase {
+ friend class VMStructs;
- int thread_type() const {
- return _thread_type;
- }
- void set_thread_type(int type) {
- _thread_type = type;
- }
+ typedef pid_t thread_id_t;
+
+ thread_id_t _thread_id;
// _pthread_id is the pthread id, which is used by library calls
// (e.g. pthread_kill).
@@ -46,15 +43,19 @@
sigset_t _caller_sigmask; // Caller's signal mask
public:
+ OSThread();
+ ~OSThread();
// Methods to save/restore caller's signal mask
sigset_t caller_sigmask() const { return _caller_sigmask; }
void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; }
-#ifndef PRODUCT
- // Used for debugging, return a unique integer for each thread.
- int thread_identifier() const { return _thread_id; }
-#endif
+ thread_id_t thread_id() const {
+ return _thread_id;
+ }
+ void set_thread_id(thread_id_t id) {
+ _thread_id = id;
+ }
pthread_t pthread_id() const {
return _pthread_id;
@@ -67,7 +68,6 @@
// suspension support.
// ***************************************************************
-public:
// flags that support signal based suspend/resume on Linux are in a
// separate class to avoid confusion with many flags in OSThread that
// are used by VM level suspend/resume.
@@ -113,17 +113,10 @@
return _startThread_lock;
}
- // ***************************************************************
- // Platform dependent initialization and cleanup
- // ***************************************************************
-
-private:
-
- void pd_initialize();
- void pd_destroy();
-
-// Reconciliation History
-// osThread_solaris.hpp 1.24 99/08/27 13:11:54
-// End
+ // Printing
+ uintx thread_id_for_printing() const override {
+ return (uintx)_thread_id;
+ }
+};
#endif // OS_LINUX_OSTHREAD_LINUX_HPP
diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp
index 1c735f1b3c9..b2b9a798119 100644
--- a/src/hotspot/os/linux/os_linux.cpp
+++ b/src/hotspot/os/linux/os_linux.cpp
@@ -817,7 +817,7 @@ static void *thread_native_entry(Thread *thread) {
OSThread* osthread = thread->osthread();
Monitor* sync = osthread->startThread_lock();
- osthread->set_thread_id(checked_cast(os::current_thread_id()));
+ osthread->set_thread_id(checked_cast(os::current_thread_id()));
if (UseNUMA) {
int lgrp_id = os::numa_get_group_id();
@@ -864,7 +864,7 @@ static void *thread_native_entry(Thread *thread) {
log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").",
os::current_thread_id(), (uintx) pthread_self());
- return 0;
+ return nullptr;
}
// On Linux, glibc places static TLS blocks (for __thread variables) on
@@ -974,9 +974,6 @@ bool os::create_thread(Thread* thread, ThreadType thr_type,
return false;
}
- // set the correct thread state
- osthread->set_thread_type(thr_type);
-
// Initial state is ALLOCATED but not INITIALIZED
osthread->set_state(ALLOCATED);
@@ -2763,7 +2760,7 @@ void os::jvm_path(char *buf, jint buflen) {
assert(ret, "cannot locate libjvm");
char *rp = nullptr;
if (ret && dli_fname[0] != '\0') {
- rp = os::Posix::realpath(dli_fname, buf, buflen);
+ rp = os::realpath(dli_fname, buf, buflen);
}
if (rp == nullptr) {
return;
@@ -2797,7 +2794,7 @@ void os::jvm_path(char *buf, jint buflen) {
}
assert(strstr(p, "/libjvm") == p, "invalid library name");
- rp = os::Posix::realpath(java_home_var, buf, buflen);
+ rp = os::realpath(java_home_var, buf, buflen);
if (rp == nullptr) {
return;
}
@@ -2818,7 +2815,7 @@ void os::jvm_path(char *buf, jint buflen) {
snprintf(buf + len, buflen-len, "/hotspot/libjvm.so");
} else {
// Go back to path of .so
- rp = os::Posix::realpath(dli_fname, buf, buflen);
+ rp = os::realpath(dli_fname, buf, buflen);
if (rp == nullptr) {
return;
}
@@ -4449,7 +4446,7 @@ void os::init(void) {
check_pax();
// Check the availability of MADV_POPULATE_WRITE.
- FLAG_SET_DEFAULT(UseMadvPopulateWrite, (::madvise(0, 0, MADV_POPULATE_WRITE) == 0));
+ FLAG_SET_DEFAULT(UseMadvPopulateWrite, (::madvise(nullptr, 0, MADV_POPULATE_WRITE) == 0));
os::Posix::init();
}
@@ -4602,7 +4599,7 @@ static void workaround_expand_exec_shield_cs_limit() {
return; // No matter, we tried, best effort.
}
- MemTracker::record_virtual_memory_type((address)codebuf, mtInternal);
+ MemTracker::record_virtual_memory_tag((address)codebuf, mtInternal);
log_info(os)("[CS limit NX emulation work-around, exec code at: %p]", codebuf);
@@ -5053,16 +5050,6 @@ int os::open(const char *path, int oflag, int mode) {
return fd;
}
-// return current position of file pointer
-jlong os::current_file_offset(int fd) {
- return (jlong)::lseek(fd, (off_t)0, SEEK_CUR);
-}
-
-// move file pointer to the specified offset
-jlong os::seek_to_file_offset(int fd, jlong offset) {
- return (jlong)::lseek(fd, (off_t)offset, SEEK_SET);
-}
-
static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time);
static jlong fast_cpu_time(Thread *thread) {
diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp
index 6b902e82802..1d4aecda936 100644
--- a/src/hotspot/os/linux/os_linux.hpp
+++ b/src/hotspot/os/linux/os_linux.hpp
@@ -30,9 +30,7 @@
// os::Linux defines the interface to Linux operating systems
class os::Linux {
- friend class CgroupSubsystem;
friend class os;
- friend class OSContainer;
static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *);
static int (*_pthread_setname_np)(pthread_t, const char*);
@@ -58,7 +56,6 @@ class os::Linux {
static julong available_memory();
static julong free_memory();
- static int active_processor_count();
static void initialize_system_info();
@@ -93,6 +90,7 @@ class os::Linux {
bool has_steal_ticks;
};
+ static int active_processor_count();
static void kernel_version(long* major, long* minor);
// which_logical_cpu=-1 returns accumulated ticks for all cpus.
diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp
index 87abbebe25f..996f83611b0 100644
--- a/src/hotspot/os/linux/os_perf_linux.cpp
+++ b/src/hotspot/os/linux/os_perf_linux.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -430,7 +430,10 @@ static int get_boot_time(uint64_t* time) {
}
static int perf_context_switch_rate(double* rate) {
+ PRAGMA_DIAG_PUSH
+ PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED
static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;
+ PRAGMA_DIAG_POP
static uint64_t bootTime;
static uint64_t lastTimeNanos;
static uint64_t lastSwitches;
@@ -786,7 +789,7 @@ char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() {
jio_snprintf(buffer, PATH_MAX, "/proc/%s/exe", _entry->d_name);
buffer[PATH_MAX - 1] = '\0';
- return os::Posix::realpath(buffer, _exePath, PATH_MAX);
+ return os::realpath(buffer, _exePath, PATH_MAX);
}
char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
diff --git a/src/hotspot/os/linux/vmStructs_linux.hpp b/src/hotspot/os/linux/vmStructs_linux.hpp
index 818f6bb188f..3b82ac58ac6 100644
--- a/src/hotspot/os/linux/vmStructs_linux.hpp
+++ b/src/hotspot/os/linux/vmStructs_linux.hpp
@@ -31,9 +31,22 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-
-#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
+#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
+ \
+ /******************************/ \
+ /* Threads (NOTE: incomplete) */ \
+ /******************************/ \
+ nonstatic_field(OSThread, _thread_id, pid_t) \
+ nonstatic_field(OSThread, _pthread_id, pthread_t)
+
+#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
+ \
+ /**********************/ \
+ /* Posix Thread IDs */ \
+ /**********************/ \
+ \
+ declare_integer_type(pid_t) \
+ declare_unsigned_integer_type(pthread_t)
#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/os/posix/dtrace/hotspot_jni.d b/src/hotspot/os/posix/dtrace/hotspot_jni.d
index eb95b7e4c3a..c5676921b37 100644
--- a/src/hotspot/os/posix/dtrace/hotspot_jni.d
+++ b/src/hotspot/os/posix/dtrace/hotspot_jni.d
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -19,7 +19,7 @@
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
- *
+ *
*/
provider hotspot_jni {
@@ -129,7 +129,7 @@ provider hotspot_jni {
probe CallNonvirtualVoidMethodA__return();
probe CallNonvirtualVoidMethod__entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualVoidMethod__return();
- probe CallNonvirtualVoidMethodV__entry(void*, void*, void*, uintptr_t);
+ probe CallNonvirtualVoidMethodV__entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualVoidMethodV__return();
probe CallObjectMethodA__entry(void*, void*, uintptr_t);
probe CallObjectMethodA__return(void*);
@@ -200,14 +200,14 @@ provider hotspot_jni {
probe CallStaticVoidMethodA__entry(void*, void*, uintptr_t);
probe CallStaticVoidMethodA__return();
probe CallStaticVoidMethod__entry(void*, void*, uintptr_t);
- probe CallStaticVoidMethod__return();
- probe CallStaticVoidMethodV__entry(void*, void*, uintptr_t);
+ probe CallStaticVoidMethod__return();
+ probe CallStaticVoidMethodV__entry(void*, void*, uintptr_t);
probe CallStaticVoidMethodV__return();
- probe CallVoidMethodA__entry(void*, void*, uintptr_t);
+ probe CallVoidMethodA__entry(void*, void*, uintptr_t);
probe CallVoidMethodA__return();
- probe CallVoidMethod__entry(void*, void*, uintptr_t);
- probe CallVoidMethod__return();
- probe CallVoidMethodV__entry(void*, void*, uintptr_t);
+ probe CallVoidMethod__entry(void*, void*, uintptr_t);
+ probe CallVoidMethod__return();
+ probe CallVoidMethodV__entry(void*, void*, uintptr_t);
probe CallVoidMethodV__return();
probe CreateJavaVM__entry(void**, void**, void*);
probe CreateJavaVM__return(uint32_t);
@@ -229,7 +229,7 @@ provider hotspot_jni {
probe ExceptionCheck__return(uintptr_t);
probe ExceptionClear__entry(void*);
probe ExceptionClear__return();
- probe ExceptionDescribe__entry(void*);
+ probe ExceptionDescribe__entry(void*);
probe ExceptionDescribe__return();
probe ExceptionOccurred__entry(void*);
probe ExceptionOccurred__return(void*);
@@ -352,6 +352,8 @@ provider hotspot_jni {
probe GetStringUTFChars__return(const char*);
probe GetStringUTFLength__entry(void*, void*);
probe GetStringUTFLength__return(uintptr_t);
+ probe GetStringUTFLengthAsLong__entry(void*, void*);
+ probe GetStringUTFLengthAsLong__return(uintptr_t);
probe GetStringUTFRegion__entry(void*, void*, uintptr_t, uintptr_t, char*);
probe GetStringUTFRegion__return();
probe GetSuperclass__entry(void*, void*);
@@ -388,13 +390,13 @@ provider hotspot_jni {
probe NewLocalRef__return(void*);
probe NewLongArray__entry(void*, uintptr_t);
probe NewLongArray__return(void*);
- probe NewObjectA__entry(void*, void*, uintptr_t);
+ probe NewObjectA__entry(void*, void*, uintptr_t);
probe NewObjectA__return(void*);
probe NewObjectArray__entry(void*, uintptr_t, void*, void*);
probe NewObjectArray__return(void*);
- probe NewObject__entry(void*, void*, uintptr_t);
+ probe NewObject__entry(void*, void*, uintptr_t);
probe NewObject__return(void*);
- probe NewObjectV__entry(void*, void*, uintptr_t);
+ probe NewObjectV__entry(void*, void*, uintptr_t);
probe NewObjectV__return(void*);
probe NewShortArray__entry(void*, uintptr_t);
probe NewShortArray__return(void*);
@@ -408,7 +410,7 @@ provider hotspot_jni {
probe PopLocalFrame__return(void*);
probe PushLocalFrame__entry(void*, uint32_t);
probe PushLocalFrame__return(uint32_t);
- probe RegisterNatives__entry(void*, void*, const void*, uint32_t);
+ probe RegisterNatives__entry(void*, void*, const void*, uint32_t);
probe RegisterNatives__return(uint32_t);
probe ReleaseBooleanArrayElements__entry(void*, void*, uintptr_t*, uint32_t);
probe ReleaseBooleanArrayElements__return();
@@ -490,13 +492,13 @@ provider hotspot_jni {
probe SetStaticShortField__return();
probe Throw__entry(void*, void*);
probe Throw__return(intptr_t);
- probe ThrowNew__entry(void*, void*, const char*);
- probe ThrowNew__return(intptr_t);
+ probe ThrowNew__entry(void*, void*, const char*);
+ probe ThrowNew__return(intptr_t);
probe ToReflectedField__entry(void*, void*, uintptr_t, uintptr_t);
probe ToReflectedField__return(void*);
probe ToReflectedMethod__entry(void*, void*, uintptr_t, uintptr_t);
probe ToReflectedMethod__return(void*);
- probe UnregisterNatives__entry(void*, void*);
+ probe UnregisterNatives__entry(void*, void*);
probe UnregisterNatives__return(uint32_t);
};
@@ -505,4 +507,3 @@ provider hotspot_jni {
#pragma D attributes Private/Private/Unknown provider hotspot_jni function
#pragma D attributes Standard/Standard/Common provider hotspot_jni name
#pragma D attributes Evolving/Evolving/Common provider hotspot_jni args
-
diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp
index 26bff6c8bd4..75253843593 100644
--- a/src/hotspot/os/posix/os_posix.cpp
+++ b/src/hotspot/os/posix/os_posix.cpp
@@ -104,49 +104,44 @@ static int clock_tics_per_sec = 100;
size_t os::_os_min_stack_allowed = PTHREAD_STACK_MIN;
// Check core dump limit and report possible place where core can be found
-void os::check_dump_limit(char* buffer, size_t bufferSize) {
+void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only) {
if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) {
jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line");
VMError::record_coredump_status(buffer, false);
- return;
- }
-
- int n;
- struct rlimit rlim;
- bool success;
-
- char core_path[PATH_MAX];
- n = get_core_path(core_path, PATH_MAX);
-
- if (n <= 0) {
- jio_snprintf(buffer, bufferSize, "core.%d (may not exist)", current_process_id());
- success = true;
+ } else {
+ struct rlimit rlim;
+ bool success = true;
+ bool warn = true;
+ char core_path[PATH_MAX];
+ if (get_core_path(core_path, PATH_MAX) <= 0) {
+ jio_snprintf(buffer, bufferSize, "core.%d (may not exist)", current_process_id());
#ifdef LINUX
- } else if (core_path[0] == '"') { // redirect to user process
- jio_snprintf(buffer, bufferSize, "Core dumps may be processed with %s", core_path);
- success = true;
+ } else if (core_path[0] == '"') { // redirect to user process
+ jio_snprintf(buffer, bufferSize, "Core dumps may be processed with %s", core_path);
#endif
- } else if (getrlimit(RLIMIT_CORE, &rlim) != 0) {
- jio_snprintf(buffer, bufferSize, "%s (may not exist)", core_path);
- success = true;
- } else {
- switch(rlim.rlim_cur) {
- case RLIM_INFINITY:
- jio_snprintf(buffer, bufferSize, "%s", core_path);
- success = true;
- break;
- case 0:
- jio_snprintf(buffer, bufferSize, "Core dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again");
- success = false;
- break;
- default:
- jio_snprintf(buffer, bufferSize, "%s (max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", core_path, uint64_t(rlim.rlim_cur) / K);
- success = true;
- break;
+ } else if (getrlimit(RLIMIT_CORE, &rlim) != 0) {
+ jio_snprintf(buffer, bufferSize, "%s (may not exist)", core_path);
+ } else {
+ switch(rlim.rlim_cur) {
+ case RLIM_INFINITY:
+ jio_snprintf(buffer, bufferSize, "%s", core_path);
+ warn = false;
+ break;
+ case 0:
+ jio_snprintf(buffer, bufferSize, "Core dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again");
+ success = false;
+ break;
+ default:
+ jio_snprintf(buffer, bufferSize, "%s (max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", core_path, uint64_t(rlim.rlim_cur) / K);
+ break;
+ }
+ }
+ if (!check_only) {
+ VMError::record_coredump_status(buffer, success);
+ } else if (warn) {
+ warning("CreateCoredumpOnCrash specified, but %s", buffer);
}
}
-
- VMError::record_coredump_status(buffer, success);
}
bool os::committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size) {
@@ -348,6 +343,16 @@ int os::create_file_for_heap(const char* dir) {
return fd;
}
+// return current position of file pointer
+jlong os::current_file_offset(int fd) {
+ return (jlong)::lseek(fd, (off_t)0, SEEK_CUR);
+}
+
+// move file pointer to the specified offset
+jlong os::seek_to_file_offset(int fd, jlong offset) {
+ return (jlong)::lseek(fd, (off_t)offset, SEEK_SET);
+}
+
// Is a (classpath) directory empty?
bool os::dir_is_empty(const char* path) {
DIR *dir = nullptr;
@@ -367,7 +372,7 @@ bool os::dir_is_empty(const char* path) {
return result;
}
-static char* reserve_mmapped_memory(size_t bytes, char* requested_addr, MEMFLAGS flag) {
+static char* reserve_mmapped_memory(size_t bytes, char* requested_addr, MemTag mem_tag) {
char * addr;
int flags = MAP_PRIVATE NOT_AIX( | MAP_NORESERVE ) | MAP_ANONYMOUS;
if (requested_addr != nullptr) {
@@ -382,7 +387,7 @@ static char* reserve_mmapped_memory(size_t bytes, char* requested_addr, MEMFLAGS
flags, -1, 0);
if (addr != MAP_FAILED) {
- MemTracker::record_virtual_memory_reserve((address)addr, bytes, CALLER_PC, flag);
+ MemTracker::record_virtual_memory_reserve((address)addr, bytes, CALLER_PC, mem_tag);
return addr;
}
return nullptr;
@@ -495,7 +500,7 @@ char* os::reserve_memory_aligned(size_t size, size_t alignment, bool exec) {
return chop_extra_memory(size, alignment, extra_base, extra_size);
}
-char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int file_desc, MEMFLAGS flag) {
+char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int file_desc, MemTag mem_tag) {
size_t extra_size = calculate_aligned_extra_size(size, alignment);
// For file mapping, we do not call os:map_memory_to_file(size,fd) since:
// - we later chop away parts of the mapping using os::release_memory and that could fail if the
@@ -503,7 +508,7 @@ char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int file_des
// - The memory API os::reserve_memory uses is an implementation detail. It may (and usually is)
// mmap but it also may System V shared memory which cannot be uncommitted as a whole, so
// chopping off and unmapping excess bits back and front (see below) would not work.
- char* extra_base = reserve_mmapped_memory(extra_size, nullptr, flag);
+ char* extra_base = reserve_mmapped_memory(extra_size, nullptr, mem_tag);
if (extra_base == nullptr) {
return nullptr;
}
@@ -1024,10 +1029,10 @@ char* os::Posix::describe_pthread_attr(char* buf, size_t buflen, const pthread_a
return buf;
}
-char* os::Posix::realpath(const char* filename, char* outbuf, size_t outbuflen) {
+char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) {
if (filename == nullptr || outbuf == nullptr || outbuflen < 1) {
- assert(false, "os::Posix::realpath: invalid arguments.");
+ assert(false, "os::realpath: invalid arguments.");
errno = EINVAL;
return nullptr;
}
@@ -1062,7 +1067,6 @@ char* os::Posix::realpath(const char* filename, char* outbuf, size_t outbuflen)
}
}
return result;
-
}
int os::stat(const char *path, struct stat *sbuf) {
diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp
index d872a6dae89..cac5b250cdf 100644
--- a/src/hotspot/os/posix/os_posix.hpp
+++ b/src/hotspot/os/posix/os_posix.hpp
@@ -73,13 +73,6 @@ class os::Posix {
// to buf with len buflen; buf is returned.
static char* describe_pthread_attr(char* buf, size_t buflen, const pthread_attr_t* attr);
- // A safe implementation of realpath which will not cause a buffer overflow if the resolved path
- // is longer than PATH_MAX.
- // On success, returns 'outbuf', which now contains the path.
- // On error, it will return null and set errno. The content of 'outbuf' is undefined.
- // On truncation error ('outbuf' too small), it will return null and set errno to ENAMETOOLONG.
- static char* realpath(const char* filename, char* outbuf, size_t outbuflen);
-
// Returns true if given uid is root.
static bool is_root(uid_t uid);
diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp
index 4339a21ae4e..4eb46169878 100644
--- a/src/hotspot/os/posix/perfMemory_posix.cpp
+++ b/src/hotspot/os/posix/perfMemory_posix.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2021 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -499,11 +499,11 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) {
// short circuit the directory search if the process doesn't even exist.
if (kill(vmid, 0) == OS_ERR) {
if (errno == ESRCH) {
- THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
- "Process not found");
+ THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
+ "Process not found");
}
else /* EPERM */ {
- THROW_MSG_0(vmSymbols::java_io_IOException(), os::strerror(errno));
+ THROW_MSG_NULL(vmSymbols::java_io_IOException(), os::strerror(errno));
}
}
@@ -1329,7 +1329,7 @@ void PerfMemory::attach(int vmid, char** addrp, size_t* sizep, TRAPS) {
//
void PerfMemory::detach(char* addr, size_t bytes) {
- assert(addr != 0, "address sanity check");
+ assert(addr != nullptr, "address sanity check");
assert(bytes > 0, "capacity sanity check");
if (PerfMemory::contains(addr) || PerfMemory::contains(addr + bytes - 1)) {
diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp
index a9d3bb9284c..6a14d0a4856 100644
--- a/src/hotspot/os/posix/signals_posix.cpp
+++ b/src/hotspot/os/posix/signals_posix.cpp
@@ -1719,7 +1719,7 @@ static int SR_initialize() {
struct sigaction act;
char *s;
// Get signal number to use for suspend/resume
- if ((s = ::getenv("_JAVA_SR_SIGNUM")) != 0) {
+ if ((s = ::getenv("_JAVA_SR_SIGNUM")) != nullptr) {
int sig;
bool result = parse_integer(s, &sig);
if (result && sig > MAX2(SIGSEGV, SIGBUS) && // See 4355769.
@@ -1742,7 +1742,7 @@ static int SR_initialize() {
pthread_sigmask(SIG_BLOCK, nullptr, &act.sa_mask);
remove_error_signals_from_set(&(act.sa_mask));
- if (sigaction(PosixSignals::SR_signum, &act, 0) == -1) {
+ if (sigaction(PosixSignals::SR_signum, &act, nullptr) == -1) {
return -1;
}
diff --git a/src/hotspot/os/posix/threadCritical_posix.cpp b/src/hotspot/os/posix/threadCritical_posix.cpp
index 45eba4c1585..cd3b42e71ba 100644
--- a/src/hotspot/os/posix/threadCritical_posix.cpp
+++ b/src/hotspot/os/posix/threadCritical_posix.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2014 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -26,6 +26,7 @@
#include "precompiled.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/threadCritical.hpp"
+#include "utilities/compilerWarnings.hpp"
// put OS-includes here
# include
@@ -35,7 +36,12 @@
//
static pthread_t tc_owner = 0;
+
+PRAGMA_DIAG_PUSH
+PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED
static pthread_mutex_t tc_mutex = PTHREAD_MUTEX_INITIALIZER;
+PRAGMA_DIAG_POP
+
static int tc_count = 0;
ThreadCritical::ThreadCritical() {
diff --git a/src/hotspot/os/windows/attachListener_windows.cpp b/src/hotspot/os/windows/attachListener_windows.cpp
index 7e455cf0a49..3f6ca941c20 100644
--- a/src/hotspot/os/windows/attachListener_windows.cpp
+++ b/src/hotspot/os/windows/attachListener_windows.cpp
@@ -318,7 +318,7 @@ void Win32AttachOperation::complete(jint result, bufferedStream* result_stream)
BOOL fSuccess;
char msg[32];
- _snprintf(msg, sizeof(msg), "%d\n", result);
+ os::snprintf(msg, sizeof(msg), "%d\n", result);
msg[sizeof(msg) - 1] = '\0';
fSuccess = write_pipe(hPipe, msg, (int)strlen(msg));
diff --git a/src/hotspot/os/windows/globals_windows.hpp b/src/hotspot/os/windows/globals_windows.hpp
index 78cbac6e9cc..8f0a6261cc0 100644
--- a/src/hotspot/os/windows/globals_windows.hpp
+++ b/src/hotspot/os/windows/globals_windows.hpp
@@ -38,6 +38,10 @@
product(bool, UseAllWindowsProcessorGroups, false, \
"Use all processor groups on supported Windows versions") \
\
+product(bool, EnableAllLargePageSizesForWindows, false, \
+ "Enable support for multiple large page sizes on " \
+ "Windows Server") \
+ \
product(bool, UseOSErrorReporting, false, \
"Let VM fatal error propagate to the OS (ie. WER on Windows)")
diff --git a/src/hotspot/os/windows/memMapPrinter_windows.cpp b/src/hotspot/os/windows/memMapPrinter_windows.cpp
new file mode 100644
index 00000000000..eb6b24a9d13
--- /dev/null
+++ b/src/hotspot/os/windows/memMapPrinter_windows.cpp
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, Red Hat, Inc. and/or its affiliates.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 "nmt/memMapPrinter.hpp"
+#include "os_windows.hpp"
+#include "runtime/vm_version.hpp"
+
+#include
+#include
+#include
+#include
+
+/* maximum number of mapping records returned */
+static const int MAX_REGIONS_RETURNED = 1000000;
+
+class MappingInfo {
+public:
+ stringStream _ap_buffer;
+ stringStream _state_buffer;
+ stringStream _protect_buffer;
+ stringStream _type_buffer;
+ char _file_name[MAX_PATH];
+
+ MappingInfo() {}
+
+ void process(MEMORY_BASIC_INFORMATION& mem_info) {
+ _ap_buffer.reset();
+ _state_buffer.reset();
+ _protect_buffer.reset();
+ _type_buffer.reset();
+ get_protect_string(_ap_buffer, mem_info.AllocationProtect);
+ get_state_string(_state_buffer, mem_info);
+ get_protect_string(_protect_buffer, mem_info.Protect);
+ get_type_string(_type_buffer, mem_info);
+ _file_name[0] = 0;
+ if (mem_info.Type == MEM_IMAGE) {
+ HMODULE hModule = 0;
+ if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast(mem_info.AllocationBase), &hModule)) {
+ GetModuleFileName(hModule, _file_name, sizeof(_file_name));
+ }
+ }
+ }
+
+ void get_protect_string(outputStream& out, DWORD prot) {
+ const char read_c = prot & (PAGE_READONLY | PAGE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY) ? 'r' : '-';
+ const char write_c = prot & (PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) ? 'w' : '-';
+ const char execute_c = prot & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) ? 'x' : '-';
+ out.print("%c%c%c", read_c, write_c, execute_c);
+ if (prot & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY)) {
+ out.put('c');
+ }
+ if (prot & PAGE_GUARD) {
+ out.put('g');
+ }
+ if (prot & PAGE_NOCACHE) {
+ out.put('n');
+ }
+ if (prot & PAGE_WRITECOMBINE) {
+ out.put('W');
+ }
+ const DWORD bits = PAGE_NOACCESS | PAGE_READONLY | PAGE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE
+ | PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE
+ | PAGE_GUARD | PAGE_NOCACHE | PAGE_WRITECOMBINE;
+ if ((prot & bits) != prot) {
+ out.print_cr("Unknown Windows memory protection value: 0x%x unknown bits: 0x%x", prot, prot & ~bits);
+ assert(false, "Unknown Windows memory protection value: 0x%x unknown bits: 0x%x", prot, prot & ~bits);
+ }
+ }
+
+ void get_state_string(outputStream& out, MEMORY_BASIC_INFORMATION& mem_info) {
+ if (mem_info.State == MEM_COMMIT) {
+ out.put('c');
+ } else if (mem_info.State == MEM_FREE) {
+ out.put('f');
+ } else if (mem_info.State == MEM_RESERVE) {
+ out.put('r');
+ } else {
+ out.print_cr("Unknown Windows memory state value: 0x%x", mem_info.State);
+ assert(false, "Unknown Windows memory state value: 0x%x", mem_info.State);
+ }
+ }
+
+ void get_type_string(outputStream& out, MEMORY_BASIC_INFORMATION& mem_info) {
+ if (mem_info.Type == MEM_IMAGE) {
+ out.print("img");
+ } else if (mem_info.Type == MEM_MAPPED) {
+ out.print("map");
+ } else if (mem_info.Type == MEM_PRIVATE) {
+ out.print("pvt");
+ } else if (mem_info.Type == 0 && mem_info.State == MEM_FREE) {
+ out.print("---");
+ } else {
+ out.print_cr("Unknown Windows memory type 0x%x", mem_info.Type);
+ assert(false, "Unknown Windows memory type 0x%x", mem_info.Type);
+ }
+ }
+};
+
+class MappingInfoSummary {
+ unsigned _num_mappings;
+ size_t _total_region_size; // combined resident set size
+ size_t _total_committed; // combined committed size
+ class WinOsInfo : public os::win32 {
+ public:
+ static void printOsInfo(outputStream* st) {
+ st->print("OS:");
+ os::win32::print_windows_version(st);
+ os::win32::print_uptime_info(st);
+ VM_Version::print_platform_virtualization_info(st);
+ os::print_memory_info(st);
+ }
+ };
+public:
+ MappingInfoSummary() : _num_mappings(0), _total_region_size(0),
+ _total_committed(0) {}
+
+ void add_mapping(const MEMORY_BASIC_INFORMATION& mem_info, const MappingInfo& mapping_info) {
+ if (mem_info.State != MEM_FREE) {
+ _num_mappings++;
+ _total_region_size += mem_info.RegionSize;
+ _total_committed += mem_info.State == MEM_COMMIT ? mem_info.RegionSize : 0;
+ }
+ }
+
+ void print_on(const MappingPrintSession& session) const {
+ outputStream* st = session.out();
+ WinOsInfo::printOsInfo(st);
+ st->print_cr("current process reserved memory: " PROPERFMT, PROPERFMTARGS(_total_region_size));
+ st->print_cr("current process committed memory: " PROPERFMT, PROPERFMTARGS(_total_committed));
+ st->print_cr("current process region count: " PROPERFMT, PROPERFMTARGS(_num_mappings));
+ }
+};
+
+class MappingInfoPrinter {
+ const MappingPrintSession& _session;
+public:
+ MappingInfoPrinter(const MappingPrintSession& session) :
+ _session(session)
+ {}
+
+ void print_single_mapping(const MEMORY_BASIC_INFORMATION& mem_info, const MappingInfo& mapping_info) const {
+ outputStream* st = _session.out();
+#define INDENT_BY(n) \
+ if (st->fill_to(n) == 0) { \
+ st->print(" "); \
+ }
+ st->print(PTR_FORMAT "-" PTR_FORMAT, mem_info.BaseAddress, static_cast(mem_info.BaseAddress) + mem_info.RegionSize);
+ INDENT_BY(38);
+ st->print("%12zu", mem_info.RegionSize);
+ INDENT_BY(51);
+ st->print("%s", mapping_info._protect_buffer.base());
+ INDENT_BY(57);
+ st->print("%s-%s", mapping_info._state_buffer.base(), mapping_info._type_buffer.base());
+ INDENT_BY(63);
+ st->print("%#11llx", reinterpret_cast(mem_info.BaseAddress) - reinterpret_cast(mem_info.AllocationBase));
+ INDENT_BY(72);
+ if (_session.print_nmt_info_for_region(mem_info.BaseAddress, static_cast(mem_info.BaseAddress) + mem_info.RegionSize)) {
+ st->print(" ");
+ }
+ st->print_raw(mapping_info._file_name);
+ #undef INDENT_BY
+ st->cr();
+ }
+
+ void print_legend() const {
+ outputStream* st = _session.out();
+ st->print_cr("from, to, vsize: address range and size");
+ st->print_cr("prot: protection:");
+ st->print_cr(" rwx: read / write / execute");
+ st->print_cr(" c: copy on write");
+ st->print_cr(" g: guard");
+ st->print_cr(" n: no cache");
+ st->print_cr(" W: write combine");
+ st->print_cr("state: region state and type:");
+ st->print_cr(" state: committed / reserved");
+ st->print_cr(" type: image / mapped / private");
+ st->print_cr("file: file mapped, if mapping is not anonymous");
+ st->print_cr("vm info: VM information (requires NMT)");
+ {
+ streamIndentor si(st, 16);
+ _session.print_nmt_flag_legend();
+ }
+ }
+
+ void print_header() const {
+ outputStream* st = _session.out();
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ // 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+ // 0x00007ffb24565000-0x00007ffb24a7e000 5345280 r-- c-img 0x1155000 C:\work\jdk\build\fastdebug\jdk\bin\server\jvm.dll
+ st->print_cr("from to vsize prot state offset vminfo/file");
+ st->print_cr("===========================================================================================");
+ }
+};
+
+void MemMapPrinter::pd_print_all_mappings(const MappingPrintSession& session) {
+
+ HANDLE hProcess = GetCurrentProcess();
+
+ MappingInfoPrinter printer(session);
+ MappingInfoSummary summary;
+
+ outputStream* const st = session.out();
+
+ printer.print_legend();
+ st->cr();
+ printer.print_header();
+
+ MEMORY_BASIC_INFORMATION mem_info;
+ MappingInfo mapping_info;
+
+ int region_count = 0;
+ ::memset(&mem_info, 0, sizeof(mem_info));
+ for (char* ptr = 0; VirtualQueryEx(hProcess, ptr, &mem_info, sizeof(mem_info)) == sizeof(mem_info); ) {
+ assert(mem_info.RegionSize > 0, "RegionSize is not greater than zero");
+ if (++region_count > MAX_REGIONS_RETURNED) {
+ st->print_cr("limit of %d regions reached (results inaccurate)", region_count);
+ break;
+ }
+ mapping_info.process(mem_info);
+ if (mem_info.State != MEM_FREE) {
+ printer.print_single_mapping(mem_info, mapping_info);
+ summary.add_mapping(mem_info, mapping_info);
+ }
+ ptr += mem_info.RegionSize;
+ ::memset(&mem_info, 0, sizeof(mem_info));
+ }
+ st->cr();
+ summary.print_on(session);
+ st->cr();
+}
diff --git a/src/hotspot/os/windows/osThread_windows.cpp b/src/hotspot/os/windows/osThread_windows.cpp
index 5f369bb7aa0..922b4b0104b 100644
--- a/src/hotspot/os/windows/osThread_windows.cpp
+++ b/src/hotspot/os/windows/osThread_windows.cpp
@@ -22,17 +22,17 @@
*
*/
-// no precompiled headers
-#include "runtime/os.hpp"
+#include "precompiled.hpp"
#include "runtime/osThread.hpp"
-void OSThread::pd_initialize() {
- set_thread_handle(nullptr);
- set_thread_id(0);
- set_interrupt_event(nullptr);
-}
+#include
+
+OSThread::OSThread()
+ : _thread_id(0),
+ _thread_handle(nullptr),
+ _interrupt_event(nullptr) {}
-void OSThread::pd_destroy() {
+OSThread::~OSThread() {
if (_interrupt_event != nullptr) {
CloseHandle(_interrupt_event);
}
diff --git a/src/hotspot/os/windows/osThread_windows.hpp b/src/hotspot/os/windows/osThread_windows.hpp
index 5bd07646b17..e54783aef1c 100644
--- a/src/hotspot/os/windows/osThread_windows.hpp
+++ b/src/hotspot/os/windows/osThread_windows.hpp
@@ -25,17 +25,29 @@
#ifndef OS_WINDOWS_OSTHREAD_WINDOWS_HPP
#define OS_WINDOWS_OSTHREAD_WINDOWS_HPP
- typedef void* HANDLE;
- public:
+#include "runtime/osThreadBase.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class OSThread : public OSThreadBase {
+ friend class VMStructs;
+
typedef unsigned long thread_id_t;
+ typedef void* HANDLE;
+
+ thread_id_t _thread_id;
- private:
// Win32-specific thread information
HANDLE _thread_handle; // Win32 thread handle
HANDLE _interrupt_event; // Event signalled on thread interrupt for use by
// Process.waitFor().
public:
+ OSThread();
+ ~OSThread();
+
+ thread_id_t thread_id() const { return _thread_id; }
+ void set_thread_id(thread_id_t id) { _thread_id = id; }
+
// The following will only apply in the Win32 implementation, and should only
// be visible in the concrete class, not this which should be an abstract base class
HANDLE thread_handle() const { return _thread_handle; }
@@ -45,13 +57,9 @@
// This is specialized on Windows to interact with the _interrupt_event.
void set_interrupted(bool z);
-#ifndef PRODUCT
- // Used for debugging, return a unique integer for each thread.
- int thread_identifier() const { return _thread_id; }
-#endif
-
- private:
- void pd_initialize();
- void pd_destroy();
+ uintx thread_id_for_printing() const override {
+ return (uintx)_thread_id;
+ }
+};
#endif // OS_WINDOWS_OSTHREAD_WINDOWS_HPP
diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp
index 1cc7d9aa33a..4dafef0c098 100644
--- a/src/hotspot/os/windows/os_windows.cpp
+++ b/src/hotspot/os/windows/os_windows.cpp
@@ -63,6 +63,7 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/statSampler.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/suspendedThreadTask.hpp"
#include "runtime/threadCritical.hpp"
#include "runtime/threads.hpp"
#include "runtime/timer.hpp"
@@ -1286,38 +1287,50 @@ void os::shutdown() {
static HANDLE dumpFile = nullptr;
-// Check if dump file can be created.
-void os::check_dump_limit(char* buffer, size_t buffsz) {
- bool status = true;
+// Check if core dump is active and if a core dump file can be created
+void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only) {
if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) {
- jio_snprintf(buffer, buffsz, "CreateCoredumpOnCrash is disabled from command line");
- status = false;
- }
-
+ jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line");
+ VMError::record_coredump_status(buffer, false);
+ } else {
+ bool success = true;
+ bool warn = true;
#ifndef ASSERT
- if (!os::win32::is_windows_server() && FLAG_IS_DEFAULT(CreateCoredumpOnCrash)) {
- jio_snprintf(buffer, buffsz, "Minidumps are not enabled by default on client versions of Windows");
- status = false;
- }
+ if (!os::win32::is_windows_server() && FLAG_IS_DEFAULT(CreateCoredumpOnCrash)) {
+ jio_snprintf(buffer, bufferSize, "Minidumps are not enabled by default on client versions of Windows");
+ success = false;
+ warn = true;
+ }
#endif
- if (status) {
- const char* cwd = get_current_directory(nullptr, 0);
- int pid = current_process_id();
- if (cwd != nullptr) {
- jio_snprintf(buffer, buffsz, "%s\\hs_err_pid%u.mdmp", cwd, pid);
- } else {
- jio_snprintf(buffer, buffsz, ".\\hs_err_pid%u.mdmp", pid);
+ if (success) {
+ if (!check_only) {
+ const char* cwd = get_current_directory(nullptr, 0);
+ int pid = current_process_id();
+ if (cwd != nullptr) {
+ jio_snprintf(buffer, bufferSize, "%s\\hs_err_pid%u.mdmp", cwd, pid);
+ } else {
+ jio_snprintf(buffer, bufferSize, ".\\hs_err_pid%u.mdmp", pid);
+ }
+
+ if (dumpFile == nullptr &&
+ (dumpFile = CreateFile(buffer, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr))
+ == INVALID_HANDLE_VALUE) {
+ jio_snprintf(buffer, bufferSize, "Failed to create minidump file (0x%x).", GetLastError());
+ success = false;
+ }
+ } else {
+ // For now on Windows, there are no more checks that we can do
+ warn = false;
+ }
}
- if (dumpFile == nullptr &&
- (dumpFile = CreateFile(buffer, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr))
- == INVALID_HANDLE_VALUE) {
- jio_snprintf(buffer, buffsz, "Failed to create minidump file (0x%x).", GetLastError());
- status = false;
+ if (!check_only) {
+ VMError::record_coredump_status(buffer, success);
+ } else if (warn) {
+ warning("CreateCoredumpOnCrash specified, but %s", buffer);
}
}
- VMError::record_coredump_status(buffer, status);
}
void os::abort(bool dump_core, void* siginfo, const void* context) {
@@ -1776,14 +1789,14 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) {
}
if (lib_arch_str != nullptr) {
- ::_snprintf(ebuf, ebuflen - 1,
- "Can't load %s-bit .dll on a %s-bit platform",
- lib_arch_str, running_arch_str);
+ os::snprintf(ebuf, ebuflen - 1,
+ "Can't load %s-bit .dll on a %s-bit platform",
+ lib_arch_str, running_arch_str);
} else {
// don't know what architecture this dll was build for
- ::_snprintf(ebuf, ebuflen - 1,
- "Can't load this .dll (machine code=0x%x) on a %s-bit platform",
- lib_arch, running_arch_str);
+ os::snprintf(ebuf, ebuflen - 1,
+ "Can't load this .dll (machine code=0x%x) on a %s-bit platform",
+ lib_arch, running_arch_str);
}
JFR_ONLY(load_event.set_error_msg(ebuf);)
return nullptr;
@@ -1947,7 +1960,10 @@ void os::win32::print_windows_version(outputStream* st) {
// - 2016 GA 10/2016 build: 14393
// - 2019 GA 11/2018 build: 17763
// - 2022 GA 08/2021 build: 20348
- if (build_number > 20347) {
+ // - 2025 Preview build : 26040
+ if (build_number > 26039) {
+ st->print("Server 2025");
+ } else if (build_number > 20347) {
st->print("Server 2022");
} else if (build_number > 17762) {
st->print("Server 2019");
@@ -3123,7 +3139,7 @@ class NUMANodeListHolder {
static size_t _large_page_size = 0;
-static bool request_lock_memory_privilege() {
+bool os::win32::request_lock_memory_privilege() {
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,
os::current_process_id());
@@ -3307,14 +3323,14 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags,
return p_buf;
}
-static size_t large_page_init_decide_size() {
+size_t os::win32::large_page_init_decide_size() {
// print a warning if any large page related flag is specified on command line
bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) ||
!FLAG_IS_DEFAULT(LargePageSizeInBytes);
-#define WARN(msg) if (warn_on_failure) { warning(msg); }
+#define WARN(...) if (warn_on_failure) { warning(__VA_ARGS__); }
- if (!request_lock_memory_privilege()) {
+ if (!os::win32::request_lock_memory_privilege()) {
WARN("JVM cannot use large page memory because it does not have enough privilege to lock pages in memory.");
return 0;
}
@@ -3325,15 +3341,26 @@ static size_t large_page_init_decide_size() {
return 0;
}
-#if defined(IA32) || defined(AMD64)
- if (size > 4*M || LargePageSizeInBytes > 4*M) {
+#if defined(IA32)
+ if (size > 4 * M || LargePageSizeInBytes > 4 * M) {
WARN("JVM cannot use large pages bigger than 4mb.");
return 0;
}
+#elif defined(AMD64)
+ if (!EnableAllLargePageSizesForWindows) {
+ if (size > 4 * M || LargePageSizeInBytes > 4 * M) {
+ WARN("JVM cannot use large pages bigger than 4mb.");
+ return 0;
+ }
+ }
#endif
- if (LargePageSizeInBytes > 0 && LargePageSizeInBytes % size == 0) {
- size = LargePageSizeInBytes;
+ if (LargePageSizeInBytes > 0) {
+ if (LargePageSizeInBytes % size == 0) {
+ size = LargePageSizeInBytes;
+ } else {
+ WARN("The specified large page size (%d) is not a multiple of the minimum large page size (%d), defaulting to minimum page size.", LargePageSizeInBytes, size);
+ }
}
#undef WARN
@@ -3346,12 +3373,23 @@ void os::large_page_init() {
return;
}
- _large_page_size = large_page_init_decide_size();
+ _large_page_size = os::win32::large_page_init_decide_size();
const size_t default_page_size = os::vm_page_size();
if (_large_page_size > default_page_size) {
+#if !defined(IA32)
+ if (EnableAllLargePageSizesForWindows) {
+ size_t min_size = GetLargePageMinimum();
+
+ // Populate _page_sizes with large page sizes less than or equal to _large_page_size, ensuring each page size is double the size of the previous one.
+ for (size_t page_size = min_size; page_size < _large_page_size; page_size *= 2) {
+ _page_sizes.add(page_size);
+ }
+ }
+#endif
+
_page_sizes.add(_large_page_size);
}
-
+ // Set UseLargePages based on whether a large page size was successfully determined
UseLargePages = _large_page_size != 0;
}
@@ -3428,7 +3466,7 @@ char* os::replace_existing_mapping_with_file_mapping(char* base, size_t size, in
// Multiple threads can race in this code but it's not possible to unmap small sections of
// virtual space to get requested alignment, like posix-like os's.
// Windows prevents multiple thread from remapping over each other so this loop is thread-safe.
-static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc, MEMFLAGS flag = mtNone) {
+static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc, MemTag mem_tag = mtNone) {
assert(is_aligned(alignment, os::vm_allocation_granularity()),
"Alignment must be a multiple of allocation granularity (page size)");
assert(is_aligned(size, os::vm_allocation_granularity()),
@@ -3441,8 +3479,8 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi
static const int max_attempts = 20;
for (int attempt = 0; attempt < max_attempts && aligned_base == nullptr; attempt ++) {
- char* extra_base = file_desc != -1 ? os::map_memory_to_file(extra_size, file_desc, flag) :
- os::reserve_memory(extra_size, false, flag);
+ char* extra_base = file_desc != -1 ? os::map_memory_to_file(extra_size, file_desc, mem_tag) :
+ os::reserve_memory(extra_size, false, mem_tag);
if (extra_base == nullptr) {
return nullptr;
}
@@ -3458,11 +3496,12 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi
// Attempt to map, into the just vacated space, the slightly smaller aligned area.
// Which may fail, hence the loop.
- aligned_base = file_desc != -1 ? os::attempt_map_memory_to_file_at(aligned_base, size, file_desc, flag) :
- os::attempt_reserve_memory_at(aligned_base, size, false, flag);
+ aligned_base = file_desc != -1 ? os::attempt_map_memory_to_file_at(aligned_base, size, file_desc, mem_tag) :
+ os::attempt_reserve_memory_at(aligned_base, size, false, mem_tag);
}
- assert(aligned_base != nullptr, "Did not manage to re-map after %d attempts?", max_attempts);
+ assert(aligned_base != nullptr,
+ "Did not manage to re-map after %d attempts (size %zu, alignment %zu, file descriptor %d)", max_attempts, size, alignment, file_desc);
return aligned_base;
}
@@ -3472,8 +3511,8 @@ char* os::reserve_memory_aligned(size_t size, size_t alignment, bool exec) {
return map_or_reserve_memory_aligned(size, alignment, -1 /* file_desc */);
}
-char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int fd, MEMFLAGS flag) {
- return map_or_reserve_memory_aligned(size, alignment, fd, flag);
+char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int fd, MemTag mem_tag) {
+ return map_or_reserve_memory_aligned(size, alignment, fd, mem_tag);
}
char* os::pd_reserve_memory(size_t bytes, bool exec) {
@@ -3614,7 +3653,6 @@ static char* reserve_large_pages_aligned(size_t size, size_t alignment, bool exe
char* os::pd_reserve_memory_special(size_t bytes, size_t alignment, size_t page_size, char* addr,
bool exec) {
assert(UseLargePages, "only for large pages");
- assert(page_size == os::large_page_size(), "Currently only support one large page size on Windows");
assert(is_aligned(addr, alignment), "Must be");
assert(is_aligned(addr, page_size), "Must be");
@@ -3623,11 +3661,17 @@ char* os::pd_reserve_memory_special(size_t bytes, size_t alignment, size_t page_
return nullptr;
}
+ // Ensure GetLargePageMinimum() returns a valid positive value
+ size_t large_page_min = GetLargePageMinimum();
+ if (large_page_min <= 0) {
+ return nullptr;
+ }
+
// The requested alignment can be larger than the page size, for example with G1
// the alignment is bound to the heap region size. So this reservation needs to
// ensure that the requested alignment is met. When there is a requested address
// this solves it self, since it must be properly aligned already.
- if (addr == nullptr && alignment > page_size) {
+ if (addr == nullptr && alignment > large_page_min) {
return reserve_large_pages_aligned(bytes, alignment, exec);
}
@@ -4089,6 +4133,39 @@ int os::win32::_build_minor = 0;
bool os::win32::_processor_group_warning_displayed = false;
bool os::win32::_job_object_processor_group_warning_displayed = false;
+void getWindowsInstallationType(char* buffer, int bufferSize) {
+ HKEY hKey;
+ const char* subKey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
+ const char* valueName = "InstallationType";
+
+ DWORD valueLength = bufferSize;
+
+ // Initialize buffer with empty string
+ buffer[0] = '\0';
+
+ // Open the registry key
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
+ // Return empty buffer if key cannot be opened
+ return;
+ }
+
+ // Query the value
+ if (RegQueryValueExA(hKey, valueName, NULL, NULL, (LPBYTE)buffer, &valueLength) != ERROR_SUCCESS) {
+ RegCloseKey(hKey);
+ buffer[0] = '\0';
+ return;
+ }
+
+ RegCloseKey(hKey);
+}
+
+bool isNanoServer() {
+ const int BUFFER_SIZE = 256;
+ char installationType[BUFFER_SIZE];
+ getWindowsInstallationType(installationType, BUFFER_SIZE);
+ return (strcmp(installationType, "Nano Server") == 0);
+}
+
void os::win32::initialize_windows_version() {
assert(_major_version == 0, "windows version already initialized.");
@@ -4106,7 +4183,13 @@ void os::win32::initialize_windows_version() {
warning("Attempt to determine system directory failed: %s", buf_len != 0 ? error_msg_buffer : "");
return;
}
- strncat(kernel32_path, "\\kernel32.dll", MAX_PATH - ret);
+
+ if (isNanoServer()) {
+ // On Windows Nanoserver the kernel32.dll is located in the forwarders subdirectory
+ strncat(kernel32_path, "\\forwarders\\kernel32.dll", MAX_PATH - ret);
+ } else {
+ strncat(kernel32_path, "\\kernel32.dll", MAX_PATH - ret);
+ }
DWORD version_size = GetFileVersionInfoSize(kernel32_path, nullptr);
if (version_size == 0) {
@@ -5314,6 +5397,28 @@ void os::funlockfile(FILE* fp) {
_unlock_file(fp);
}
+char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) {
+
+ if (filename == nullptr || outbuf == nullptr || outbuflen < 1) {
+ assert(false, "os::realpath: invalid arguments.");
+ errno = EINVAL;
+ return nullptr;
+ }
+
+ char* result = nullptr;
+ ALLOW_C_FUNCTION(::_fullpath, char* p = ::_fullpath(nullptr, filename, 0);)
+ if (p != nullptr) {
+ if (strlen(p) < outbuflen) {
+ strcpy(outbuf, p);
+ result = outbuf;
+ } else {
+ errno = ENAMETOOLONG;
+ }
+ ALLOW_C_FUNCTION(::free, ::free(p);) // *not* os::free
+ }
+ return result;
+}
+
// Map a block of memory.
char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset,
char *addr, size_t bytes, bool read_only,
@@ -5648,7 +5753,15 @@ void PlatformEvent::park() {
// TODO: consider a brief spin here, gated on the success of recent
// spin attempts by this thread.
while (_Event < 0) {
+ // The following code is only here to maintain the
+ // characteristics/performance from when an ObjectMonitor
+ // "responsible" thread used to issue timed parks.
+ HighResolutionInterval *phri = nullptr;
+ if (!ForceTimeHighResolution) {
+ phri = new HighResolutionInterval((jlong)1);
+ }
DWORD rv = ::WaitForSingleObject(_ParkHandle, INFINITE);
+ delete phri; // if it is null, harmless
assert(rv != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError());
assert(rv == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", rv);
}
@@ -5740,11 +5853,23 @@ void Parker::unpark() {
SetEvent(_ParkHandle);
}
+// Platform Mutex/Monitor implementation
+
+PlatformMutex::PlatformMutex() {
+ InitializeCriticalSection(&_mutex);
+}
+
PlatformMutex::~PlatformMutex() {
DeleteCriticalSection(&_mutex);
}
-// Platform Monitor implementation
+PlatformMonitor::PlatformMonitor() {
+ InitializeConditionVariable(&_cond);
+}
+
+PlatformMonitor::~PlatformMonitor() {
+ // There is no DeleteConditionVariable API
+}
// Must already be locked
int PlatformMonitor::wait(uint64_t millis) {
@@ -5910,7 +6035,7 @@ static void do_resume(HANDLE* h) {
// retrieve a suspend/resume context capable handle
// from the tid. Caller validates handle return value.
void get_thread_handle_for_extended_context(HANDLE* h,
- OSThread::thread_id_t tid) {
+ DWORD tid) {
if (h != nullptr) {
*h = OpenThread(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, tid);
}
diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp
index 3bc5ab9eef1..1d523724300 100644
--- a/src/hotspot/os/windows/os_windows.hpp
+++ b/src/hotspot/os/windows/os_windows.hpp
@@ -65,6 +65,8 @@ class os::win32 {
static void setmode_streams();
static bool is_windows_11_or_greater();
static bool is_windows_server_2022_or_greater();
+ static bool request_lock_memory_privilege();
+ static size_t large_page_init_decide_size();
static int windows_major_version() {
assert(_major_version > 0, "windows version not initialized.");
return _major_version;
diff --git a/src/hotspot/os/windows/os_windows.inline.hpp b/src/hotspot/os/windows/os_windows.inline.hpp
index bb2da39d422..e9b30a33dfd 100644
--- a/src/hotspot/os/windows/os_windows.inline.hpp
+++ b/src/hotspot/os/windows/os_windows.inline.hpp
@@ -49,30 +49,23 @@ inline void os::map_stack_shadow_pages(address sp) {
// If we decrement stack pointer more than one page
// the OS may not map an intervening page into our space
// and may fault on a memory access to interior of our frame.
+ address original_sp = sp;
const size_t page_size = os::vm_page_size();
const size_t n_pages = StackOverflow::stack_shadow_zone_size() / page_size;
for (size_t pages = 1; pages <= n_pages; pages++) {
sp -= page_size;
*sp = 0;
}
+ StackOverflow* state = JavaThread::current()->stack_overflow_state();
+ assert(original_sp > state->shadow_zone_safe_limit(), "original_sp=" INTPTR_FORMAT ", "
+ "shadow_zone_safe_limit=" INTPTR_FORMAT, p2i(original_sp), p2i(state->shadow_zone_safe_limit()));
+ state->set_shadow_zone_growth_watermark(original_sp);
}
inline bool os::numa_has_group_homing() { return false; }
// Platform Mutex/Monitor implementation
-inline PlatformMutex::PlatformMutex() {
- InitializeCriticalSection(&_mutex);
-}
-
-inline PlatformMonitor::PlatformMonitor() {
- InitializeConditionVariable(&_cond);
-}
-
-inline PlatformMonitor::~PlatformMonitor() {
- // There is no DeleteConditionVariable API
-}
-
inline void PlatformMutex::lock() {
EnterCriticalSection(&_mutex);
}
diff --git a/src/hotspot/os/windows/perfMemory_windows.cpp b/src/hotspot/os/windows/perfMemory_windows.cpp
index a71101731fb..06b057315cb 100644
--- a/src/hotspot/os/windows/perfMemory_windows.cpp
+++ b/src/hotspot/os/windows/perfMemory_windows.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -165,7 +165,7 @@ static char* get_user_tmp_dir(const char* user) {
char* dirname = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
// construct the path name to user specific tmp directory
- _snprintf(dirname, nbytes, "%s\\%s_%s", tmpdir, perfdir, user);
+ os::snprintf(dirname, nbytes, "%s\\%s_%s", tmpdir, perfdir, user);
return dirname;
}
@@ -455,7 +455,7 @@ static char *get_sharedmem_objectname(const char* user, int vmid) {
//
nbytes += UINT_CHARS;
char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
- _snprintf(name, nbytes, "%s_%s_%u", PERFDATA_NAME, user, vmid);
+ os::snprintf(name, nbytes, "%s_%s_%u", PERFDATA_NAME, user, vmid);
return name;
}
@@ -471,7 +471,7 @@ static char* get_sharedmem_filename(const char* dirname, int vmid) {
size_t nbytes = strlen(dirname) + UINT_CHARS + 2;
char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
- _snprintf(name, nbytes, "%s\\%d", dirname, vmid);
+ os::snprintf(name, nbytes, "%s\\%d", dirname, vmid);
return name;
}
diff --git a/src/hotspot/os/windows/vmStructs_windows.hpp b/src/hotspot/os/windows/vmStructs_windows.hpp
index 2550e685f16..93f4ea7c811 100644
--- a/src/hotspot/os/windows/vmStructs_windows.hpp
+++ b/src/hotspot/os/windows/vmStructs_windows.hpp
@@ -29,9 +29,18 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-
-#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
+#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
+ \
+ /******************************/ \
+ /* Threads (NOTE: incomplete) */ \
+ /******************************/ \
+ \
+ nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
+ unchecked_nonstatic_field(OSThread, _thread_handle, sizeof(HANDLE)) /* NOTE: no type */
+
+#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
+ \
+ declare_unsigned_integer_type(OSThread::thread_id_t)
#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp b/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp
index 157d57f8e0f..123cd67248f 100644
--- a/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp
+++ b/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp
@@ -30,21 +30,9 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
- \
- /******************************/ \
- /* Threads (NOTE: incomplete) */ \
- /******************************/ \
- nonstatic_field(OSThread, _thread_id, pthread_t) \
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
- \
- /**********************/ \
- /* Posix Thread IDs */ \
- /**********************/ \
- \
- declare_unsigned_integer_type(pthread_t)
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp b/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp
index 07b878106cf..c384afac7ec 100644
--- a/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp
+++ b/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp
@@ -31,22 +31,9 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
- \
- /******************************/ \
- /* Threads (NOTE: incomplete) */ \
- /******************************/ \
- nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- nonstatic_field(OSThread, _unique_thread_id, uint64_t)
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
- \
- /**********************/ \
- /* Thread IDs */ \
- /**********************/ \
- \
- declare_unsigned_integer_type(OSThread::thread_id_t)
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp
index fb43541fa77..b48ea82712e 100644
--- a/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp
+++ b/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp
@@ -29,22 +29,9 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
- \
- /******************************/ \
- /* Threads (NOTE: incomplete) */ \
- /******************************/ \
- nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- nonstatic_field(OSThread, _unique_thread_id, uint64_t)
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
- \
- /**********************/ \
- /* Thread IDs */ \
- /**********************/ \
- \
- declare_unsigned_integer_type(OSThread::thread_id_t)
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S
index 2724e78862d..b3e7f643979 100644
--- a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S
+++ b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S
@@ -26,6 +26,7 @@
.align 5
DECLARE_FUNC(aarch64_atomic_fetch_add_8_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
ldaddal x1, x2, [x0]
#else
@@ -41,6 +42,7 @@ DECLARE_FUNC(aarch64_atomic_fetch_add_8_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_fetch_add_4_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
ldaddal w1, w2, [x0]
#else
@@ -56,8 +58,9 @@ DECLARE_FUNC(aarch64_atomic_fetch_add_4_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_fetch_add_8_relaxed_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
- ldadd x1, x2, [x0]
+ ldadd x1, x2, [x0]
#else
prfm pstl1strm, [x0]
0: ldxr x2, [x0]
@@ -70,8 +73,9 @@ DECLARE_FUNC(aarch64_atomic_fetch_add_8_relaxed_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_fetch_add_4_relaxed_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
- ldadd w1, w2, [x0]
+ ldadd w1, w2, [x0]
#else
prfm pstl1strm, [x0]
0: ldxr w2, [x0]
@@ -84,6 +88,7 @@ DECLARE_FUNC(aarch64_atomic_fetch_add_4_relaxed_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_xchg_4_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
swpal w1, w2, [x0]
#else
@@ -98,6 +103,7 @@ DECLARE_FUNC(aarch64_atomic_xchg_4_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_xchg_8_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
swpal x1, x2, [x0]
#else
@@ -112,6 +118,7 @@ DECLARE_FUNC(aarch64_atomic_xchg_8_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_1_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casalb w3, w2, [x0]
@@ -131,6 +138,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_1_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_4_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casal w3, w2, [x0]
@@ -149,6 +157,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_4_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_8_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casal x3, x2, [x0]
@@ -167,6 +176,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_8_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_4_release_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casl w3, w2, [x0]
@@ -183,6 +193,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_4_release_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_8_release_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casl x3, x2, [x0]
@@ -199,6 +210,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_8_release_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_4_seq_cst_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casal w3, w2, [x0]
@@ -215,6 +227,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_4_seq_cst_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_8_seq_cst_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casal x3, x2, [x0]
@@ -231,6 +244,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_8_seq_cst_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_1_relaxed_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casb w3, w2, [x0]
@@ -248,6 +262,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_1_relaxed_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_4_relaxed_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
cas w3, w2, [x0]
@@ -264,6 +279,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_4_relaxed_default_impl):
.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_8_relaxed_default_impl):
+ hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
cas x3, x2, [x0]
@@ -277,3 +293,35 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_8_relaxed_default_impl):
#endif
1: mov x0, x3
ret
+
+/* Emit .note.gnu.property section in case of PAC or BTI being enabled.
+ * For more details see "ELF for the Arm® 64-bit Architecture (AArch64)".
+ * https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst
+ */
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+ #ifdef __ARM_FEATURE_PAC_DEFAULT
+ #define GNU_PROPERTY_AARCH64_FEATURE 3
+ #else
+ #define GNU_PROPERTY_AARCH64_FEATURE 1
+ #endif
+#else
+ #ifdef __ARM_FEATURE_PAC_DEFAULT
+ #define GNU_PROPERTY_AARCH64_FEATURE 2
+ #else
+ #define GNU_PROPERTY_AARCH64_FEATURE 0
+ #endif
+#endif
+
+#if (GNU_PROPERTY_AARCH64_FEATURE != 0)
+ .pushsection .note.gnu.property, "a"
+ .align 3
+ .long 4 /* name length */
+ .long 0x10 /* data length */
+ .long 5 /* note type: NT_GNU_PROPERTY_TYPE_0 */
+ .string "GNU" /* vendor name */
+ .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
+ .long 4 /* pr_datasze */
+ .long GNU_PROPERTY_AARCH64_FEATURE
+ .long 0
+ .popsection
+#endif
diff --git a/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S
index f9702d5e554..33fe81d9206 100644
--- a/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S
+++ b/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S
@@ -83,29 +83,41 @@ fwd_copy_drain:
br t0
.align 5
- ret // -8 == 0 words
+ // -8 == 0 words
+ hint #0x24 // bti j
+ ret
.align 5
- ldr t0, [s, #16] // -7 == 1 word
+ // -7 == 1 word
+ hint #0x24 // bti j
+ ldr t0, [s, #16]
str t0, [d, #16]
ret
.align 5
- ldp t0, t1, [s, #16] // -6 = 2 words
+ // -6 == 2 words
+ hint #0x24 // bti j
+ ldp t0, t1, [s, #16]
stp t0, t1, [d, #16]
ret
.align 5
- ldp t0, t1, [s, #16] // -5 = 3 words
+ // -5 == 3 words
+ hint #0x24 // bti j
+ ldp t0, t1, [s, #16]
ldr t2, [s, #32]
stp t0, t1, [d, #16]
str t2, [d, #32]
ret
.align 5
- ldp t0, t1, [s, #16] // -4 = 4 words
+ // -4 == 4 words
+ hint #0x24 // bti j
+ ldp t0, t1, [s, #16]
ldp t2, t3, [s, #32]
stp t0, t1, [d, #16]
stp t2, t3, [d, #32]
ret
.align 5
- ldp t0, t1, [s, #16] // -3 = 5 words
+ // -3 == 5 words
+ hint #0x24 // bti j
+ ldp t0, t1, [s, #16]
ldp t2, t3, [s, #32]
ldr t4, [s, #48]
stp t0, t1, [d, #16]
@@ -113,7 +125,9 @@ fwd_copy_drain:
str t4, [d, #48]
ret
.align 5
- ldp t0, t1, [s, #16] // -2 = 6 words
+ // -2 == 6 words
+ hint #0x24 // bti j
+ ldp t0, t1, [s, #16]
ldp t2, t3, [s, #32]
ldp t4, t5, [s, #48]
stp t0, t1, [d, #16]
@@ -121,18 +135,20 @@ fwd_copy_drain:
stp t4, t5, [d, #48]
ret
.align 5
- ldp t0, t1, [s, #16] // -1 = 7 words
+ // -1 == 7 words
+ hint #0x24 // bti j
+ ldp t0, t1, [s, #16]
ldp t2, t3, [s, #32]
ldp t4, t5, [s, #48]
ldr t6, [s, #64]
stp t0, t1, [d, #16]
stp t2, t3, [d, #32]
stp t4, t5, [d, #48]
- str t6, [d, #64]
- // Is always aligned here, code for 7 words is one instruction
+ // Is always aligned here, code for 7 words is two instructions
// too large so it just falls through.
.align 5
0:
+ str t6, [d, #64]
ret
.align 6
@@ -184,29 +200,41 @@ bwd_copy_drain:
br t0
.align 5
- ret // -8 == 0 words
+ // -8 == 0 words
+ hint #0x24 // bti j
+ ret
.align 5
- ldr t0, [s, #-8] // -7 == 1 word
+ // -7 == 1 word
+ hint #0x24 // bti j
+ ldr t0, [s, #-8]
str t0, [d, #-8]
ret
.align 5
- ldp t0, t1, [s, #-16] // -6 = 2 words
+ // -6 == 2 words
+ hint #0x24 // bti j
+ ldp t0, t1, [s, #-16]
stp t0, t1, [d, #-16]
ret
.align 5
- ldp t0, t1, [s, #-16] // -5 = 3 words
+ // -5 == 3 words
+ hint #0x24 // bti j
+ ldp t0, t1, [s, #-16]
ldr t2, [s, #-24]
stp t0, t1, [d, #-16]
str t2, [d, #-24]
ret
.align 5
- ldp t0, t1, [s, #-16] // -4 = 4 words
+ // -4 == 4 words
+ hint #0x24 // bti j
+ ldp t0, t1, [s, #-16]
ldp t2, t3, [s, #-32]
stp t0, t1, [d, #-16]
stp t2, t3, [d, #-32]
ret
.align 5
- ldp t0, t1, [s, #-16] // -3 = 5 words
+ // -3 == 5 words
+ hint #0x24 // bti j
+ ldp t0, t1, [s, #-16]
ldp t2, t3, [s, #-32]
ldr t4, [s, #-40]
stp t0, t1, [d, #-16]
@@ -214,7 +242,9 @@ bwd_copy_drain:
str t4, [d, #-40]
ret
.align 5
- ldp t0, t1, [s, #-16] // -2 = 6 words
+ // -2 == 6 words
+ hint #0x24 // bti j
+ ldp t0, t1, [s, #-16]
ldp t2, t3, [s, #-32]
ldp t4, t5, [s, #-48]
stp t0, t1, [d, #-16]
@@ -222,16 +252,50 @@ bwd_copy_drain:
stp t4, t5, [d, #-48]
ret
.align 5
- ldp t0, t1, [s, #-16] // -1 = 7 words
+ // -1 == 7 words
+ hint #0x24 // bti j
+ ldp t0, t1, [s, #-16]
ldp t2, t3, [s, #-32]
ldp t4, t5, [s, #-48]
ldr t6, [s, #-56]
stp t0, t1, [d, #-16]
stp t2, t3, [d, #-32]
stp t4, t5, [d, #-48]
- str t6, [d, #-56]
- // Is always aligned here, code for 7 words is one instruction
+ // Is always aligned here, code for 7 words is two instructions
// too large so it just falls through.
.align 5
0:
+ str t6, [d, #-56]
ret
+
+/* Emit .note.gnu.property section in case of PAC or BTI being enabled.
+ * For more details see "ELF for the Arm® 64-bit Architecture (AArch64)".
+ * https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst
+ */
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+ #ifdef __ARM_FEATURE_PAC_DEFAULT
+ #define GNU_PROPERTY_AARCH64_FEATURE 3
+ #else
+ #define GNU_PROPERTY_AARCH64_FEATURE 1
+ #endif
+#else
+ #ifdef __ARM_FEATURE_PAC_DEFAULT
+ #define GNU_PROPERTY_AARCH64_FEATURE 2
+ #else
+ #define GNU_PROPERTY_AARCH64_FEATURE 0
+ #endif
+#endif
+
+#if (GNU_PROPERTY_AARCH64_FEATURE != 0)
+ .pushsection .note.gnu.property, "a"
+ .align 3
+ .long 4 /* name length */
+ .long 0x10 /* data length */
+ .long 5 /* note type: NT_GNU_PROPERTY_TYPE_0 */
+ .string "GNU" /* vendor name */
+ .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
+ .long 4 /* pr_datasze */
+ .long GNU_PROPERTY_AARCH64_FEATURE
+ .long 0
+ .popsection
+#endif
diff --git a/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S
index 82d989a9b88..a26aab44ac4 100644
--- a/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S
+++ b/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S
@@ -48,3 +48,35 @@ DECLARE_FUNC(_SafeFetchN_fault):
DECLARE_FUNC(_SafeFetchN_continuation):
mov x0, x1
ret
+
+/* Emit .note.gnu.property section in case of PAC or BTI being enabled.
+ * For more details see "ELF for the Arm® 64-bit Architecture (AArch64)".
+ * https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst
+ */
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+ #ifdef __ARM_FEATURE_PAC_DEFAULT
+ #define GNU_PROPERTY_AARCH64_FEATURE 3
+ #else
+ #define GNU_PROPERTY_AARCH64_FEATURE 1
+ #endif
+#else
+ #ifdef __ARM_FEATURE_PAC_DEFAULT
+ #define GNU_PROPERTY_AARCH64_FEATURE 2
+ #else
+ #define GNU_PROPERTY_AARCH64_FEATURE 0
+ #endif
+#endif
+
+#if (GNU_PROPERTY_AARCH64_FEATURE != 0)
+ .pushsection .note.gnu.property, "a"
+ .align 3
+ .long 4 /* name length */
+ .long 0x10 /* data length */
+ .long 5 /* note type: NT_GNU_PROPERTY_TYPE_0 */
+ .string "GNU" /* vendor name */
+ .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
+ .long 4 /* pr_datasze */
+ .long GNU_PROPERTY_AARCH64_FEATURE
+ .long 0
+ .popsection
+#endif
diff --git a/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S
index ca31585871d..55a252301d7 100644
--- a/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S
+++ b/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S
@@ -44,3 +44,35 @@ DECLARE_FUNC(_ZN10JavaThread25aarch64_get_thread_helperEv):
ret
.size _ZN10JavaThread25aarch64_get_thread_helperEv, .-_ZN10JavaThread25aarch64_get_thread_helperEv
+
+/* Emit .note.gnu.property section in case of PAC or BTI being enabled.
+ * For more details see "ELF for the Arm® 64-bit Architecture (AArch64)".
+ * https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst
+ */
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+ #ifdef __ARM_FEATURE_PAC_DEFAULT
+ #define GNU_PROPERTY_AARCH64_FEATURE 3
+ #else
+ #define GNU_PROPERTY_AARCH64_FEATURE 1
+ #endif
+#else
+ #ifdef __ARM_FEATURE_PAC_DEFAULT
+ #define GNU_PROPERTY_AARCH64_FEATURE 2
+ #else
+ #define GNU_PROPERTY_AARCH64_FEATURE 0
+ #endif
+#endif
+
+#if (GNU_PROPERTY_AARCH64_FEATURE != 0)
+ .pushsection .note.gnu.property, "a"
+ .align 3
+ .long 4 /* name length */
+ .long 0x10 /* data length */
+ .long 5 /* note type: NT_GNU_PROPERTY_TYPE_0 */
+ .string "GNU" /* vendor name */
+ .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
+ .long 4 /* pr_datasze */
+ .long GNU_PROPERTY_AARCH64_FEATURE
+ .long 0
+ .popsection
+#endif
diff --git a/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp
index f2ad002996b..3c8e9c44414 100644
--- a/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp
+++ b/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp
@@ -30,23 +30,9 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
- \
- /******************************/ \
- /* Threads (NOTE: incomplete) */ \
- /******************************/ \
- nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- nonstatic_field(OSThread, _pthread_id, pthread_t)
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
- \
- /**********************/ \
- /* Posix Thread IDs */ \
- /**********************/ \
- \
- declare_integer_type(OSThread::thread_id_t) \
- declare_unsigned_integer_type(pthread_t)
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp b/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp
index 9b4bd0faf0a..120726bf55f 100644
--- a/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp
+++ b/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp
@@ -29,22 +29,9 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
- \
- /******************************/ \
- /* Threads (NOTE: incomplete) */ \
- /******************************/ \
- nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- nonstatic_field(OSThread, _pthread_id, pthread_t)
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
- \
- /**********************/ \
- /* Posix Thread IDs */ \
- /**********************/ \
- \
- declare_integer_type(OSThread::thread_id_t) \
- declare_unsigned_integer_type(pthread_t)
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp b/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp
index 9464c359770..ae948c73031 100644
--- a/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp
+++ b/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp
@@ -30,23 +30,9 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
- \
- /******************************/ \
- /* Threads (NOTE: incomplete) */ \
- /******************************/ \
- nonstatic_field(OSThread, _thread_id, pid_t) \
- nonstatic_field(OSThread, _pthread_id, pthread_t)
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
- \
- /**********************/ \
- /* Posix Thread IDs */ \
- /**********************/ \
- \
- declare_integer_type(pid_t) \
- declare_unsigned_integer_type(pthread_t)
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp
index a7dc84770f8..368d6c971fa 100644
--- a/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp
+++ b/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp
@@ -54,6 +54,24 @@ inline void OrderAccess::fence() {
}
inline void OrderAccess::cross_modify_fence_impl() {
+ // From 3 “Zifencei” Instruction-Fetch Fence, Version 2.0
+ // "RISC-V does not guarantee that stores to instruction memory will be made
+ // visible to instruction fetches on a RISC-V hart until that hart executes a
+ // FENCE.I instruction. A FENCE.I instruction ensures that a subsequent
+ // instruction fetch on a RISC-V hart will see any previous data stores
+ // already visible to the same RISC-V hart. FENCE.I does not ensure that other
+ // RISC-V harts’ instruction fetches will observe the local hart’s stores in a
+ // multiprocessor system."
+ //
+ // Hence to be able to use fence.i directly we need a kernel that supports
+ // PR_RISCV_CTX_SW_FENCEI_ON. Thus if context switch to another hart we are
+ // ensured that instruction fetch will see any previous data stores
+ //
+ // The alternative is using full system IPI (system wide icache sync) then
+ // this barrier is not strictly needed. As this is emitted in runtime slow-path
+ // we will just always emit it, typically after a safepoint.
+ guarantee(VM_Version::supports_fencei_barrier(), "Linux kernel require fence.i");
+ __asm__ volatile("fence.i" : : : "memory");
}
#endif // OS_CPU_LINUX_RISCV_ORDERACCESS_LINUX_RISCV_HPP
diff --git a/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp
index 6cf7683a586..3946394c19b 100644
--- a/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp
+++ b/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp
@@ -30,23 +30,9 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
- \
- /******************************/ \
- /* Threads (NOTE: incomplete) */ \
- /******************************/ \
- nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- nonstatic_field(OSThread, _pthread_id, pthread_t)
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
- \
- /**********************/ \
- /* Posix Thread IDs */ \
- /**********************/ \
- \
- declare_integer_type(OSThread::thread_id_t) \
- declare_unsigned_integer_type(pthread_t)
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp
index 3f9f26b525b..a3a226502f6 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
@@ -35,6 +35,7 @@
#include
#include
#include
+#include
#ifndef HWCAP_ISA_I
#define HWCAP_ISA_I nth_bit('I' - 'A')
@@ -82,6 +83,23 @@
__v; \
})
+// prctl PR_RISCV_SET_ICACHE_FLUSH_CTX is from Linux 6.9
+#ifndef PR_RISCV_SET_ICACHE_FLUSH_CTX
+#define PR_RISCV_SET_ICACHE_FLUSH_CTX 71
+#endif
+#ifndef PR_RISCV_CTX_SW_FENCEI_ON
+#define PR_RISCV_CTX_SW_FENCEI_ON 0
+#endif
+#ifndef PR_RISCV_CTX_SW_FENCEI_OFF
+#define PR_RISCV_CTX_SW_FENCEI_OFF 1
+#endif
+#ifndef PR_RISCV_SCOPE_PER_PROCESS
+#define PR_RISCV_SCOPE_PER_PROCESS 0
+#endif
+#ifndef PR_RISCV_SCOPE_PER_THREAD
+#define PR_RISCV_SCOPE_PER_THREAD 1
+#endif
+
uint32_t VM_Version::cpu_vector_length() {
assert(ext_V.enabled(), "should not call this");
return (uint32_t)read_csr(CSR_VLENB);
@@ -102,6 +120,7 @@ void VM_Version::setup_cpu_available_features() {
if (!RiscvHwprobe::probe_features()) {
os_aux_features();
}
+
char* uarch = os_uarch_additional_features();
vendor_features();
@@ -155,6 +174,24 @@ void VM_Version::setup_cpu_available_features() {
i++;
}
+ // Linux kernel require Zifencei
+ if (!ext_Zifencei.enabled()) {
+ log_info(os, cpu)("Zifencei not found, required by Linux, enabling.");
+ ext_Zifencei.enable_feature();
+ }
+
+ if (UseCtxFencei) {
+ // Note that we can set this up only for effected threads
+ // via PR_RISCV_SCOPE_PER_THREAD, i.e. on VM attach/deattach.
+ int ret = prctl(PR_RISCV_SET_ICACHE_FLUSH_CTX, PR_RISCV_CTX_SW_FENCEI_ON, PR_RISCV_SCOPE_PER_PROCESS);
+ if (ret == 0) {
+ log_debug(os, cpu)("UseCtxFencei (PR_RISCV_CTX_SW_FENCEI_ON) enabled.");
+ } else {
+ FLAG_SET_ERGO(UseCtxFencei, false);
+ log_info(os, cpu)("UseCtxFencei (PR_RISCV_CTX_SW_FENCEI_ON) disabled, unsupported by kernel.");
+ }
+ }
+
_features_string = os::strdup(buf);
}
diff --git a/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp b/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp
index 0442510fa24..a0fb5eb1a6a 100644
--- a/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp
+++ b/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp
@@ -30,23 +30,9 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
- \
- /******************************/ \
- /* Threads (NOTE: incomplete) */ \
- /******************************/ \
- nonstatic_field(OSThread, _thread_id, pid_t) \
- nonstatic_field(OSThread, _pthread_id, pthread_t)
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
- \
- /**********************/ \
- /* Posix Thread IDs */ \
- /**********************/ \
- \
- declare_integer_type(pid_t) \
- declare_unsigned_integer_type(pthread_t)
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp
index 78988dd4fd0..0d5d07fc8a8 100644
--- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp
+++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp
@@ -224,7 +224,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
if (info != nullptr && uc != nullptr && thread != nullptr) {
pc = (address) os::Posix::ucontext_get_pc(uc);
- if (sig == SIGSEGV && info->si_addr == 0 && info->si_code == SI_KERNEL) {
+ if (sig == SIGSEGV && info->si_addr == nullptr && info->si_code == SI_KERNEL) {
// An irrecoverable SI_KERNEL SIGSEGV has occurred.
// It's likely caused by dereferencing an address larger than TASK_SIZE.
return false;
diff --git a/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp
index 277486549c0..8f6d3657237 100644
--- a/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp
+++ b/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp
@@ -29,23 +29,9 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
- \
- /******************************/ \
- /* Threads (NOTE: incomplete) */ \
- /******************************/ \
- nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- nonstatic_field(OSThread, _pthread_id, pthread_t)
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
- \
- /**********************/ \
- /* Posix Thread IDs */ \
- /**********************/ \
- \
- declare_integer_type(OSThread::thread_id_t) \
- declare_unsigned_integer_type(pthread_t)
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp b/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp
index ce2ad2d046f..96a34fe967b 100644
--- a/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp
+++ b/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp
@@ -26,8 +26,27 @@
#ifndef OS_CPU_WINDOWS_AARCH64_COPY_WINDOWS_AARCH64_HPP
#define OS_CPU_WINDOWS_AARCH64_COPY_WINDOWS_AARCH64_HPP
+#include "runtime/atomic.hpp"
+
#include
+template
+static void pd_conjoint_atomic_helper(const T* from, T* to, size_t count) {
+ if (from > to) {
+ while (count-- > 0) {
+ // Copy forwards
+ Atomic::store(to++, Atomic::load(from++));
+ }
+ } else {
+ from += count - 1;
+ to += count - 1;
+ while (count-- > 0) {
+ // Copy backwards
+ Atomic::store(to--, Atomic::load(from--));
+ }
+ }
+}
+
static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) {
(void)memmove(to, from, count * HeapWordSize);
}
@@ -71,55 +90,19 @@ static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) {
}
static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) {
- if (from > to) {
- while (count-- > 0) {
- // Copy forwards
- *to++ = *from++;
- }
- } else {
- from += count - 1;
- to += count - 1;
- while (count-- > 0) {
- // Copy backwards
- *to-- = *from--;
- }
- }
+ pd_conjoint_atomic_helper(from, to, count);
}
static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) {
- if (from > to) {
- while (count-- > 0) {
- // Copy forwards
- *to++ = *from++;
- }
- } else {
- from += count - 1;
- to += count - 1;
- while (count-- > 0) {
- // Copy backwards
- *to-- = *from--;
- }
- }
+ pd_conjoint_atomic_helper(from, to, count);
}
static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) {
- pd_conjoint_oops_atomic((const oop*)from, (oop*)to, count);
+ pd_conjoint_atomic_helper(from, to, count);
}
static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) {
- if (from > to) {
- while (count-- > 0) {
- // Copy forwards
- *to++ = *from++;
- }
- } else {
- from += count - 1;
- to += count - 1;
- while (count-- > 0) {
- // Copy backwards
- *to-- = *from--;
- }
- }
+ pd_conjoint_atomic_helper(from, to, count);
}
static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) {
diff --git a/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp b/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp
index 220787823dc..18a5588b743 100644
--- a/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp
+++ b/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp
@@ -29,18 +29,9 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
- \
- /******************************/ \
- /* Threads (NOTE: incomplete) */ \
- /******************************/ \
- \
- nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- unchecked_nonstatic_field(OSThread, _thread_handle, sizeof(HANDLE)) /* NOTE: no type */
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
- \
- declare_unsigned_integer_type(OSThread::thread_id_t)
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp
index 7e0814c014b..62022d780a2 100644
--- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp
+++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.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
@@ -180,7 +180,7 @@ bool os::win32::register_code_area(char *low, char *high) {
MacroAssembler* masm = new MacroAssembler(&cb);
pDCD = (pDynamicCodeData) masm->pc();
- masm->jump(ExternalAddress((address)&HandleExceptionFromCodeCache), rscratch1);
+ masm->jump(RuntimeAddress((address)&HandleExceptionFromCodeCache), rscratch1);
masm->flush();
// Create an Unwind Structure specifying no unwind info
diff --git a/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp b/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp
index 9f50a7ed9ae..985a6a331da 100644
--- a/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp
+++ b/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp
@@ -29,18 +29,9 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
- \
- /******************************/ \
- /* Threads (NOTE: incomplete) */ \
- /******************************/ \
- \
- nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- unchecked_nonstatic_field(OSThread, _thread_handle, sizeof(HANDLE)) /* NOTE: no type */
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
- \
- declare_unsigned_integer_type(OSThread::thread_id_t)
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
diff --git a/src/hotspot/share/adlc/adlArena.cpp b/src/hotspot/share/adlc/adlArena.cpp
index d29a255a905..ebd1f74911d 100644
--- a/src/hotspot/share/adlc/adlArena.cpp
+++ b/src/hotspot/share/adlc/adlArena.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,7 @@ void* AdlReAllocateHeap(void* old_ptr, size_t size) {
}
void* AdlChunk::operator new(size_t requested_size, size_t length) throw() {
+ assert(requested_size <= SIZE_MAX - length, "overflow");
return AdlCHeapObj::operator new(requested_size + length);
}
@@ -62,8 +63,6 @@ void AdlChunk::chop() {
AdlChunk *k = this;
while( k ) {
AdlChunk *tmp = k->_next;
- // clear out this chunk (to detect allocation bugs)
- memset(k, 0xBE, k->_len);
free(k); // Free chunk (was malloc'd)
k = tmp;
}
@@ -129,6 +128,7 @@ void* AdlArena::grow( size_t x ) {
//------------------------------calloc-----------------------------------------
// Allocate zeroed storage in AdlArena
void *AdlArena::Acalloc( size_t items, size_t x ) {
+ assert(items <= SIZE_MAX / x, "overflow");
size_t z = items*x; // Total size needed
void *ptr = Amalloc(z); // Get space
memset( ptr, 0, z ); // Zap space
@@ -136,21 +136,26 @@ void *AdlArena::Acalloc( size_t items, size_t x ) {
}
//------------------------------realloc----------------------------------------
+static size_t pointer_delta(const void *left, const void *right) {
+ assert(left >= right, "pointer delta underflow");
+ return (uintptr_t)left - (uintptr_t)right;
+}
+
// Reallocate storage in AdlArena.
void *AdlArena::Arealloc( void *old_ptr, size_t old_size, size_t new_size ) {
char *c_old = (char*)old_ptr; // Handy name
- // Stupid fast special case
- if( new_size <= old_size ) { // Shrink in-place
- if( c_old+old_size == _hwm) // Attempt to free the excess bytes
- _hwm = c_old+new_size; // Adjust hwm
- return c_old;
- }
- // See if we can resize in-place
- if( (c_old+old_size == _hwm) && // Adjusting recent thing
- (c_old+new_size <= _max) ) { // Still fits where it sits
- _hwm = c_old+new_size; // Adjust hwm
- return c_old; // Return old pointer
+ // Reallocating the latest allocation?
+ if (c_old + old_size == _hwm) {
+ assert(_chunk->bottom() <= c_old, "invariant");
+
+ // Reallocate in place if it fits. Also handles shrinking
+ if (pointer_delta(_max, c_old) >= new_size) {
+ _hwm = c_old + new_size;
+ return c_old;
+ }
+ } else if (new_size <= old_size) { // Shrink in place
+ return c_old;
}
// Oops, got to relocate guts
diff --git a/src/hotspot/share/adlc/adlArena.hpp b/src/hotspot/share/adlc/adlArena.hpp
index 254f414f707..2e8d8ae8ae2 100644
--- a/src/hotspot/share/adlc/adlArena.hpp
+++ b/src/hotspot/share/adlc/adlArena.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -105,8 +105,10 @@ class AdlArena: public AdlCHeapObj {
// Fast allocate in the arena. Common case is: pointer test + increment.
void* Amalloc(size_t x) {
#ifdef _LP64
+ assert(x <= SIZE_MAX - (8-1), "overflow");
x = (x + (8-1)) & ((unsigned)(-8));
#else
+ assert(x <= SIZE_MAX - (4-1), "overflow");
x = (x + (4-1)) & ((unsigned)(-4));
#endif
if (_hwm + x > _max) {
diff --git a/src/hotspot/share/adlc/forms.cpp b/src/hotspot/share/adlc/forms.cpp
index 068d745254e..c34a73ea1e1 100644
--- a/src/hotspot/share/adlc/forms.cpp
+++ b/src/hotspot/share/adlc/forms.cpp
@@ -276,7 +276,6 @@ Form::DataType Form::is_load_from_memory(const char *opType) const {
Form::DataType Form::is_store_to_memory(const char *opType) const {
if( strcmp(opType,"StoreB")==0) return Form::idealB;
- if( strcmp(opType,"StoreCM")==0) return Form::idealB;
if( strcmp(opType,"StoreC")==0) return Form::idealC;
if( strcmp(opType,"StoreD")==0) return Form::idealD;
if( strcmp(opType,"StoreF")==0) return Form::idealF;
diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp
index be97547f8ce..e7dd00fa390 100644
--- a/src/hotspot/share/adlc/formssel.cpp
+++ b/src/hotspot/share/adlc/formssel.cpp
@@ -210,15 +210,16 @@ bool InstructForm::is_pinned(FormDict &globals) {
if ( ! _matrule) return false;
int index = 0;
- if (_matrule->find_type("Goto", index)) return true;
- if (_matrule->find_type("If", index)) return true;
- if (_matrule->find_type("CountedLoopEnd",index)) return true;
- if (_matrule->find_type("Return", index)) return true;
- if (_matrule->find_type("Rethrow", index)) return true;
- if (_matrule->find_type("TailCall", index)) return true;
- if (_matrule->find_type("TailJump", index)) return true;
- if (_matrule->find_type("Halt", index)) return true;
- if (_matrule->find_type("Jump", index)) return true;
+ if (_matrule->find_type("Goto", index)) return true;
+ if (_matrule->find_type("If", index)) return true;
+ if (_matrule->find_type("CountedLoopEnd", index)) return true;
+ if (_matrule->find_type("Return", index)) return true;
+ if (_matrule->find_type("Rethrow", index)) return true;
+ if (_matrule->find_type("TailCall", index)) return true;
+ if (_matrule->find_type("TailJump", index)) return true;
+ if (_matrule->find_type("ForwardException", index)) return true;
+ if (_matrule->find_type("Halt", index)) return true;
+ if (_matrule->find_type("Jump", index)) return true;
return is_parm(globals);
}
@@ -228,12 +229,13 @@ bool InstructForm::is_projection(FormDict &globals) {
if ( ! _matrule) return false;
int index = 0;
- if (_matrule->find_type("Goto", index)) return true;
- if (_matrule->find_type("Return", index)) return true;
- if (_matrule->find_type("Rethrow", index)) return true;
- if (_matrule->find_type("TailCall",index)) return true;
- if (_matrule->find_type("TailJump",index)) return true;
- if (_matrule->find_type("Halt", index)) return true;
+ if (_matrule->find_type("Goto", index)) return true;
+ if (_matrule->find_type("Return", index)) return true;
+ if (_matrule->find_type("Rethrow", index)) return true;
+ if (_matrule->find_type("TailCall", index)) return true;
+ if (_matrule->find_type("TailJump", index)) return true;
+ if (_matrule->find_type("ForwardException", index)) return true;
+ if (_matrule->find_type("Halt", index)) return true;
return false;
}
@@ -376,6 +378,7 @@ bool InstructForm::is_ideal_return() const {
if (_matrule->find_type("Rethrow",index)) return true;
if (_matrule->find_type("TailCall",index)) return true;
if (_matrule->find_type("TailJump",index)) return true;
+ if (_matrule->find_type("ForwardException", index)) return true;
return false;
}
@@ -894,6 +897,7 @@ uint InstructForm::oper_input_base(FormDict &globals) {
strcmp(_matrule->_opType,"Rethrow" )==0 ||
strcmp(_matrule->_opType,"TailCall" )==0 ||
strcmp(_matrule->_opType,"TailJump" )==0 ||
+ strcmp(_matrule->_opType,"ForwardException")==0 ||
strcmp(_matrule->_opType,"SafePoint" )==0 ||
strcmp(_matrule->_opType,"Halt" )==0 )
return AdlcVMDeps::Parms; // Skip the machine-state edges
@@ -3650,7 +3654,6 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const {
#if INCLUDE_SHENANDOAHGC
"ShenandoahCompareAndSwapN", "ShenandoahCompareAndSwapP", "ShenandoahWeakCompareAndSwapP", "ShenandoahWeakCompareAndSwapN", "ShenandoahCompareAndExchangeP", "ShenandoahCompareAndExchangeN",
#endif
- "StoreCM",
"GetAndSetB", "GetAndSetS", "GetAndAddI", "GetAndSetI", "GetAndSetP",
"GetAndAddB", "GetAndAddS", "GetAndAddL", "GetAndSetL", "GetAndSetN",
"ClearArray"
@@ -4352,8 +4355,8 @@ bool MatchRule::is_vector() const {
"Replicate","ReverseV","ReverseBytesV",
"RoundDoubleModeV","RotateLeftV" , "RotateRightV", "LoadVector","StoreVector",
"LoadVectorGather", "StoreVectorScatter", "LoadVectorGatherMasked", "StoreVectorScatterMasked",
- "VectorTest", "VectorLoadMask", "VectorStoreMask", "VectorBlend", "VectorInsert",
- "VectorRearrange","VectorLoadShuffle", "VectorLoadConst",
+ "SelectFromTwoVector", "VectorTest", "VectorLoadMask", "VectorStoreMask", "VectorBlend", "VectorInsert",
+ "VectorRearrange", "VectorLoadShuffle", "VectorLoadConst",
"VectorCastB2X", "VectorCastS2X", "VectorCastI2X",
"VectorCastL2X", "VectorCastF2X", "VectorCastD2X", "VectorCastF2HF", "VectorCastHF2F",
"VectorUCastB2X", "VectorUCastS2X", "VectorUCastI2X",
diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp
index ea47e435c0b..b25e07bc36d 100644
--- a/src/hotspot/share/asm/codeBuffer.cpp
+++ b/src/hotspot/share/asm/codeBuffer.cpp
@@ -135,10 +135,11 @@ CodeBuffer::~CodeBuffer() {
// Previous incarnations of this buffer are held live, so that internal
// addresses constructed before expansions will not be confused.
cb->free_blob();
+ }
+ if (_overflow_arena != nullptr) {
// free any overflow storage
- delete cb->_overflow_arena;
+ delete _overflow_arena;
}
-
if (_shared_trampoline_requests != nullptr) {
delete _shared_trampoline_requests;
}
@@ -973,8 +974,6 @@ void CodeBuffer::take_over_code_from(CodeBuffer* cb) {
CodeSection* this_sect = code_section(n);
this_sect->take_over_code_from(cb_sect);
}
- _overflow_arena = cb->_overflow_arena;
- cb->_overflow_arena = nullptr;
// Make sure the old cb won't try to use it or free it.
DEBUG_ONLY(cb->_blob = (BufferBlob*)badAddress);
}
diff --git a/src/hotspot/share/asm/register.hpp b/src/hotspot/share/asm/register.hpp
index 7dfc9b03f87..6078edecb4a 100644
--- a/src/hotspot/share/asm/register.hpp
+++ b/src/hotspot/share/asm/register.hpp
@@ -276,19 +276,23 @@ inline constexpr bool different_registers(R first_register, Rx... more_registers
}
template
-inline void assert_different_registers(R first_register, Rx... more_registers) {
+inline void assert_different_registers_impl(const char* file, int line, R first_register, Rx... more_registers) {
#ifdef ASSERT
if (!different_registers(first_register, more_registers...)) {
const R regs[] = { first_register, more_registers... };
// Find a duplicate entry.
for (size_t i = 0; i < ARRAY_SIZE(regs) - 1; ++i) {
for (size_t j = i + 1; j < ARRAY_SIZE(regs); ++j) {
- assert(!regs[i]->is_valid() || regs[i] != regs[j],
- "Multiple uses of register: %s", regs[i]->name());
+ if (regs[i]->is_valid()) {
+ assert_with_file_and_line(regs[i] != regs[j], file, line, "regs[%zu] and regs[%zu] are both: %s",
+ i, j, regs[i]->name());
+ }
}
}
}
#endif
}
+#define assert_different_registers(...) assert_different_registers_impl(__FILE__, __LINE__, __VA_ARGS__)
+
#endif // SHARE_ASM_REGISTER_HPP
diff --git a/src/hotspot/share/c1/c1_CodeStubs.hpp b/src/hotspot/share/c1/c1_CodeStubs.hpp
index 04e379842e1..9abfa45785b 100644
--- a/src/hotspot/share/c1/c1_CodeStubs.hpp
+++ b/src/hotspot/share/c1/c1_CodeStubs.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -264,10 +264,10 @@ class NewInstanceStub: public CodeStub {
LIR_Opr _klass_reg;
LIR_Opr _result;
CodeEmitInfo* _info;
- Runtime1::StubID _stub_id;
+ C1StubId _stub_id;
public:
- NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id);
+ NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, C1StubId stub_id);
virtual void emit_code(LIR_Assembler* e);
virtual CodeEmitInfo* info() const { return _info; }
virtual void visit(LIR_OpVisitState* visitor) {
@@ -515,11 +515,11 @@ class DeoptimizeStub : public CodeStub {
class SimpleExceptionStub: public CodeStub {
private:
LIR_Opr _obj;
- Runtime1::StubID _stub;
+ C1StubId _stub;
CodeEmitInfo* _info;
public:
- SimpleExceptionStub(Runtime1::StubID stub, LIR_Opr obj, CodeEmitInfo* info):
+ SimpleExceptionStub(C1StubId stub, LIR_Opr obj, CodeEmitInfo* info):
_obj(obj), _stub(stub), _info(info) {
FrameMap* f = Compilation::current()->frame_map();
f->update_reserved_argument_area_size(2 * BytesPerWord);
@@ -546,7 +546,7 @@ class SimpleExceptionStub: public CodeStub {
class ArrayStoreExceptionStub: public SimpleExceptionStub {
public:
- ArrayStoreExceptionStub(LIR_Opr obj, CodeEmitInfo* info): SimpleExceptionStub(Runtime1::throw_array_store_exception_id, obj, info) {}
+ ArrayStoreExceptionStub(LIR_Opr obj, CodeEmitInfo* info): SimpleExceptionStub(C1StubId::throw_array_store_exception_id, obj, info) {}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("ArrayStoreExceptionStub"); }
#endif // PRODUCT
diff --git a/src/hotspot/share/c1/c1_Compilation.cpp b/src/hotspot/share/c1/c1_Compilation.cpp
index 48201a86053..7e0d439aff4 100644
--- a/src/hotspot/share/c1/c1_Compilation.cpp
+++ b/src/hotspot/share/c1/c1_Compilation.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
@@ -274,8 +274,6 @@ void Compilation::emit_lir() {
// Assign physical registers to LIR operands using a linear scan algorithm.
allocator->do_linear_scan();
CHECK_BAILOUT();
-
- _max_spills = allocator->max_spills();
}
if (BailoutAfterLIR) {
@@ -568,7 +566,6 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho
, _method(method)
, _osr_bci(osr_bci)
, _hir(nullptr)
-, _max_spills(-1)
, _frame_map(nullptr)
, _masm(nullptr)
, _has_exception_handlers(false)
diff --git a/src/hotspot/share/c1/c1_Compilation.hpp b/src/hotspot/share/c1/c1_Compilation.hpp
index d55a8debca7..0ac0a4d4169 100644
--- a/src/hotspot/share/c1/c1_Compilation.hpp
+++ b/src/hotspot/share/c1/c1_Compilation.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -73,7 +73,6 @@ class Compilation: public StackObj {
ciMethod* _method;
int _osr_bci;
IR* _hir;
- int _max_spills;
FrameMap* _frame_map;
C1_MacroAssembler* _masm;
bool _has_exception_handlers;
@@ -151,7 +150,6 @@ class Compilation: public StackObj {
int osr_bci() const { return _osr_bci; }
bool is_osr_compile() const { return osr_bci() >= 0; }
IR* hir() const { return _hir; }
- int max_spills() const { return _max_spills; }
FrameMap* frame_map() const { return _frame_map; }
CodeBuffer* code() { return &_code; }
C1_MacroAssembler* masm() const { return _masm; }
diff --git a/src/hotspot/share/c1/c1_Compiler.cpp b/src/hotspot/share/c1/c1_Compiler.cpp
index e1c4e90d063..a0944c864e6 100644
--- a/src/hotspot/share/c1/c1_Compiler.cpp
+++ b/src/hotspot/share/c1/c1_Compiler.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
@@ -167,6 +167,9 @@ bool Compiler::is_intrinsic_supported(vmIntrinsics::ID id) {
case vmIntrinsics::_dsin:
case vmIntrinsics::_dcos:
case vmIntrinsics::_dtan:
+ #if defined(AMD64)
+ case vmIntrinsics::_dtanh:
+ #endif
case vmIntrinsics::_dlog:
case vmIntrinsics::_dlog10:
case vmIntrinsics::_dexp:
diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp
index 0493b0458cd..02be6f8d49e 100644
--- a/src/hotspot/share/c1/c1_GraphBuilder.cpp
+++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp
@@ -1389,6 +1389,11 @@ void GraphBuilder::jsr(int dest) {
// If the bytecodes are strange (jumping out of a jsr block) then we
// might end up trying to re-parse a block containing a jsr which
// has already been activated. Watch for this case and bail out.
+ if (next_bci() >= method()->code_size()) {
+ // This can happen if the subroutine does not terminate with a ret,
+ // effectively turning the jsr into a goto.
+ BAILOUT("too-complicated jsr/ret structure");
+ }
for (ScopeData* cur_scope_data = scope_data();
cur_scope_data != nullptr && cur_scope_data->parsing_jsr() && cur_scope_data->scope() == scope();
cur_scope_data = cur_scope_data->parent()) {
@@ -1563,7 +1568,7 @@ void GraphBuilder::method_return(Value x, bool ignore_return) {
// The conditions for a memory barrier are described in Parse::do_exits().
bool need_mem_bar = false;
if (method()->name() == ciSymbols::object_initializer_name() &&
- (scope()->wrote_final() ||
+ (scope()->wrote_final() || scope()->wrote_stable() ||
(AlwaysSafeConstructors && scope()->wrote_fields()) ||
(support_IRIW_for_not_multiple_copy_atomic_cpu && scope()->wrote_volatile()))) {
need_mem_bar = true;
@@ -1741,15 +1746,17 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
}
}
- if (field->is_final() && (code == Bytecodes::_putfield)) {
- scope()->set_wrote_final();
- }
-
if (code == Bytecodes::_putfield) {
scope()->set_wrote_fields();
if (field->is_volatile()) {
scope()->set_wrote_volatile();
}
+ if (field->is_final()) {
+ scope()->set_wrote_final();
+ }
+ if (field->is_stable()) {
+ scope()->set_wrote_stable();
+ }
}
const int offset = !needs_patching ? field->offset_in_bytes() : -1;
@@ -2114,7 +2121,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
}
if (cha_monomorphic_target != nullptr) {
- assert(!target->can_be_statically_bound() || target == cha_monomorphic_target, "");
+ assert(!target->can_be_statically_bound() || target->equals(cha_monomorphic_target), "");
assert(!cha_monomorphic_target->is_abstract(), "");
if (!cha_monomorphic_target->can_be_statically_bound(actual_recv)) {
// If we inlined because CHA revealed only a single target method,
@@ -3332,6 +3339,7 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope)
case vmIntrinsics::_dsin : // fall through
case vmIntrinsics::_dcos : // fall through
case vmIntrinsics::_dtan : // fall through
+ case vmIntrinsics::_dtanh : // fall through
case vmIntrinsics::_dlog : // fall through
case vmIntrinsics::_dlog10 : // fall through
case vmIntrinsics::_dexp : // fall through
@@ -3734,6 +3742,9 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee, bool ignore_return) {
bool GraphBuilder::try_inline_jsr(int jsr_dest_bci) {
// Introduce a new callee continuation point - all Ret instructions
// will be replaced with Gotos to this point.
+ if (next_bci() >= method()->code_size()) {
+ return false;
+ }
BlockBegin* cont = block_at(next_bci());
assert(cont != nullptr, "continuation must exist (BlockListBuilder starts a new block after a jsr");
diff --git a/src/hotspot/share/c1/c1_IR.cpp b/src/hotspot/share/c1/c1_IR.cpp
index e375d16aafb..b3faa54cc69 100644
--- a/src/hotspot/share/c1/c1_IR.cpp
+++ b/src/hotspot/share/c1/c1_IR.cpp
@@ -146,6 +146,7 @@ IRScope::IRScope(Compilation* compilation, IRScope* caller, int caller_bci, ciMe
_wrote_final = false;
_wrote_fields = false;
_wrote_volatile = false;
+ _wrote_stable = false;
_start = nullptr;
if (osr_bci != -1) {
diff --git a/src/hotspot/share/c1/c1_IR.hpp b/src/hotspot/share/c1/c1_IR.hpp
index 3035643708a..e2582c77b39 100644
--- a/src/hotspot/share/c1/c1_IR.hpp
+++ b/src/hotspot/share/c1/c1_IR.hpp
@@ -149,6 +149,7 @@ class IRScope: public CompilationResourceObj {
bool _wrote_final; // has written final field
bool _wrote_fields; // has written fields
bool _wrote_volatile; // has written volatile field
+ bool _wrote_stable; // has written @Stable field
BlockBegin* _start; // the start block, successsors are method entries
ResourceBitMap _requires_phi_function; // bit is set if phi functions at loop headers are necessary for a local variable
@@ -187,6 +188,8 @@ class IRScope: public CompilationResourceObj {
bool wrote_fields () const { return _wrote_fields; }
void set_wrote_volatile() { _wrote_volatile = true; }
bool wrote_volatile () const { return _wrote_volatile; }
+ void set_wrote_stable() { _wrote_stable = true; }
+ bool wrote_stable() const { return _wrote_stable; }
};
diff --git a/src/hotspot/share/c1/c1_Instruction.hpp b/src/hotspot/share/c1/c1_Instruction.hpp
index 32ff3d9f61c..e577e7fd90b 100644
--- a/src/hotspot/share/c1/c1_Instruction.hpp
+++ b/src/hotspot/share/c1/c1_Instruction.hpp
@@ -281,11 +281,11 @@ class Instruction: public CompilationResourceObj {
#endif
int _use_count; // the number of instructions referring to this value (w/o prev/next); only roots can have use count = 0 or > 1
int _pin_state; // set of PinReason describing the reason for pinning
+ unsigned int _flags; // Flag bits
ValueType* _type; // the instruction value type
Instruction* _next; // the next instruction if any (null for BlockEnd instructions)
Instruction* _subst; // the substitution instruction if any
LIR_Opr _operand; // LIR specific information
- unsigned int _flags; // Flag bits
ValueStack* _state_before; // Copy of state with input operands still on stack (or null)
ValueStack* _exception_state; // Copy of state for exception handling
@@ -403,11 +403,11 @@ class Instruction: public CompilationResourceObj {
#endif
_use_count(0)
, _pin_state(0)
+ , _flags(0)
, _type(type)
, _next(nullptr)
, _subst(nullptr)
, _operand(LIR_OprFact::illegalOpr)
- , _flags(0)
, _state_before(state_before)
, _exception_handlers(nullptr)
, _block(nullptr)
@@ -1518,9 +1518,9 @@ LEAF(MonitorExit, AccessMonitor)
LEAF(Intrinsic, StateSplit)
private:
vmIntrinsics::ID _id;
+ ArgsNonNullState _nonnull_state;
Values* _args;
Value _recv;
- ArgsNonNullState _nonnull_state;
public:
// preserves_state can be set to true for Intrinsics
diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp
index 3f53011024b..f03ed38284c 100644
--- a/src/hotspot/share/c1/c1_LIR.cpp
+++ b/src/hotspot/share/c1/c1_LIR.cpp
@@ -296,13 +296,13 @@ LIR_OpTypeCheck::LIR_OpTypeCheck(LIR_Code code, LIR_Opr result, LIR_Opr object,
, _tmp1(tmp1)
, _tmp2(tmp2)
, _tmp3(tmp3)
- , _fast_check(fast_check)
, _info_for_patch(info_for_patch)
, _info_for_exception(info_for_exception)
, _stub(stub)
, _profiled_method(nullptr)
, _profiled_bci(-1)
, _should_profile(false)
+ , _fast_check(fast_check)
{
if (code == lir_checkcast) {
assert(info_for_exception != nullptr, "checkcast throws exceptions");
@@ -323,13 +323,13 @@ LIR_OpTypeCheck::LIR_OpTypeCheck(LIR_Code code, LIR_Opr object, LIR_Opr array, L
, _tmp1(tmp1)
, _tmp2(tmp2)
, _tmp3(tmp3)
- , _fast_check(false)
, _info_for_patch(nullptr)
, _info_for_exception(info_for_exception)
, _stub(nullptr)
, _profiled_method(nullptr)
, _profiled_bci(-1)
, _should_profile(false)
+ , _fast_check(false)
{
if (code == lir_store_check) {
_stub = new ArrayStoreExceptionStub(object, info_for_exception);
diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp
index c69d29f8d61..c568caeca4b 100644
--- a/src/hotspot/share/c1/c1_LIR.hpp
+++ b/src/hotspot/share/c1/c1_LIR.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
#include "c1/c1_ValueType.hpp"
#include "oops/method.hpp"
#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
class BlockBegin;
class BlockList;
@@ -528,44 +529,44 @@ class LIR_Address: public LIR_OprPtr {
private:
LIR_Opr _base;
LIR_Opr _index;
- Scale _scale;
intx _disp;
+ Scale _scale;
BasicType _type;
public:
LIR_Address(LIR_Opr base, LIR_Opr index, BasicType type):
_base(base)
, _index(index)
- , _scale(times_1)
, _disp(0)
+ , _scale(times_1)
, _type(type) { verify(); }
LIR_Address(LIR_Opr base, intx disp, BasicType type):
_base(base)
, _index(LIR_Opr::illegalOpr())
- , _scale(times_1)
, _disp(disp)
+ , _scale(times_1)
, _type(type) { verify(); }
LIR_Address(LIR_Opr base, BasicType type):
_base(base)
, _index(LIR_Opr::illegalOpr())
- , _scale(times_1)
, _disp(0)
+ , _scale(times_1)
, _type(type) { verify(); }
LIR_Address(LIR_Opr base, LIR_Opr index, intx disp, BasicType type):
_base(base)
, _index(index)
- , _scale(times_1)
, _disp(disp)
+ , _scale(times_1)
, _type(type) { verify(); }
LIR_Address(LIR_Opr base, LIR_Opr index, Scale scale, intx disp, BasicType type):
_base(base)
, _index(index)
- , _scale(scale)
, _disp(disp)
+ , _scale(scale)
, _type(type) { verify(); }
LIR_Opr base() const { return _base; }
@@ -1122,7 +1123,7 @@ class LIR_Op: public CompilationResourceObj {
}
#endif
- virtual const char * name() const PRODUCT_RETURN0;
+ virtual const char * name() const PRODUCT_RETURN_NULL;
virtual void visit(LIR_OpVisitState* state);
int id() const { return _id; }
@@ -1400,7 +1401,7 @@ class LIR_Op1: public LIR_Op {
virtual bool is_patching() { return _patch != lir_patch_none; }
virtual void emit_code(LIR_Assembler* masm);
virtual LIR_Op1* as_Op1() { return this; }
- virtual const char * name() const PRODUCT_RETURN0;
+ virtual const char * name() const PRODUCT_RETURN_NULL;
void set_in_opr(LIR_Opr opr) { _opr = opr; }
@@ -1544,13 +1545,13 @@ class LIR_OpTypeCheck: public LIR_Op {
LIR_Opr _tmp1;
LIR_Opr _tmp2;
LIR_Opr _tmp3;
- bool _fast_check;
CodeEmitInfo* _info_for_patch;
CodeEmitInfo* _info_for_exception;
CodeStub* _stub;
ciMethod* _profiled_method;
int _profiled_bci;
bool _should_profile;
+ bool _fast_check;
public:
LIR_OpTypeCheck(LIR_Code code, LIR_Opr result, LIR_Opr object, ciKlass* klass,
@@ -1593,13 +1594,13 @@ class LIR_Op2: public LIR_Op {
protected:
LIR_Opr _opr1;
LIR_Opr _opr2;
- BasicType _type;
LIR_Opr _tmp1;
LIR_Opr _tmp2;
LIR_Opr _tmp3;
LIR_Opr _tmp4;
LIR_Opr _tmp5;
LIR_Condition _condition;
+ BasicType _type;
void verify() const;
@@ -1609,13 +1610,13 @@ class LIR_Op2: public LIR_Op {
, _fpu_stack_size(0)
, _opr1(opr1)
, _opr2(opr2)
- , _type(type)
, _tmp1(LIR_OprFact::illegalOpr)
, _tmp2(LIR_OprFact::illegalOpr)
, _tmp3(LIR_OprFact::illegalOpr)
, _tmp4(LIR_OprFact::illegalOpr)
, _tmp5(LIR_OprFact::illegalOpr)
- , _condition(condition) {
+ , _condition(condition)
+ , _type(type) {
assert(code == lir_cmp || code == lir_branch || code == lir_cond_float_branch || code == lir_assert, "code check");
}
@@ -1624,13 +1625,13 @@ class LIR_Op2: public LIR_Op {
, _fpu_stack_size(0)
, _opr1(opr1)
, _opr2(opr2)
- , _type(type)
, _tmp1(LIR_OprFact::illegalOpr)
, _tmp2(LIR_OprFact::illegalOpr)
, _tmp3(LIR_OprFact::illegalOpr)
, _tmp4(LIR_OprFact::illegalOpr)
, _tmp5(LIR_OprFact::illegalOpr)
- , _condition(condition) {
+ , _condition(condition)
+ , _type(type) {
assert(code == lir_cmove, "code check");
assert(type != T_ILLEGAL, "cmove should have type");
}
@@ -1641,13 +1642,13 @@ class LIR_Op2: public LIR_Op {
, _fpu_stack_size(0)
, _opr1(opr1)
, _opr2(opr2)
- , _type(type)
, _tmp1(LIR_OprFact::illegalOpr)
, _tmp2(LIR_OprFact::illegalOpr)
, _tmp3(LIR_OprFact::illegalOpr)
, _tmp4(LIR_OprFact::illegalOpr)
, _tmp5(LIR_OprFact::illegalOpr)
- , _condition(lir_cond_unknown) {
+ , _condition(lir_cond_unknown)
+ , _type(type) {
assert(code != lir_cmp && code != lir_branch && code != lir_cond_float_branch && is_in_range(code, begin_op2, end_op2), "code check");
}
@@ -1657,13 +1658,13 @@ class LIR_Op2: public LIR_Op {
, _fpu_stack_size(0)
, _opr1(opr1)
, _opr2(opr2)
- , _type(T_ILLEGAL)
, _tmp1(tmp1)
, _tmp2(tmp2)
, _tmp3(tmp3)
, _tmp4(tmp4)
, _tmp5(tmp5)
- , _condition(lir_cond_unknown) {
+ , _condition(lir_cond_unknown)
+ , _type(T_ILLEGAL) {
assert(code != lir_cmp && code != lir_branch && code != lir_cond_float_branch && is_in_range(code, begin_op2, end_op2), "code check");
}
@@ -1748,8 +1749,8 @@ class LIR_OpAllocArray : public LIR_Op {
LIR_Opr _tmp2;
LIR_Opr _tmp3;
LIR_Opr _tmp4;
- BasicType _type;
CodeStub* _stub;
+ BasicType _type;
bool _zero_array;
public:
@@ -1761,8 +1762,8 @@ class LIR_OpAllocArray : public LIR_Op {
, _tmp2(t2)
, _tmp3(t3)
, _tmp4(t4)
- , _type(type)
, _stub(stub)
+ , _type(type)
, _zero_array(zero_array) {}
LIR_Opr klass() const { return _klass; }
@@ -1811,13 +1812,13 @@ class LIR_Op4: public LIR_Op {
LIR_Opr _opr2;
LIR_Opr _opr3;
LIR_Opr _opr4;
- BasicType _type;
LIR_Opr _tmp1;
LIR_Opr _tmp2;
LIR_Opr _tmp3;
LIR_Opr _tmp4;
LIR_Opr _tmp5;
LIR_Condition _condition;
+ BasicType _type;
public:
LIR_Op4(LIR_Code code, LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr opr3, LIR_Opr opr4,
@@ -1827,13 +1828,13 @@ class LIR_Op4: public LIR_Op {
, _opr2(opr2)
, _opr3(opr3)
, _opr4(opr4)
- , _type(type)
, _tmp1(LIR_OprFact::illegalOpr)
, _tmp2(LIR_OprFact::illegalOpr)
, _tmp3(LIR_OprFact::illegalOpr)
, _tmp4(LIR_OprFact::illegalOpr)
, _tmp5(LIR_OprFact::illegalOpr)
- , _condition(condition) {
+ , _condition(condition)
+ , _type(type) {
assert(code == lir_cmove, "code check");
assert(type != T_ILLEGAL, "cmove should have type");
}
@@ -2033,8 +2034,9 @@ class LIR_OpProfileCall : public LIR_Op {
virtual void print_instr(outputStream* out) const PRODUCT_RETURN;
bool should_profile_receiver_type() const {
bool callee_is_static = _profiled_callee->is_loaded() && _profiled_callee->is_static();
+ bool callee_is_private = _profiled_callee->is_loaded() && _profiled_callee->is_private();
Bytecodes::Code bc = _profiled_method->java_code_at_bci(_profiled_bci);
- bool call_is_virtual = (bc == Bytecodes::_invokevirtual && !_profiled_callee->can_be_statically_bound()) || bc == Bytecodes::_invokeinterface;
+ bool call_is_virtual = (bc == Bytecodes::_invokevirtual && !callee_is_private) || bc == Bytecodes::_invokeinterface;
return C1ProfileVirtualCalls && call_is_virtual && !callee_is_static;
}
};
diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp
index cd084135658..74fdf7a5b76 100644
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp
@@ -659,7 +659,7 @@ void LIRGenerator::new_instance(LIR_Opr dst, ciInstanceKlass* klass, bool is_unr
if (UseFastNewInstance && klass->is_loaded()
&& !Klass::layout_helper_needs_slow_path(klass->layout_helper())) {
- Runtime1::StubID stub_id = klass->is_initialized() ? Runtime1::fast_new_instance_id : Runtime1::fast_new_instance_init_check_id;
+ C1StubId stub_id = klass->is_initialized() ? C1StubId::fast_new_instance_id : C1StubId::fast_new_instance_init_check_id;
CodeStub* slow_path = new NewInstanceStub(klass_reg, dst, klass, info, stub_id);
@@ -670,7 +670,7 @@ void LIRGenerator::new_instance(LIR_Opr dst, ciInstanceKlass* klass, bool is_unr
__ allocate_object(dst, scratch1, scratch2, scratch3, scratch4,
oopDesc::header_size(), instance_size, klass_reg, !klass->is_initialized(), slow_path);
} else {
- CodeStub* slow_path = new NewInstanceStub(klass_reg, dst, klass, info, Runtime1::new_instance_id);
+ CodeStub* slow_path = new NewInstanceStub(klass_reg, dst, klass, info, C1StubId::new_instance_id);
__ branch(lir_cond_always, slow_path);
__ branch_destination(slow_path->continuation());
}
@@ -1300,7 +1300,7 @@ void LIRGenerator::do_isPrimitive(Intrinsic* x) {
}
__ move(new LIR_Address(rcvr.result(), java_lang_Class::klass_offset(), T_ADDRESS), temp, info);
- __ cmp(lir_cond_notEqual, temp, LIR_OprFact::metadataConst(0));
+ __ cmp(lir_cond_notEqual, temp, LIR_OprFact::metadataConst(nullptr));
__ cmove(lir_cond_notEqual, LIR_OprFact::intConst(0), LIR_OprFact::intConst(1), result, T_BOOLEAN);
}
@@ -1333,7 +1333,7 @@ void LIRGenerator::do_getModifiers(Intrinsic* x) {
// Check if this is a Java mirror of primitive type, and select the appropriate klass.
LIR_Opr klass = new_register(T_METADATA);
- __ cmp(lir_cond_equal, recv_klass, LIR_OprFact::metadataConst(0));
+ __ cmp(lir_cond_equal, recv_klass, LIR_OprFact::metadataConst(nullptr));
__ cmove(lir_cond_equal, prim_klass, recv_klass, klass, T_ADDRESS);
// Get the answer.
@@ -1479,7 +1479,7 @@ void LIRGenerator::do_RegisterFinalizer(Intrinsic* x) {
args->append(receiver.result());
CodeEmitInfo* info = state_for(x, x->state());
call_runtime(&signature, args,
- CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::register_finalizer_id)),
+ CAST_FROM_FN_PTR(address, Runtime1::entry_for(C1StubId::register_finalizer_id)),
voidType, info);
set_no_result(x);
@@ -2971,6 +2971,7 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
case vmIntrinsics::_dsqrt: // fall through
case vmIntrinsics::_dsqrt_strict: // fall through
case vmIntrinsics::_dtan: // fall through
+ case vmIntrinsics::_dtanh: // fall through
case vmIntrinsics::_dsin : // fall through
case vmIntrinsics::_dcos : // fall through
case vmIntrinsics::_dexp : // fall through
diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp
index 31ae3f6bee0..3ebd1f42f36 100644
--- a/src/hotspot/share/c1/c1_Runtime1.cpp
+++ b/src/hotspot/share/c1/c1_Runtime1.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
@@ -109,10 +109,13 @@ void StubAssembler::set_num_rt_args(int args) {
// Implementation of Runtime1
-CodeBlob* Runtime1::_blobs[Runtime1::number_of_ids];
+CodeBlob* Runtime1::_blobs[(int)C1StubId::NUM_STUBIDS];
+
+#define C1_BLOB_NAME_DEFINE(name) "C1 Runtime " # name "_blob",
const char *Runtime1::_blob_names[] = {
- RUNTIME1_STUBS(STUB_NAME, LAST_STUB_NAME)
+ C1_STUBS_DO(C1_BLOB_NAME_DEFINE)
};
+#undef C1_STUB_NAME_DEFINE
#ifndef PRODUCT
// statistics
@@ -190,17 +193,17 @@ static void deopt_caller(JavaThread* current) {
}
}
-class StubIDStubAssemblerCodeGenClosure: public StubAssemblerCodeGenClosure {
+class C1StubIdStubAssemblerCodeGenClosure: public StubAssemblerCodeGenClosure {
private:
- Runtime1::StubID _id;
+ C1StubId _id;
public:
- StubIDStubAssemblerCodeGenClosure(Runtime1::StubID id) : _id(id) {}
+ C1StubIdStubAssemblerCodeGenClosure(C1StubId id) : _id(id) {}
virtual OopMapSet* generate_code(StubAssembler* sasm) {
return Runtime1::generate_code_for(_id, sasm);
}
};
-CodeBlob* Runtime1::generate_blob(BufferBlob* buffer_blob, int stub_id, const char* name, bool expect_oop_map, StubAssemblerCodeGenClosure* cl) {
+CodeBlob* Runtime1::generate_blob(BufferBlob* buffer_blob, C1StubId id, const char* name, bool expect_oop_map, StubAssemblerCodeGenClosure* cl) {
ResourceMark rm;
// create code buffer for code storage
CodeBuffer code(buffer_blob);
@@ -212,7 +215,7 @@ CodeBlob* Runtime1::generate_blob(BufferBlob* buffer_blob, int stub_id, const ch
Compilation::setup_code_buffer(&code, 0);
// create assembler for code generation
- StubAssembler* sasm = new StubAssembler(&code, name, stub_id);
+ StubAssembler* sasm = new StubAssembler(&code, name, (int)id);
// generate code for runtime stub
oop_maps = cl->generate_code(sasm);
assert(oop_maps == nullptr || sasm->frame_size() != no_frame_size,
@@ -237,40 +240,41 @@ CodeBlob* Runtime1::generate_blob(BufferBlob* buffer_blob, int stub_id, const ch
return blob;
}
-void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) {
- assert(0 <= id && id < number_of_ids, "illegal stub id");
+void Runtime1::generate_blob_for(BufferBlob* buffer_blob, C1StubId id) {
+ assert(C1StubId::NO_STUBID < id && id < C1StubId::NUM_STUBIDS, "illegal stub id");
bool expect_oop_map = true;
#ifdef ASSERT
// Make sure that stubs that need oopmaps have them
switch (id) {
// These stubs don't need to have an oopmap
- case dtrace_object_alloc_id:
- case slow_subtype_check_id:
- case fpu2long_stub_id:
- case unwind_exception_id:
- case counter_overflow_id:
+ case C1StubId::dtrace_object_alloc_id:
+ case C1StubId::slow_subtype_check_id:
+ case C1StubId::fpu2long_stub_id:
+ case C1StubId::unwind_exception_id:
+ case C1StubId::counter_overflow_id:
expect_oop_map = false;
break;
default:
break;
}
#endif
- StubIDStubAssemblerCodeGenClosure cl(id);
+ C1StubIdStubAssemblerCodeGenClosure cl(id);
CodeBlob* blob = generate_blob(buffer_blob, id, name_for(id), expect_oop_map, &cl);
// install blob
- _blobs[id] = blob;
+ _blobs[(int)id] = blob;
}
void Runtime1::initialize(BufferBlob* blob) {
// platform-dependent initialization
initialize_pd();
// generate stubs
- for (int id = 0; id < number_of_ids; id++) generate_blob_for(blob, (StubID)id);
+ int limit = (int)C1StubId::NUM_STUBIDS;
+ for (int id = 0; id < limit; id++) generate_blob_for(blob, (C1StubId)id);
// printing
#ifndef PRODUCT
if (PrintSimpleStubs) {
ResourceMark rm;
- for (int id = 0; id < number_of_ids; id++) {
+ for (int id = 0; id < limit; id++) {
_blobs[id]->print();
if (_blobs[id]->oop_maps() != nullptr) {
_blobs[id]->oop_maps()->print();
@@ -282,20 +286,22 @@ void Runtime1::initialize(BufferBlob* blob) {
bs->generate_c1_runtime_stubs(blob);
}
-CodeBlob* Runtime1::blob_for(StubID id) {
- assert(0 <= id && id < number_of_ids, "illegal stub id");
- return _blobs[id];
+CodeBlob* Runtime1::blob_for(C1StubId id) {
+ assert(C1StubId::NO_STUBID < id && id < C1StubId::NUM_STUBIDS, "illegal stub id");
+ return _blobs[(int)id];
}
-const char* Runtime1::name_for(StubID id) {
- assert(0 <= id && id < number_of_ids, "illegal stub id");
- return _blob_names[id];
+const char* Runtime1::name_for(C1StubId id) {
+ assert(C1StubId::NO_STUBID < id && id < C1StubId::NUM_STUBIDS, "illegal stub id");
+ return _blob_names[(int)id];
}
const char* Runtime1::name_for_address(address entry) {
- for (int id = 0; id < number_of_ids; id++) {
- if (entry == entry_for((StubID)id)) return name_for((StubID)id);
+ int limit = (int)C1StubId::NUM_STUBIDS;
+ for (int i = 0; i < limit; i++) {
+ C1StubId id = (C1StubId)i;
+ if (entry == entry_for(id)) return name_for(id);
}
#define FUNCTION_CASE(a, f) \
@@ -341,6 +347,7 @@ const char* Runtime1::name_for_address(address entry) {
FUNCTION_CASE(entry, StubRoutines::dsin());
FUNCTION_CASE(entry, StubRoutines::dcos());
FUNCTION_CASE(entry, StubRoutines::dtan());
+ FUNCTION_CASE(entry, StubRoutines::dtanh());
#undef FUNCTION_CASE
@@ -425,8 +432,8 @@ JRT_ENTRY(void, Runtime1::new_multi_array(JavaThread* current, Klass* klass, int
JRT_END
-JRT_ENTRY(void, Runtime1::unimplemented_entry(JavaThread* current, StubID id))
- tty->print_cr("Runtime1::entry_for(%d) returned unimplemented entry point", id);
+JRT_ENTRY(void, Runtime1::unimplemented_entry(JavaThread* current, C1StubId id))
+ tty->print_cr("Runtime1::entry_for(%d) returned unimplemented entry point", (int)id);
JRT_END
@@ -525,8 +532,8 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c
// This function is called when we are about to throw an exception. Therefore,
// we have to poll the stack watermark barrier to make sure that not yet safe
// stack frames are made safe before returning into them.
- if (current->last_frame().cb() == Runtime1::blob_for(Runtime1::handle_exception_from_callee_id)) {
- // The Runtime1::handle_exception_from_callee_id handler is invoked after the
+ if (current->last_frame().cb() == Runtime1::blob_for(C1StubId::handle_exception_from_callee_id)) {
+ // The C1StubId::handle_exception_from_callee_id handler is invoked after the
// frame has been unwound. It instead builds its own stub frame, to call the
// runtime. But the throwing frame has already been unwound here.
StackWatermarkSet::after_unwind(current);
@@ -757,8 +764,8 @@ JRT_BLOCK_ENTRY(void, Runtime1::monitorenter(JavaThread* current, oopDesc* obj,
if (LockingMode == LM_MONITOR) {
lock->set_obj(obj);
}
- assert(LockingMode == LM_LIGHTWEIGHT || obj == lock->obj(), "must match");
- SharedRuntime::monitor_enter_helper(obj, LockingMode == LM_LIGHTWEIGHT ? nullptr : lock->lock(), current);
+ assert(obj == lock->obj(), "must match");
+ SharedRuntime::monitor_enter_helper(obj, lock->lock(), current);
JRT_END
@@ -880,7 +887,7 @@ static Klass* resolve_field_return_klass(const methodHandle& caller, int bci, TR
// movl reg, [reg1 + ] (for field offsets)
// jmp continue
//
-// patch_stub: jmp Runtim1::patch_code (through a runtime stub)
+// patch_stub: jmp Runtime1::patch_code (through a runtime stub)
// jmp patch_site
//
// If the class is being initialized the patch body is rewritten and
@@ -922,7 +929,7 @@ static Klass* resolve_field_return_klass(const methodHandle& caller, int bci, TR
// Therefore, if there is any chance of a race condition, we try to
// patch only naturally aligned words, as single, full-word writes.
-JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_id ))
+JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, C1StubId stub_id ))
#ifndef PRODUCT
if (PrintC1Statistics) {
_patch_code_slowcase_cnt++;
@@ -959,9 +966,9 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_
Handle mirror(current, nullptr); // oop needed by load_mirror_patching code
Handle appendix(current, nullptr); // oop needed by appendix_patching code
bool load_klass_or_mirror_patch_id =
- (stub_id == Runtime1::load_klass_patching_id || stub_id == Runtime1::load_mirror_patching_id);
+ (stub_id == C1StubId::load_klass_patching_id || stub_id == C1StubId::load_mirror_patching_id);
- if (stub_id == Runtime1::access_field_patching_id) {
+ if (stub_id == C1StubId::access_field_patching_id) {
Bytecode_field field_access(caller_method, bci);
fieldDescriptor result; // initialize class if needed
@@ -1044,7 +1051,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_
default: fatal("unexpected bytecode for load_klass_or_mirror_patch_id");
}
load_klass = k;
- } else if (stub_id == load_appendix_patching_id) {
+ } else if (stub_id == C1StubId::load_appendix_patching_id) {
Bytecode_invoke bytecode(caller_method, bci);
Bytecodes::Code bc = bytecode.invoke_code();
@@ -1096,7 +1103,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_
// Now copy code back
{
- MutexLocker ml_patch (current, Patching_lock, Mutex::_no_safepoint_check_flag);
+ MutexLocker ml_code (current, CodeCache_lock, Mutex::_no_safepoint_check_flag);
//
// Deoptimization may have happened while we waited for the lock.
// In that case we don't bother to do any patching we just return
@@ -1128,7 +1135,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_
if (TracePatching) {
ttyLocker ttyl;
tty->print_cr(" Patching %s at bci %d at address " INTPTR_FORMAT " (%s)", Bytecodes::name(code), bci,
- p2i(instr_pc), (stub_id == Runtime1::access_field_patching_id) ? "field" : "klass");
+ p2i(instr_pc), (stub_id == C1StubId::access_field_patching_id) ? "field" : "klass");
nmethod* caller_code = CodeCache::find_nmethod(caller_frame.pc());
assert(caller_code != nullptr, "nmethod not found");
@@ -1144,7 +1151,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_
}
// depending on the code below, do_patch says whether to copy the patch body back into the nmethod
bool do_patch = true;
- if (stub_id == Runtime1::access_field_patching_id) {
+ if (stub_id == C1StubId::access_field_patching_id) {
// The offset may not be correct if the class was not loaded at code generation time.
// Set it now.
NativeMovRegMem* n_move = nativeMovRegMem_at(copy_buff);
@@ -1170,7 +1177,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_
assert(n_copy->data() == 0 ||
n_copy->data() == (intptr_t)Universe::non_oop_word(),
"illegal init value");
- if (stub_id == Runtime1::load_klass_patching_id) {
+ if (stub_id == C1StubId::load_klass_patching_id) {
assert(load_klass != nullptr, "klass not set");
n_copy->set_data((intx) (load_klass));
} else {
@@ -1182,7 +1189,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_
Disassembler::decode(copy_buff, copy_buff + *byte_count, tty);
}
}
- } else if (stub_id == Runtime1::load_appendix_patching_id) {
+ } else if (stub_id == C1StubId::load_appendix_patching_id) {
NativeMovConstReg* n_copy = nativeMovConstReg_at(copy_buff);
assert(n_copy->data() == 0 ||
n_copy->data() == (intptr_t)Universe::non_oop_word(),
@@ -1201,7 +1208,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_
// first replace the tail, then the call
#ifdef ARM
if((load_klass_or_mirror_patch_id ||
- stub_id == Runtime1::load_appendix_patching_id) &&
+ stub_id == C1StubId::load_appendix_patching_id) &&
nativeMovConstReg_at(copy_buff)->is_pc_relative()) {
nmethod* nm = CodeCache::find_nmethod(instr_pc);
address addr = nullptr;
@@ -1209,13 +1216,13 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_
RelocIterator mds(nm, copy_buff, copy_buff + 1);
while (mds.next()) {
if (mds.type() == relocInfo::oop_type) {
- assert(stub_id == Runtime1::load_mirror_patching_id ||
- stub_id == Runtime1::load_appendix_patching_id, "wrong stub id");
+ assert(stub_id == C1StubId::load_mirror_patching_id ||
+ stub_id == C1StubId::load_appendix_patching_id, "wrong stub id");
oop_Relocation* r = mds.oop_reloc();
addr = (address)r->oop_addr();
break;
} else if (mds.type() == relocInfo::metadata_type) {
- assert(stub_id == Runtime1::load_klass_patching_id, "wrong stub id");
+ assert(stub_id == C1StubId::load_klass_patching_id, "wrong stub id");
metadata_Relocation* r = mds.metadata_reloc();
addr = (address)r->metadata_addr();
break;
@@ -1238,9 +1245,9 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_
NativeGeneralJump::replace_mt_safe(instr_pc, copy_buff);
if (load_klass_or_mirror_patch_id ||
- stub_id == Runtime1::load_appendix_patching_id) {
+ stub_id == C1StubId::load_appendix_patching_id) {
relocInfo::relocType rtype =
- (stub_id == Runtime1::load_klass_patching_id) ?
+ (stub_id == C1StubId::load_klass_patching_id) ?
relocInfo::metadata_type :
relocInfo::oop_type;
// update relocInfo to metadata
@@ -1261,12 +1268,8 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_
}
}
}
- }
-
- // If we are patching in a non-perm oop, make sure the nmethod
- // is on the right list.
- {
- MutexLocker ml_code (current, CodeCache_lock, Mutex::_no_safepoint_check_flag);
+ // If we are patching in a non-perm oop, make sure the nmethod
+ // is on the right list.
nmethod* nm = CodeCache::find_nmethod(caller_frame.pc());
guarantee(nm != nullptr, "only nmethods can contain non-perm oops");
@@ -1278,9 +1281,9 @@ JRT_END
#else // DEOPTIMIZE_WHEN_PATCHING
-static bool is_patching_needed(JavaThread* current, Runtime1::StubID stub_id) {
- if (stub_id == Runtime1::load_klass_patching_id ||
- stub_id == Runtime1::load_mirror_patching_id) {
+static bool is_patching_needed(JavaThread* current, C1StubId stub_id) {
+ if (stub_id == C1StubId::load_klass_patching_id ||
+ stub_id == C1StubId::load_mirror_patching_id) {
// last java frame on stack
vframeStream vfst(current, true);
assert(!vfst.at_end(), "Java frame must exist");
@@ -1309,7 +1312,7 @@ static bool is_patching_needed(JavaThread* current, Runtime1::StubID stub_id) {
return true;
}
-void Runtime1::patch_code(JavaThread* current, Runtime1::StubID stub_id) {
+void Runtime1::patch_code(JavaThread* current, C1StubId stub_id) {
#ifndef PRODUCT
if (PrintC1Statistics) {
_patch_code_slowcase_cnt++;
@@ -1364,7 +1367,7 @@ int Runtime1::move_klass_patching(JavaThread* current) {
{
// Enter VM mode
ResetNoHandleMark rnhm;
- patch_code(current, load_klass_patching_id);
+ patch_code(current, C1StubId::load_klass_patching_id);
}
// Back in JAVA, use no oops DON'T safepoint
@@ -1381,7 +1384,7 @@ int Runtime1::move_mirror_patching(JavaThread* current) {
{
// Enter VM mode
ResetNoHandleMark rnhm;
- patch_code(current, load_mirror_patching_id);
+ patch_code(current, C1StubId::load_mirror_patching_id);
}
// Back in JAVA, use no oops DON'T safepoint
@@ -1398,7 +1401,7 @@ int Runtime1::move_appendix_patching(JavaThread* current) {
{
// Enter VM mode
ResetNoHandleMark rnhm;
- patch_code(current, load_appendix_patching_id);
+ patch_code(current, C1StubId::load_appendix_patching_id);
}
// Back in JAVA, use no oops DON'T safepoint
@@ -1425,7 +1428,7 @@ int Runtime1::access_field_patching(JavaThread* current) {
{
// Enter VM mode
ResetNoHandleMark rnhm;
- patch_code(current, access_field_patching_id);
+ patch_code(current, C1StubId::access_field_patching_id);
}
// Back in JAVA, use no oops DON'T safepoint
diff --git a/src/hotspot/share/c1/c1_Runtime1.hpp b/src/hotspot/share/c1/c1_Runtime1.hpp
index 2e4c9f8a733..330c4067504 100644
--- a/src/hotspot/share/c1/c1_Runtime1.hpp
+++ b/src/hotspot/share/c1/c1_Runtime1.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@
#include "interpreter/interpreter.hpp"
#include "memory/allStatic.hpp"
#include "runtime/deoptimization.hpp"
+#include "runtime/stubDeclarations.hpp"
class StubAssembler;
@@ -37,61 +38,26 @@ class StubAssembler;
// runtime routines needed by code code generated
// by the Compiler1.
-#define RUNTIME1_STUBS(stub, last_entry) \
- stub(dtrace_object_alloc) \
- stub(unwind_exception) \
- stub(forward_exception) \
- stub(throw_range_check_failed) /* throws ArrayIndexOutOfBoundsException */ \
- stub(throw_index_exception) /* throws IndexOutOfBoundsException */ \
- stub(throw_div0_exception) \
- stub(throw_null_pointer_exception) \
- stub(register_finalizer) \
- stub(new_instance) \
- stub(fast_new_instance) \
- stub(fast_new_instance_init_check) \
- stub(new_type_array) \
- stub(new_object_array) \
- stub(new_multi_array) \
- stub(handle_exception_nofpu) /* optimized version that does not preserve fpu registers */ \
- stub(handle_exception) \
- stub(handle_exception_from_callee) \
- stub(throw_array_store_exception) \
- stub(throw_class_cast_exception) \
- stub(throw_incompatible_class_change_error) \
- stub(slow_subtype_check) \
- stub(monitorenter) \
- stub(monitorenter_nofpu) /* optimized version that does not preserve fpu registers */ \
- stub(monitorexit) \
- stub(monitorexit_nofpu) /* optimized version that does not preserve fpu registers */ \
- stub(deoptimize) \
- stub(access_field_patching) \
- stub(load_klass_patching) \
- stub(load_mirror_patching) \
- stub(load_appendix_patching) \
- stub(fpu2long_stub) \
- stub(counter_overflow) \
- stub(predicate_failed_trap) \
- last_entry(number_of_ids)
-
-#define DECLARE_STUB_ID(x) x ## _id ,
-#define DECLARE_LAST_STUB_ID(x) x
-#define STUB_NAME(x) #x " Runtime1 stub",
-#define LAST_STUB_NAME(x) #x " Runtime1 stub"
-
class StubAssemblerCodeGenClosure: public Closure {
public:
virtual OopMapSet* generate_code(StubAssembler* sasm) = 0;
};
+// define C1StubId enum tags: unwind_exception_id etc
+
+#define C1_STUB_ID_ENUM_DECLARE(name) STUB_ID_NAME(name),
+enum class C1StubId :int {
+ NO_STUBID = -1,
+ C1_STUBS_DO(C1_STUB_ID_ENUM_DECLARE)
+ NUM_STUBIDS
+};
+#undef C1_STUB_ID_ENUM_DECLARE
+
class Runtime1: public AllStatic {
friend class VMStructs;
friend class ArrayCopyStub;
- public:
- enum StubID {
- RUNTIME1_STUBS(DECLARE_STUB_ID, DECLARE_LAST_STUB_ID)
- };
-
+public:
// statistics
#ifndef PRODUCT
static uint _generic_arraycopystub_cnt;
@@ -115,17 +81,17 @@ class Runtime1: public AllStatic {
#endif
private:
- static CodeBlob* _blobs[number_of_ids];
+ static CodeBlob* _blobs[(int)C1StubId::NUM_STUBIDS];
static const char* _blob_names[];
// stub generation
public:
- static CodeBlob* generate_blob(BufferBlob* buffer_blob, int stub_id, const char* name, bool expect_oop_map, StubAssemblerCodeGenClosure *cl);
- static void generate_blob_for(BufferBlob* blob, StubID id);
- static OopMapSet* generate_code_for(StubID id, StubAssembler* sasm);
+ static CodeBlob* generate_blob(BufferBlob* buffer_blob, C1StubId id, const char* name, bool expect_oop_map, StubAssemblerCodeGenClosure *cl);
+ static void generate_blob_for(BufferBlob* blob, C1StubId id);
+ static OopMapSet* generate_code_for(C1StubId id, StubAssembler* sasm);
private:
static OopMapSet* generate_exception_throw(StubAssembler* sasm, address target, bool has_argument);
- static OopMapSet* generate_handle_exception(StubID id, StubAssembler* sasm);
+ static OopMapSet* generate_handle_exception(C1StubId id, StubAssembler* sasm);
static void generate_unwind_exception(StubAssembler *sasm);
static OopMapSet* generate_patching(StubAssembler* sasm, address target);
@@ -140,7 +106,7 @@ class Runtime1: public AllStatic {
static address counter_overflow(JavaThread* current, int bci, Method* method);
- static void unimplemented_entry(JavaThread* current, StubID id);
+ static void unimplemented_entry(JavaThread* current, C1StubId id);
static address exception_handler_for_pc(JavaThread* current);
@@ -162,7 +128,7 @@ class Runtime1: public AllStatic {
static int move_mirror_patching(JavaThread* current);
static int move_appendix_patching(JavaThread* current);
- static void patch_code(JavaThread* current, StubID stub_id);
+ static void patch_code(JavaThread* current, C1StubId stub_id);
public:
// initialization
@@ -170,9 +136,9 @@ class Runtime1: public AllStatic {
static void initialize_pd();
// stubs
- static CodeBlob* blob_for (StubID id);
- static address entry_for(StubID id) { return blob_for(id)->code_begin(); }
- static const char* name_for (StubID id);
+ static CodeBlob* blob_for (C1StubId id);
+ static address entry_for(C1StubId id) { return blob_for(id)->code_begin(); }
+ static const char* name_for (C1StubId id);
static const char* name_for_address(address entry);
// platform might add runtime names.
diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp
index 76b6698a400..3c67216d4c5 100644
--- a/src/hotspot/share/cds/archiveBuilder.cpp
+++ b/src/hotspot/share/cds/archiveBuilder.cpp
@@ -1104,6 +1104,17 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
LogStreamHandle(Info, cds, map) st;
+ HeapRootSegments segments = heap_info->heap_root_segments();
+ assert(segments.base_offset() == 0, "Sanity");
+
+ for (size_t seg_idx = 0; seg_idx < segments.count(); seg_idx++) {
+ address requested_start = ArchiveHeapWriter::buffered_addr_to_requested_addr(start);
+ st.print_cr(PTR_FORMAT ": Heap roots segment [%d]",
+ p2i(requested_start), segments.size_in_elems(seg_idx));
+ start += segments.size_in_bytes(seg_idx);
+ }
+ log_heap_roots();
+
while (start < end) {
size_t byte_size;
oop source_oop = ArchiveHeapWriter::buffered_addr_to_source_obj(start);
@@ -1114,12 +1125,6 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
// This is a regular oop that got archived.
print_oop_with_requested_addr_cr(&st, source_oop, false);
byte_size = source_oop->size() * BytesPerWord;
- } else if (start == ArchiveHeapWriter::buffered_heap_roots_addr()) {
- // HeapShared::roots() is copied specially, so it doesn't exist in
- // ArchiveHeapWriter::BufferOffsetToSourceObjectTable.
- // See ArchiveHeapWriter::copy_roots_to_buffer().
- st.print_cr("HeapShared::roots[%d]", HeapShared::pending_roots()->length());
- byte_size = ArchiveHeapWriter::heap_roots_word_size() * BytesPerWord;
} else if ((byte_size = ArchiveHeapWriter::get_filler_size_at(start)) > 0) {
// We have a filler oop, which also does not exist in BufferOffsetToSourceObjectTable.
st.print_cr("filler " SIZE_FORMAT " bytes", byte_size);
@@ -1132,8 +1137,6 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
if (source_oop != nullptr) {
log_oop_details(heap_info, source_oop, /*buffered_addr=*/start);
- } else if (start == ArchiveHeapWriter::buffered_heap_roots_addr()) {
- log_heap_roots();
}
start = oop_end;
}
diff --git a/src/hotspot/share/cds/archiveHeapLoader.cpp b/src/hotspot/share/cds/archiveHeapLoader.cpp
index feaf245d22c..0e7ef08064c 100644
--- a/src/hotspot/share/cds/archiveHeapLoader.cpp
+++ b/src/hotspot/share/cds/archiveHeapLoader.cpp
@@ -374,8 +374,17 @@ void ArchiveHeapLoader::finish_initialization() {
if (is_in_use()) {
patch_native_pointers();
intptr_t bottom = is_loaded() ? _loaded_heap_bottom : _mapped_heap_bottom;
- intptr_t roots_oop = bottom + FileMapInfo::current_info()->heap_roots_offset();
- HeapShared::init_roots(cast_to_oop(roots_oop));
+
+ // The heap roots are stored in one or more segments that are laid out consecutively.
+ // The size of each segment (except for the last one) is max_size_in_{elems,bytes}.
+ HeapRootSegments segments = FileMapInfo::current_info()->heap_root_segments();
+ HeapShared::init_root_segment_sizes(segments.max_size_in_elems());
+ intptr_t first_segment_addr = bottom + segments.base_offset();
+ for (size_t c = 0; c < segments.count(); c++) {
+ oop segment_oop = cast_to_oop(first_segment_addr + (c * segments.max_size_in_bytes()));
+ assert(segment_oop->is_objArray(), "Must be");
+ HeapShared::add_root_segment((objArrayOop)segment_oop);
+ }
}
}
diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp
index bf49805658c..710e693bfdb 100644
--- a/src/hotspot/share/cds/archiveHeapWriter.cpp
+++ b/src/hotspot/share/cds/archiveHeapWriter.cpp
@@ -52,9 +52,9 @@ GrowableArrayCHeap* ArchiveHeapWriter::_buffer = nullptr;
// The following are offsets from buffer_bottom()
size_t ArchiveHeapWriter::_buffer_used;
-size_t ArchiveHeapWriter::_heap_roots_offset;
-size_t ArchiveHeapWriter::_heap_roots_word_size;
+// Heap root segments
+HeapRootSegments ArchiveHeapWriter::_heap_root_segments;
address ArchiveHeapWriter::_requested_bottom;
address ArchiveHeapWriter::_requested_top;
@@ -88,7 +88,6 @@ void ArchiveHeapWriter::init() {
_native_pointers = new GrowableArrayCHeap(2048);
_source_objs = new GrowableArrayCHeap(10000);
- guarantee(UseG1GC, "implementation limitation");
guarantee(MIN_GC_REGION_ALIGNMENT <= G1HeapRegion::min_region_size_in_words() * HeapWordSize, "must be");
}
}
@@ -164,10 +163,6 @@ address ArchiveHeapWriter::buffered_addr_to_requested_addr(address buffered_addr
return _requested_bottom + buffered_address_to_offset(buffered_addr);
}
-oop ArchiveHeapWriter::heap_roots_requested_address() {
- return cast_to_oop(_requested_bottom + _heap_roots_offset);
-}
-
address ArchiveHeapWriter::requested_address() {
assert(_buffer != nullptr, "must be initialized");
return _requested_bottom;
@@ -186,54 +181,85 @@ void ArchiveHeapWriter::ensure_buffer_space(size_t min_bytes) {
_buffer->at_grow(to_array_index(min_bytes));
}
-void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeap* roots) {
- Klass* k = Universe::objectArrayKlass(); // already relocated to point to archived klass
- int length = roots->length();
- _heap_roots_word_size = objArrayOopDesc::object_size(length);
- size_t byte_size = _heap_roots_word_size * HeapWordSize;
- if (byte_size >= MIN_GC_REGION_ALIGNMENT) {
- log_error(cds, heap)("roots array is too large. Please reduce the number of classes");
- vm_exit(1);
- }
-
- maybe_fill_gc_region_gap(byte_size);
+objArrayOop ArchiveHeapWriter::allocate_root_segment(size_t offset, int element_count) {
+ HeapWord* mem = offset_to_buffered_address(offset);
+ memset(mem, 0, objArrayOopDesc::object_size(element_count));
- size_t new_used = _buffer_used + byte_size;
- ensure_buffer_space(new_used);
+ // The initialization code is copied from MemAllocator::finish and ObjArrayAllocator::initialize.
+ oopDesc::set_mark(mem, markWord::prototype());
+ oopDesc::release_set_klass(mem, Universe::objectArrayKlass());
+ arrayOopDesc::set_length(mem, element_count);
+ return objArrayOop(cast_to_oop(mem));
+}
- HeapWord* mem = offset_to_buffered_address(_buffer_used);
- memset(mem, 0, byte_size);
- {
- // This is copied from MemAllocator::finish
- oopDesc::set_mark(mem, markWord::prototype());
- oopDesc::release_set_klass(mem, k);
- }
- {
- // This is copied from ObjArrayAllocator::initialize
- arrayOopDesc::set_length(mem, length);
+void ArchiveHeapWriter::root_segment_at_put(objArrayOop segment, int index, oop root) {
+ // Do not use arrayOop->obj_at_put(i, o) as arrayOop is outside the real heap!
+ if (UseCompressedOops) {
+ *segment->obj_at_addr(index) = CompressedOops::encode(root);
+ } else {
+ *segment->obj_at_addr(index) = root;
}
+}
- objArrayOop arrayOop = objArrayOop(cast_to_oop(mem));
- for (int i = 0; i < length; i++) {
- // Do not use arrayOop->obj_at_put(i, o) as arrayOop is outside of the real heap!
- oop o = roots->at(i);
- if (UseCompressedOops) {
- * arrayOop->obj_at_addr(i) = CompressedOops::encode(o);
- } else {
- * arrayOop->obj_at_addr(i) = o;
+void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeap* roots) {
+ // Depending on the number of classes we are archiving, a single roots array may be
+ // larger than MIN_GC_REGION_ALIGNMENT. Roots are allocated first in the buffer, which
+ // allows us to chop the large array into a series of "segments". Current layout
+ // starts with zero or more segments exactly fitting MIN_GC_REGION_ALIGNMENT, and end
+ // with a single segment that may be smaller than MIN_GC_REGION_ALIGNMENT.
+ // This is simple and efficient. We do not need filler objects anywhere between the segments,
+ // or immediately after the last segment. This allows starting the object dump immediately
+ // after the roots.
+
+ assert((_buffer_used % MIN_GC_REGION_ALIGNMENT) == 0,
+ "Pre-condition: Roots start at aligned boundary: " SIZE_FORMAT, _buffer_used);
+
+ int max_elem_count = ((MIN_GC_REGION_ALIGNMENT - arrayOopDesc::header_size_in_bytes()) / heapOopSize);
+ assert(objArrayOopDesc::object_size(max_elem_count)*HeapWordSize == MIN_GC_REGION_ALIGNMENT,
+ "Should match exactly");
+
+ HeapRootSegments segments(_buffer_used,
+ roots->length(),
+ MIN_GC_REGION_ALIGNMENT,
+ max_elem_count);
+
+ int root_index = 0;
+ for (size_t seg_idx = 0; seg_idx < segments.count(); seg_idx++) {
+ int size_elems = segments.size_in_elems(seg_idx);
+ size_t size_bytes = segments.size_in_bytes(seg_idx);
+
+ size_t oop_offset = _buffer_used;
+ _buffer_used = oop_offset + size_bytes;
+ ensure_buffer_space(_buffer_used);
+
+ assert((oop_offset % MIN_GC_REGION_ALIGNMENT) == 0,
+ "Roots segment " SIZE_FORMAT " start is not aligned: " SIZE_FORMAT,
+ segments.count(), oop_offset);
+
+ objArrayOop seg_oop = allocate_root_segment(oop_offset, size_elems);
+ for (int i = 0; i < size_elems; i++) {
+ root_segment_at_put(seg_oop, i, roots->at(root_index++));
}
+
+ log_info(cds, heap)("archived obj root segment [%d] = " SIZE_FORMAT " bytes, obj = " PTR_FORMAT,
+ size_elems, size_bytes, p2i(seg_oop));
}
- log_info(cds, heap)("archived obj roots[%d] = " SIZE_FORMAT " bytes, klass = %p, obj = %p", length, byte_size, k, mem);
- _heap_roots_offset = _buffer_used;
- _buffer_used = new_used;
+ assert(root_index == roots->length(), "Post-condition: All roots are handled");
+
+ _heap_root_segments = segments;
}
+// The goal is to sort the objects in increasing order of:
+// - objects that have only oop pointers
+// - objects that have both native and oop pointers
+// - objects that have only native pointers
+// - objects that have no pointers
static int oop_sorting_rank(oop o) {
bool has_oop_ptr, has_native_ptr;
HeapShared::get_pointer_info(o, has_oop_ptr, has_native_ptr);
- if (!has_oop_ptr) {
+ if (has_oop_ptr) {
if (!has_native_ptr) {
return 0;
} else {
@@ -248,11 +274,6 @@ static int oop_sorting_rank(oop o) {
}
}
-// The goal is to sort the objects in increasing order of:
-// - objects that have no pointers
-// - objects that have only native pointers
-// - objects that have both native and oop pointers
-// - objects that have only oop pointers
int ArchiveHeapWriter::compare_objs_by_oop_fields(HeapObjOrder* a, HeapObjOrder* b) {
int rank_a = a->_rank;
int rank_b = b->_rank;
@@ -282,6 +303,10 @@ void ArchiveHeapWriter::sort_source_objs() {
}
void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeap* roots) {
+ // There could be multiple root segments, which we want to be aligned by region.
+ // Putting them ahead of objects makes sure we waste no space.
+ copy_roots_to_buffer(roots);
+
sort_source_objs();
for (int i = 0; i < _source_objs_order->length(); i++) {
int src_obj_index = _source_objs_order->at(i)._index;
@@ -295,8 +320,6 @@ void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeapmaybe_grow();
}
- copy_roots_to_buffer(roots);
-
log_info(cds)("Size of heap region = " SIZE_FORMAT " bytes, %d objects, %d roots, %d native ptrs",
_buffer_used, _source_objs->length() + 1, roots->length(), _num_native_ptrs);
}
@@ -430,32 +453,36 @@ size_t ArchiveHeapWriter::copy_one_source_obj_to_buffer(oop src_obj) {
void ArchiveHeapWriter::set_requested_address(ArchiveHeapInfo* info) {
assert(!info->is_used(), "only set once");
- assert(UseG1GC, "must be");
- address heap_end = (address)G1CollectedHeap::heap()->reserved().end();
- log_info(cds, heap)("Heap end = %p", heap_end);
size_t heap_region_byte_size = _buffer_used;
assert(heap_region_byte_size > 0, "must archived at least one object!");
-
if (UseCompressedOops) {
- _requested_bottom = align_down(heap_end - heap_region_byte_size, G1HeapRegion::GrainBytes);
+ if (UseG1GC) {
+ address heap_end = (address)G1CollectedHeap::heap()->reserved().end();
+ log_info(cds, heap)("Heap end = %p", heap_end);
+ _requested_bottom = align_down(heap_end - heap_region_byte_size, G1HeapRegion::GrainBytes);
+ _requested_bottom = align_down(_requested_bottom, MIN_GC_REGION_ALIGNMENT);
+ assert(is_aligned(_requested_bottom, G1HeapRegion::GrainBytes), "sanity");
+ } else {
+ _requested_bottom = align_up(CompressedOops::begin(), MIN_GC_REGION_ALIGNMENT);
+ }
} else {
// We always write the objects as if the heap started at this address. This
// makes the contents of the archive heap deterministic.
//
// Note that at runtime, the heap address is selected by the OS, so the archive
// heap will not be mapped at 0x10000000, and the contents need to be patched.
- _requested_bottom = (address)NOCOOPS_REQUESTED_BASE;
+ _requested_bottom = align_up((address)NOCOOPS_REQUESTED_BASE, MIN_GC_REGION_ALIGNMENT);
}
- assert(is_aligned(_requested_bottom, G1HeapRegion::GrainBytes), "sanity");
+ assert(is_aligned(_requested_bottom, MIN_GC_REGION_ALIGNMENT), "sanity");
_requested_top = _requested_bottom + _buffer_used;
info->set_buffer_region(MemRegion(offset_to_buffered_address(0),
offset_to_buffered_address(_buffer_used)));
- info->set_heap_roots_offset(_heap_roots_offset);
+ info->set_heap_root_segments(_heap_root_segments);
}
// Oop relocation
@@ -543,12 +570,6 @@ void ArchiveHeapWriter::update_header_for_requested_obj(oop requested_obj, oop s
}
}
-// Relocate an element in the buffered copy of HeapShared::roots()
-template void ArchiveHeapWriter::relocate_root_at(oop requested_roots, int index, CHeapBitMap* oopmap) {
- size_t offset = (size_t)((objArrayOop)requested_roots)->obj_at_offset(index);
- relocate_field_in_buffer((T*)(buffered_heap_roots_addr() + offset), oopmap);
-}
-
class ArchiveHeapWriter::EmbeddedOopRelocator: public BasicOopIterateClosure {
oop _src_obj;
address _buffered_obj;
@@ -600,14 +621,24 @@ void ArchiveHeapWriter::relocate_embedded_oops(GrowableArrayCHeaplength() : 0;
- for (int i = 0; i < length; i++) {
+ for (size_t seg_idx = 0; seg_idx < _heap_root_segments.count(); seg_idx++) {
+ size_t seg_offset = _heap_root_segments.segment_offset(seg_idx);
+
+ objArrayOop requested_obj = (objArrayOop)requested_obj_from_buffer_offset(seg_offset);
+ update_header_for_requested_obj(requested_obj, nullptr, Universe::objectArrayKlass());
+ address buffered_obj = offset_to_buffered_address(seg_offset);
+ int length = _heap_root_segments.size_in_elems(seg_idx);
+
if (UseCompressedOops) {
- relocate_root_at(requested_roots, i, heap_info->oopmap());
+ for (int i = 0; i < length; i++) {
+ narrowOop* addr = (narrowOop*)(buffered_obj + objArrayOopDesc::obj_at_offset(i));
+ relocate_field_in_buffer(addr, heap_info->oopmap());
+ }
} else {
- relocate_root_at(requested_roots, i, heap_info->oopmap());
+ for (int i = 0; i < length; i++) {
+ oop* addr = (oop*)(buffered_obj + objArrayOopDesc::obj_at_offset(i));
+ relocate_field_in_buffer(addr, heap_info->oopmap());
+ }
}
}
diff --git a/src/hotspot/share/cds/archiveHeapWriter.hpp b/src/hotspot/share/cds/archiveHeapWriter.hpp
index 99d5294007f..29ea50ba5fe 100644
--- a/src/hotspot/share/cds/archiveHeapWriter.hpp
+++ b/src/hotspot/share/cds/archiveHeapWriter.hpp
@@ -41,8 +41,7 @@ class ArchiveHeapInfo {
MemRegion _buffer_region; // Contains the archived objects to be written into the CDS archive.
CHeapBitMap _oopmap;
CHeapBitMap _ptrmap;
- size_t _heap_roots_offset; // Offset of the HeapShared::roots() object, from the bottom
- // of the archived heap objects, in bytes.
+ HeapRootSegments _heap_root_segments;
public:
ArchiveHeapInfo() : _buffer_region(), _oopmap(128, mtClassShared), _ptrmap(128, mtClassShared) {}
@@ -57,8 +56,8 @@ class ArchiveHeapInfo {
CHeapBitMap* oopmap() { return &_oopmap; }
CHeapBitMap* ptrmap() { return &_ptrmap; }
- void set_heap_roots_offset(size_t n) { _heap_roots_offset = n; }
- size_t heap_roots_offset() const { return _heap_roots_offset; }
+ void set_heap_root_segments(HeapRootSegments segments) { _heap_root_segments = segments; };
+ HeapRootSegments heap_root_segments() { return _heap_root_segments; }
};
#if INCLUDE_CDS_JAVA_HEAP
@@ -112,6 +111,11 @@ class ArchiveHeapWriter : AllStatic {
public:
static const intptr_t NOCOOPS_REQUESTED_BASE = 0x10000000;
+ // The minimum region size of all collectors that are supported by CDS.
+ // G1 heap region size can never be smaller than 1M.
+ // Shenandoah heap region size can never be smaller than 256K.
+ static constexpr int MIN_GC_REGION_ALIGNMENT = 256 * K;
+
private:
class EmbeddedOopRelocator;
struct NativePointerInfo {
@@ -119,20 +123,13 @@ class ArchiveHeapWriter : AllStatic {
int _field_offset;
};
- // The minimum region size of all collectors that are supported by CDS in
- // ArchiveHeapLoader::can_map() mode. Currently only G1 is supported. G1's region size
- // depends on -Xmx, but can never be smaller than 1 * M.
- // (TODO: Perhaps change to 256K to be compatible with Shenandoah)
- static constexpr int MIN_GC_REGION_ALIGNMENT = 1 * M;
-
static GrowableArrayCHeap* _buffer;
// The number of bytes that have written into _buffer (may be smaller than _buffer->length()).
static size_t _buffer_used;
- // The bottom of the copy of Heap::roots() inside this->_buffer.
- static size_t _heap_roots_offset;
- static size_t _heap_roots_word_size;
+ // The heap root segments information.
+ static HeapRootSegments _heap_root_segments;
// The address range of the requested location of the archived heap objects.
static address _requested_bottom;
@@ -193,6 +190,8 @@ class ArchiveHeapWriter : AllStatic {
return buffered_addr - buffer_bottom();
}
+ static void root_segment_at_put(objArrayOop segment, int index, oop root);
+ static objArrayOop allocate_root_segment(size_t offset, int element_count);
static void copy_roots_to_buffer(GrowableArrayCHeap* roots);
static void copy_source_objs_to_buffer(GrowableArrayCHeap* roots);
static size_t copy_one_source_obj_to_buffer(oop src_obj);
@@ -219,7 +218,6 @@ class ArchiveHeapWriter : AllStatic {
template static T* requested_addr_to_buffered_addr(T* p);
template static void relocate_field_in_buffer(T* field_addr_in_buffer, CHeapBitMap* oopmap);
template static void mark_oop_pointer(T* buffered_addr, CHeapBitMap* oopmap);
- template static void relocate_root_at(oop requested_roots, int index, CHeapBitMap* oopmap);
static void update_header_for_requested_obj(oop requested_obj, oop src_obj, Klass* src_klass);
@@ -234,13 +232,6 @@ class ArchiveHeapWriter : AllStatic {
static bool is_string_too_large_to_archive(oop string);
static void write(GrowableArrayCHeap*, ArchiveHeapInfo* heap_info);
static address requested_address(); // requested address of the lowest achived heap object
- static oop heap_roots_requested_address(); // requested address of HeapShared::roots()
- static address buffered_heap_roots_addr() {
- return offset_to_buffered_address(_heap_roots_offset);
- }
- static size_t heap_roots_word_size() {
- return _heap_roots_word_size;
- }
static size_t get_filler_size_at(address buffered_addr);
static void mark_native_pointer(oop src_obj, int offset);
diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp
index 76cfa441fa7..4622a27cbec 100644
--- a/src/hotspot/share/cds/archiveUtils.cpp
+++ b/src/hotspot/share/cds/archiveUtils.cpp
@@ -369,3 +369,24 @@ void ArchiveUtils::log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) {
}
}
}
+
+size_t HeapRootSegments::size_in_bytes(size_t seg_idx) {
+ assert(seg_idx < _count, "In range");
+ return objArrayOopDesc::object_size(size_in_elems(seg_idx)) * HeapWordSize;
+}
+
+int HeapRootSegments::size_in_elems(size_t seg_idx) {
+ assert(seg_idx < _count, "In range");
+ if (seg_idx != _count - 1) {
+ return _max_size_in_elems;
+ } else {
+ // Last slice, leftover
+ return _roots_count % _max_size_in_elems;
+ }
+}
+
+size_t HeapRootSegments::segment_offset(size_t seg_idx) {
+ assert(seg_idx < _count, "In range");
+ return _base_offset + seg_idx * _max_size_in_bytes;
+}
+
diff --git a/src/hotspot/share/cds/archiveUtils.hpp b/src/hotspot/share/cds/archiveUtils.hpp
index 32cef97886f..5a78bc26ee6 100644
--- a/src/hotspot/share/cds/archiveUtils.hpp
+++ b/src/hotspot/share/cds/archiveUtils.hpp
@@ -250,4 +250,44 @@ class ArchiveUtils {
static void log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) NOT_CDS_RETURN;
};
+class HeapRootSegments {
+private:
+ size_t _base_offset;
+ size_t _count;
+ int _roots_count;
+ int _max_size_in_bytes;
+ int _max_size_in_elems;
+
+public:
+ size_t base_offset() { return _base_offset; }
+ size_t count() { return _count; }
+ int roots_count() { return _roots_count; }
+ int max_size_in_bytes() { return _max_size_in_bytes; }
+ int max_size_in_elems() { return _max_size_in_elems; }
+
+ size_t size_in_bytes(size_t seg_idx);
+ int size_in_elems(size_t seg_idx);
+ size_t segment_offset(size_t seg_idx);
+
+ // Trivial copy assignments are allowed to copy the entire object representation.
+ // We also inline this class into archive header. Therefore, it is important to make
+ // sure any gaps in object representation are initialized to zeroes. This is why
+ // constructors memset before doing field assignments.
+ HeapRootSegments() {
+ memset(this, 0, sizeof(*this));
+ }
+ HeapRootSegments(size_t base_offset, int roots_count, int max_size_in_bytes, int max_size_in_elems) {
+ memset(this, 0, sizeof(*this));
+ _base_offset = base_offset;
+ _count = (roots_count + max_size_in_elems - 1) / max_size_in_elems;
+ _roots_count = roots_count;
+ _max_size_in_bytes = max_size_in_bytes;
+ _max_size_in_elems = max_size_in_elems;
+ }
+
+ // This class is trivially copyable and assignable.
+ HeapRootSegments(const HeapRootSegments&) = default;
+ HeapRootSegments& operator=(const HeapRootSegments&) = default;
+};
+
#endif // SHARE_CDS_ARCHIVEUTILS_HPP
diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp
index a0a562eca21..5915424c4fe 100644
--- a/src/hotspot/share/cds/cdsConfig.cpp
+++ b/src/hotspot/share/cds/cdsConfig.cpp
@@ -236,7 +236,7 @@ void CDSConfig::init_shared_archive_paths() {
}
void CDSConfig::check_internal_module_property(const char* key, const char* value) {
- if (Arguments::is_internal_module_property(key)) {
+ if (Arguments::is_internal_module_property(key) && !Arguments::is_module_path_property(key)) {
stop_using_optimized_module_handling();
log_info(cds)("optimized module handling: disabled due to incompatible property: %s=%s", key, value);
}
diff --git a/src/hotspot/share/cds/cdsProtectionDomain.cpp b/src/hotspot/share/cds/cdsProtectionDomain.cpp
index a4ffeea26dc..2eb47ff2788 100644
--- a/src/hotspot/share/cds/cdsProtectionDomain.cpp
+++ b/src/hotspot/share/cds/cdsProtectionDomain.cpp
@@ -199,17 +199,9 @@ Handle CDSProtectionDomain::get_shared_jar_manifest(int shared_path_index, TRAPS
Handle CDSProtectionDomain::get_shared_jar_url(int shared_path_index, TRAPS) {
Handle url_h;
if (shared_jar_url(shared_path_index) == nullptr) {
- JavaValue result(T_OBJECT);
const char* path = FileMapInfo::shared_path_name(shared_path_index);
- Handle path_string = java_lang_String::create_from_str(path, CHECK_(url_h));
- Klass* classLoaders_klass =
- vmClasses::jdk_internal_loader_ClassLoaders_klass();
- JavaCalls::call_static(&result, classLoaders_klass,
- vmSymbols::toFileURL_name(),
- vmSymbols::toFileURL_signature(),
- path_string, CHECK_(url_h));
-
- atomic_set_shared_jar_url(shared_path_index, result.get_oop());
+ oop result_oop = to_file_URL(path, url_h, CHECK_(url_h));
+ atomic_set_shared_jar_url(shared_path_index, result_oop);
}
url_h = Handle(THREAD, shared_jar_url(shared_path_index));
@@ -217,6 +209,17 @@ Handle CDSProtectionDomain::get_shared_jar_url(int shared_path_index, TRAPS) {
return url_h;
}
+oop CDSProtectionDomain::to_file_URL(const char* path, Handle url_h, TRAPS) {
+ JavaValue result(T_OBJECT);
+ Handle path_string = java_lang_String::create_from_str(path, CHECK_NULL);
+ JavaCalls::call_static(&result,
+ vmClasses::jdk_internal_loader_ClassLoaders_klass(),
+ vmSymbols::toFileURL_name(),
+ vmSymbols::toFileURL_signature(),
+ path_string, CHECK_NULL);
+ return result.get_oop();
+}
+
// Get the ProtectionDomain associated with the CodeSource from the classloader.
Handle CDSProtectionDomain::get_protection_domain_from_classloader(Handle class_loader,
Handle url, TRAPS) {
diff --git a/src/hotspot/share/cds/cdsProtectionDomain.hpp b/src/hotspot/share/cds/cdsProtectionDomain.hpp
index 0e688fcfa00..baab4ab0e72 100644
--- a/src/hotspot/share/cds/cdsProtectionDomain.hpp
+++ b/src/hotspot/share/cds/cdsProtectionDomain.hpp
@@ -80,6 +80,7 @@ class CDSProtectionDomain : AllStatic {
static Handle create_jar_manifest(const char* man, size_t size, TRAPS);
static Handle get_shared_jar_manifest(int shared_path_index, TRAPS);
static Handle get_shared_jar_url(int shared_path_index, TRAPS);
+ static oop to_file_URL(const char* path, Handle url_h, TRAPS);
static Handle get_protection_domain_from_classloader(Handle class_loader,
Handle url, TRAPS);
static Handle get_shared_protection_domain(Handle class_loader,
diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp
index b2695ac2e78..694a179d7ee 100644
--- a/src/hotspot/share/cds/classListParser.cpp
+++ b/src/hotspot/share/cds/classListParser.cpp
@@ -463,7 +463,7 @@ void ClassListParser::check_class_name(const char* class_name) {
err = "class name too long";
} else {
assert(Symbol::max_length() < INT_MAX && len < INT_MAX, "must be");
- if (!UTF8::is_legal_utf8((const unsigned char*)class_name, (int)len, /*version_leq_47*/false)) {
+ if (!UTF8::is_legal_utf8((const unsigned char*)class_name, len, /*version_leq_47*/false)) {
err = "class name is not valid UTF8";
}
}
@@ -508,7 +508,9 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
}
- InstanceKlass* k = UnregisteredClasses::load_class(class_name, _source, CHECK_NULL);
+ ResourceMark rm;
+ char * source_path = os::strdup_check_oom(ClassLoader::uri_to_path(_source));
+ InstanceKlass* k = UnregisteredClasses::load_class(class_name, source_path, CHECK_NULL);
if (k->local_interfaces()->length() != _interfaces->length()) {
print_specified_interfaces();
print_actual_interfaces(k);
@@ -849,4 +851,3 @@ void ClassListParser::parse_constant_pool_tag() {
ClassPrelinker::preresolve_field_and_method_cp_entries(THREAD, ik, &preresolve_list);
}
}
-
diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp
index 78cd092445b..1b9f589f1c5 100644
--- a/src/hotspot/share/cds/classListWriter.cpp
+++ b/src/hotspot/share/cds/classListWriter.cpp
@@ -174,6 +174,8 @@ void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stre
}
}
+ // NB: the string following "source: " is not really a proper file name, but rather
+ // a truncated URI referring to a file. It must be decoded after reading.
#ifdef _WINDOWS
// "file:/C:/dir/foo.jar" -> "C:/dir/foo.jar"
stream->print(" source: %s", cfs->source() + 6);
diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp
index 96c826fb67e..715fce5f3fc 100644
--- a/src/hotspot/share/cds/filemap.cpp
+++ b/src/hotspot/share/cds/filemap.cpp
@@ -268,7 +268,6 @@ void FileMapHeader::print(outputStream* st) {
st->print_cr("- core_region_alignment: " SIZE_FORMAT, _core_region_alignment);
st->print_cr("- obj_alignment: %d", _obj_alignment);
st->print_cr("- narrow_oop_base: " INTPTR_FORMAT, p2i(_narrow_oop_base));
- st->print_cr("- narrow_oop_base: " INTPTR_FORMAT, p2i(_narrow_oop_base));
st->print_cr("- narrow_oop_shift %d", _narrow_oop_shift);
st->print_cr("- compact_strings: %d", _compact_strings);
st->print_cr("- max_heap_size: " UINTX_FORMAT, _max_heap_size);
@@ -290,7 +289,11 @@ void FileMapHeader::print(outputStream* st) {
st->print_cr("- has_non_jar_in_classpath: %d", _has_non_jar_in_classpath);
st->print_cr("- requested_base_address: " INTPTR_FORMAT, p2i(_requested_base_address));
st->print_cr("- mapped_base_address: " INTPTR_FORMAT, p2i(_mapped_base_address));
- st->print_cr("- heap_roots_offset: " SIZE_FORMAT, _heap_roots_offset);
+ st->print_cr("- heap_root_segments.roots_count: %d" , _heap_root_segments.roots_count());
+ st->print_cr("- heap_root_segments.base_offset: " SIZE_FORMAT_X, _heap_root_segments.base_offset());
+ st->print_cr("- heap_root_segments.count: " SIZE_FORMAT, _heap_root_segments.count());
+ st->print_cr("- heap_root_segments.max_size_elems: %d", _heap_root_segments.max_size_in_elems());
+ st->print_cr("- heap_root_segments.max_size_bytes: %d", _heap_root_segments.max_size_in_bytes());
st->print_cr("- _heap_oopmap_start_pos: " SIZE_FORMAT, _heap_oopmap_start_pos);
st->print_cr("- _heap_ptrmap_start_pos: " SIZE_FORMAT, _heap_ptrmap_start_pos);
st->print_cr("- _rw_ptrmap_start_pos: " SIZE_FORMAT, _rw_ptrmap_start_pos);
@@ -578,7 +581,7 @@ int FileMapInfo::get_module_shared_path_index(Symbol* location) {
// skip_uri_protocol was also called during dump time -- see ClassLoaderExt::process_module_table()
ResourceMark rm;
- const char* file = ClassLoader::skip_uri_protocol(location->as_C_string());
+ const char* file = ClassLoader::uri_to_path(location->as_C_string());
for (int i = ClassLoaderExt::app_module_paths_start_index(); i < get_number_of_shared_paths(); i++) {
SharedClassPathEntry* ent = shared_path(i);
if (!ent->is_non_existent()) {
@@ -778,12 +781,12 @@ bool FileMapInfo::check_paths(int shared_path_start_idx, int num_paths, Growable
assert(strlen(rp_array->at(i)) > (size_t)runtime_prefix_len, "sanity");
const char* runtime_path = rp_array->at(i) + runtime_prefix_len;
if (!os::same_files(dumptime_path, runtime_path)) {
- return true;
+ return false;
}
i++;
j++;
}
- return false;
+ return true;
}
bool FileMapInfo::validate_boot_class_paths() {
@@ -807,7 +810,7 @@ bool FileMapInfo::validate_boot_class_paths() {
char* rp = skip_first_path_entry(runtime_boot_path);
assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image");
int dp_len = header()->app_class_paths_start_index() - 1; // ignore the first path to the module image
- bool mismatch = false;
+ bool match = true;
bool relaxed_check = !header()->has_platform_or_app_classes();
if (dp_len == 0 && rp == nullptr) {
@@ -820,7 +823,7 @@ bool FileMapInfo::validate_boot_class_paths() {
if (check_paths_existence(rp)) {
// If a path exists in the runtime boot paths, it is considered a mismatch
// since there's no boot path specified during dump time.
- mismatch = true;
+ match = false;
}
}
} else if (dp_len > 0 && rp != nullptr) {
@@ -837,16 +840,16 @@ bool FileMapInfo::validate_boot_class_paths() {
// check the full runtime boot path, must match with dump time
num = rp_len;
}
- mismatch = check_paths(1, num, rp_array, 0, 0);
+ match = check_paths(1, num, rp_array, 0, 0);
} else {
// create_path_array() ignores non-existing paths. Although the dump time and runtime boot classpath lengths
// are the same initially, after the call to create_path_array(), the runtime boot classpath length could become
// shorter. We consider boot classpath mismatch in this case.
- mismatch = true;
+ match = false;
}
}
- if (mismatch) {
+ if (!match) {
// The paths are different
return classpath_failure("[BOOT classpath mismatch, actual =", runtime_boot_path);
}
@@ -857,7 +860,7 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) {
const char *appcp = Arguments::get_appclasspath();
assert(appcp != nullptr, "null app classpath");
int rp_len = num_paths(appcp);
- bool mismatch = false;
+ bool match = false;
if (rp_len < shared_app_paths_len) {
return classpath_failure("Run time APP classpath is shorter than the one at dump time: ", appcp);
}
@@ -886,8 +889,8 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) {
// run 2: -cp x.jar:NE4:b.jar -> x.jar:b.jar -> mismatched
int j = header()->app_class_paths_start_index();
- mismatch = check_paths(j, shared_app_paths_len, rp_array, 0, 0);
- if (mismatch) {
+ match = check_paths(j, shared_app_paths_len, rp_array, 0, 0);
+ if (!match) {
// To facilitate app deployment, we allow the JAR files to be moved *together* to
// a different location, as long as they are still stored under the same directory
// structure. E.g., the following is OK.
@@ -898,10 +901,10 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) {
if (dumptime_prefix_len != 0 || runtime_prefix_len != 0) {
log_info(class, path)("LCP length for app classpath (dumptime: %u, runtime: %u)",
dumptime_prefix_len, runtime_prefix_len);
- mismatch = check_paths(j, shared_app_paths_len, rp_array,
+ match = check_paths(j, shared_app_paths_len, rp_array,
dumptime_prefix_len, runtime_prefix_len);
}
- if (mismatch) {
+ if (!match) {
return classpath_failure("[APP classpath mismatch, actual: -Djava.class.path=", appcp);
}
}
@@ -923,15 +926,35 @@ void FileMapInfo::log_paths(const char* msg, int start_idx, int end_idx) {
}
}
+void FileMapInfo::extract_module_paths(const char* runtime_path, GrowableArray* module_paths) {
+ GrowableArray* path_array = create_path_array(runtime_path);
+ int num_paths = path_array->length();
+ for (int i = 0; i < num_paths; i++) {
+ const char* name = path_array->at(i);
+ ClassLoaderExt::extract_jar_files_from_path(name, module_paths);
+ }
+ // module paths are stored in sorted order in the CDS archive.
+ module_paths->sort(ClassLoaderExt::compare_module_path_by_name);
+}
+
bool FileMapInfo::check_module_paths() {
- const char* rp = Arguments::get_property("jdk.module.path");
- int num_paths = CDSConfig::num_archives(rp);
- if (num_paths != header()->num_module_paths()) {
+ const char* runtime_path = Arguments::get_property("jdk.module.path");
+ int archived_num_module_paths = header()->num_module_paths();
+ if (runtime_path == nullptr && archived_num_module_paths == 0) {
+ return true;
+ }
+ if ((runtime_path == nullptr && archived_num_module_paths > 0) ||
+ (runtime_path != nullptr && archived_num_module_paths == 0)) {
return false;
}
ResourceMark rm;
- GrowableArray* rp_array = create_path_array(rp);
- return check_paths(header()->app_module_paths_start_index(), num_paths, rp_array, 0, 0);
+ GrowableArray* module_paths = new GrowableArray(3);
+ extract_module_paths(runtime_path, module_paths);
+ int num_paths = module_paths->length();
+ if (num_paths != archived_num_module_paths) {
+ return false;
+ }
+ return check_paths(header()->app_module_paths_start_index(), num_paths, module_paths, 0, 0);
}
bool FileMapInfo::validate_shared_path_table() {
@@ -941,6 +964,16 @@ bool FileMapInfo::validate_shared_path_table() {
// Load the shared path table info from the archive header
_shared_path_table = header()->shared_path_table();
+
+ bool matched_module_paths = true;
+ if (CDSConfig::is_dumping_dynamic_archive() || header()->has_full_module_graph()) {
+ matched_module_paths = check_module_paths();
+ }
+ if (header()->has_full_module_graph() && !matched_module_paths) {
+ CDSConfig::stop_using_optimized_module_handling();
+ log_info(cds)("optimized module handling: disabled because of mismatched module paths");
+ }
+
if (CDSConfig::is_dumping_dynamic_archive()) {
// Only support dynamic dumping with the usage of the default CDS archive
// or a simple base archive.
@@ -956,7 +989,7 @@ bool FileMapInfo::validate_shared_path_table() {
"Dynamic archiving is disabled because base layer archive has appended boot classpath");
}
if (header()->num_module_paths() > 0) {
- if (!check_module_paths()) {
+ if (!matched_module_paths) {
CDSConfig::disable_dumping_dynamic_archive();
log_warning(cds)(
"Dynamic archiving is disabled because base layer archive has a different module path");
@@ -1578,39 +1611,38 @@ static size_t write_bitmap(const CHeapBitMap* map, char* output, size_t offset)
return offset + size_in_bytes;
}
-// The start of the archived heap has many primitive arrays (String
-// bodies) that are not marked by the oop/ptr maps. So we must have
-// lots of leading zeros.
-size_t FileMapInfo::remove_bitmap_leading_zeros(CHeapBitMap* map) {
- size_t old_zeros = map->find_first_set_bit(0);
+// The sorting code groups the objects with non-null oop/ptrs together.
+// Relevant bitmaps then have lots of leading and trailing zeros, which
+// we do not have to store.
+size_t FileMapInfo::remove_bitmap_zeros(CHeapBitMap* map) {
+ BitMap::idx_t first_set = map->find_first_set_bit(0);
+ BitMap::idx_t last_set = map->find_last_set_bit(0);
size_t old_size = map->size();
// Slice and resize bitmap
- map->truncate(old_zeros, map->size());
+ map->truncate(first_set, last_set + 1);
- DEBUG_ONLY(
- size_t new_zeros = map->find_first_set_bit(0);
- assert(new_zeros == 0, "Should have removed leading zeros");
- )
+ assert(map->at(0), "First bit should be set");
+ assert(map->at(map->size() - 1), "Last bit should be set");
assert(map->size() <= old_size, "sanity");
- return old_zeros;
+
+ return first_set;
}
char* FileMapInfo::write_bitmap_region(CHeapBitMap* rw_ptrmap, CHeapBitMap* ro_ptrmap, ArchiveHeapInfo* heap_info,
size_t &size_in_bytes) {
- size_t removed_rw_zeros = remove_bitmap_leading_zeros(rw_ptrmap);
- size_t removed_ro_zeros = remove_bitmap_leading_zeros(ro_ptrmap);
- header()->set_rw_ptrmap_start_pos(removed_rw_zeros);
- header()->set_ro_ptrmap_start_pos(removed_ro_zeros);
+ size_t removed_rw_leading_zeros = remove_bitmap_zeros(rw_ptrmap);
+ size_t removed_ro_leading_zeros = remove_bitmap_zeros(ro_ptrmap);
+ header()->set_rw_ptrmap_start_pos(removed_rw_leading_zeros);
+ header()->set_ro_ptrmap_start_pos(removed_ro_leading_zeros);
size_in_bytes = rw_ptrmap->size_in_bytes() + ro_ptrmap->size_in_bytes();
if (heap_info->is_used()) {
- // Remove leading zeros
- size_t removed_oop_zeros = remove_bitmap_leading_zeros(heap_info->oopmap());
- size_t removed_ptr_zeros = remove_bitmap_leading_zeros(heap_info->ptrmap());
-
- header()->set_heap_oopmap_start_pos(removed_oop_zeros);
- header()->set_heap_ptrmap_start_pos(removed_ptr_zeros);
+ // Remove leading and trailing zeros
+ size_t removed_oop_leading_zeros = remove_bitmap_zeros(heap_info->oopmap());
+ size_t removed_ptr_leading_zeros = remove_bitmap_zeros(heap_info->ptrmap());
+ header()->set_heap_oopmap_start_pos(removed_oop_leading_zeros);
+ header()->set_heap_ptrmap_start_pos(removed_ptr_leading_zeros);
size_in_bytes += heap_info->oopmap()->size_in_bytes();
size_in_bytes += heap_info->ptrmap()->size_in_bytes();
@@ -1648,7 +1680,7 @@ size_t FileMapInfo::write_heap_region(ArchiveHeapInfo* heap_info) {
char* buffer_start = heap_info->buffer_start();
size_t buffer_size = heap_info->buffer_byte_size();
write_region(MetaspaceShared::hp, buffer_start, buffer_size, false, false);
- header()->set_heap_roots_offset(heap_info->heap_roots_offset());
+ header()->set_heap_root_segments(heap_info->heap_root_segments());
return buffer_size;
}
@@ -1713,10 +1745,10 @@ void FileMapInfo::close() {
*/
static char* map_memory(int fd, const char* file_name, size_t file_offset,
char *addr, size_t bytes, bool read_only,
- bool allow_exec, MEMFLAGS flags = mtNone) {
+ bool allow_exec, MemTag mem_tag = mtNone) {
char* mem = os::map_memory(fd, file_name, file_offset, addr, bytes,
AlwaysPreTouch ? false : read_only,
- allow_exec, flags);
+ allow_exec, mem_tag);
if (mem != nullptr && AlwaysPreTouch) {
os::pretouch_memory(mem, mem + bytes);
}
@@ -2025,7 +2057,7 @@ void FileMapInfo::map_or_load_heap_region() {
// TODO - remove implicit knowledge of G1
log_info(cds)("Cannot use CDS heap data. UseG1GC is required for -XX:-UseCompressedOops");
} else {
- log_info(cds)("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC or UseParallelGC are required.");
+ log_info(cds)("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC, UseParallelGC, or UseShenandoahGC are required.");
}
}
}
@@ -2175,24 +2207,38 @@ bool FileMapInfo::map_heap_region_impl() {
_mapped_heap_memregion = MemRegion(start, word_size);
- // Map the archived heap data. No need to call MemTracker::record_virtual_memory_type()
+ // Map the archived heap data. No need to call MemTracker::record_virtual_memory_tag()
// for mapped region as it is part of the reserved java heap, which is already recorded.
char* addr = (char*)_mapped_heap_memregion.start();
- char* base = map_memory(_fd, _full_path, r->file_offset(),
- addr, _mapped_heap_memregion.byte_size(), r->read_only(),
- r->allow_exec());
- if (base == nullptr || base != addr) {
- dealloc_heap_region();
- log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap. "
- INTPTR_FORMAT ", size = " SIZE_FORMAT " bytes",
- p2i(addr), _mapped_heap_memregion.byte_size());
- return false;
- }
+ char* base;
- if (VerifySharedSpaces && !r->check_region_crc(base)) {
- dealloc_heap_region();
- log_info(cds)("UseSharedSpaces: mapped heap region is corrupt");
- return false;
+ if (MetaspaceShared::use_windows_memory_mapping()) {
+ if (!read_region(MetaspaceShared::hp, addr,
+ align_up(_mapped_heap_memregion.byte_size(), os::vm_page_size()),
+ /* do_commit = */ true)) {
+ dealloc_heap_region();
+ log_error(cds)("Failed to read archived heap region into " INTPTR_FORMAT, p2i(addr));
+ return false;
+ }
+ // Checks for VerifySharedSpaces is already done inside read_region()
+ base = addr;
+ } else {
+ base = map_memory(_fd, _full_path, r->file_offset(),
+ addr, _mapped_heap_memregion.byte_size(), r->read_only(),
+ r->allow_exec());
+ if (base == nullptr || base != addr) {
+ dealloc_heap_region();
+ log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap. "
+ INTPTR_FORMAT ", size = " SIZE_FORMAT " bytes",
+ p2i(addr), _mapped_heap_memregion.byte_size());
+ return false;
+ }
+
+ if (VerifySharedSpaces && !r->check_region_crc(base)) {
+ dealloc_heap_region();
+ log_info(cds)("UseSharedSpaces: mapped heap region is corrupt");
+ return false;
+ }
}
r->set_mapped_base(base);
diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp
index 7b10c16920b..6650f524408 100644
--- a/src/hotspot/share/cds/filemap.hpp
+++ b/src/hotspot/share/cds/filemap.hpp
@@ -25,6 +25,7 @@
#ifndef SHARE_CDS_FILEMAP_HPP
#define SHARE_CDS_FILEMAP_HPP
+#include "cds/archiveUtils.hpp"
#include "cds/metaspaceShared.hpp"
#include "include/cds.h"
#include "logging/logLevel.hpp"
@@ -225,8 +226,7 @@ class FileMapHeader: private CDSFileMapHeaderBase {
bool _use_optimized_module_handling;// No module-relation VM options were specified, so we can skip
// some expensive operations.
bool _has_full_module_graph; // Does this CDS archive contain the full archived module graph?
- size_t _heap_roots_offset; // Offset of the HeapShared::roots() object, from the bottom
- // of the archived heap objects, in bytes.
+ HeapRootSegments _heap_root_segments; // Heap root segments info
size_t _heap_oopmap_start_pos; // The first bit in the oopmap corresponds to this position in the heap.
size_t _heap_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the heap.
size_t _rw_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the rw region
@@ -270,7 +270,8 @@ class FileMapHeader: private CDSFileMapHeaderBase {
bool has_non_jar_in_classpath() const { return _has_non_jar_in_classpath; }
bool compressed_oops() const { return _compressed_oops; }
bool compressed_class_pointers() const { return _compressed_class_ptrs; }
- size_t heap_roots_offset() const { return _heap_roots_offset; }
+ HeapRootSegments heap_root_segments() const { return _heap_root_segments; }
+ bool has_full_module_graph() const { return _has_full_module_graph; }
size_t heap_oopmap_start_pos() const { return _heap_oopmap_start_pos; }
size_t heap_ptrmap_start_pos() const { return _heap_ptrmap_start_pos; }
size_t rw_ptrmap_start_pos() const { return _rw_ptrmap_start_pos; }
@@ -285,7 +286,7 @@ class FileMapHeader: private CDSFileMapHeaderBase {
void set_cloned_vtables(char* p) { set_as_offset(p, &_cloned_vtables_offset); }
void set_serialized_data(char* p) { set_as_offset(p, &_serialized_data_offset); }
void set_mapped_base_address(char* p) { _mapped_base_address = p; }
- void set_heap_roots_offset(size_t n) { _heap_roots_offset = n; }
+ void set_heap_root_segments(HeapRootSegments segments) { _heap_root_segments = segments; }
void set_heap_oopmap_start_pos(size_t n) { _heap_oopmap_start_pos = n; }
void set_heap_ptrmap_start_pos(size_t n) { _heap_ptrmap_start_pos = n; }
void set_rw_ptrmap_start_pos(size_t n) { _rw_ptrmap_start_pos = n; }
@@ -385,7 +386,7 @@ class FileMapInfo : public CHeapObj {
address narrow_oop_base() const { return header()->narrow_oop_base(); }
int narrow_oop_shift() const { return header()->narrow_oop_shift(); }
uintx max_heap_size() const { return header()->max_heap_size(); }
- size_t heap_roots_offset() const { return header()->heap_roots_offset(); }
+ HeapRootSegments heap_root_segments() const { return header()->heap_root_segments(); }
size_t core_region_alignment() const { return header()->core_region_alignment(); }
size_t heap_oopmap_start_pos() const { return header()->heap_oopmap_start_pos(); }
size_t heap_ptrmap_start_pos() const { return header()->heap_ptrmap_start_pos(); }
@@ -445,7 +446,7 @@ class FileMapInfo : public CHeapObj {
void write_header();
void write_region(int region, char* base, size_t size,
bool read_only, bool allow_exec);
- size_t remove_bitmap_leading_zeros(CHeapBitMap* map);
+ size_t remove_bitmap_zeros(CHeapBitMap* map);
char* write_bitmap_region(CHeapBitMap* rw_ptrmap, CHeapBitMap* ro_ptrmap, ArchiveHeapInfo* heap_info,
size_t &size_in_bytes);
size_t write_heap_region(ArchiveHeapInfo* heap_info);
@@ -554,6 +555,7 @@ class FileMapInfo : public CHeapObj {
GrowableArray* rp_array,
unsigned int dumptime_prefix_len,
unsigned int runtime_prefix_len) NOT_CDS_RETURN_(false);
+ void extract_module_paths(const char* runtime_path, GrowableArray* module_paths);
bool validate_boot_class_paths() NOT_CDS_RETURN_(false);
bool validate_app_class_paths(int shared_app_paths_len) NOT_CDS_RETURN_(false);
bool map_heap_region_impl() NOT_CDS_JAVA_HEAP_RETURN_(false);
diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp
index ff84ddc13fc..22040448770 100644
--- a/src/hotspot/share/cds/heapShared.cpp
+++ b/src/hotspot/share/cds/heapShared.cpp
@@ -33,6 +33,7 @@
#include "cds/heapShared.hpp"
#include "cds/metaspaceShared.hpp"
#include "classfile/classLoaderData.hpp"
+#include "classfile/classLoaderExt.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/modules.hpp"
#include "classfile/stringTable.hpp"
@@ -55,6 +56,7 @@
#include "oops/oop.inline.hpp"
#include "oops/typeArrayOop.inline.hpp"
#include "prims/jvmtiExport.hpp"
+#include "runtime/arguments.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/javaCalls.hpp"
@@ -133,7 +135,8 @@ static ArchivableStaticFieldInfo fmg_archive_subgraph_entry_fields[] = {
KlassSubGraphInfo* HeapShared::_default_subgraph_info;
GrowableArrayCHeap* HeapShared::_pending_roots = nullptr;
-OopHandle HeapShared::_roots;
+GrowableArrayCHeap* HeapShared::_root_segments;
+int HeapShared::_root_segment_max_size_elems;
OopHandle HeapShared::_scratch_basic_type_mirrors[T_VOID+1];
MetaspaceObjToOopHandleTable* HeapShared::_scratch_java_mirror_table = nullptr;
MetaspaceObjToOopHandleTable* HeapShared::_scratch_references_table = nullptr;
@@ -225,7 +228,7 @@ int HeapShared::append_root(oop obj) {
return _pending_roots->append(obj);
}
-objArrayOop HeapShared::roots() {
+objArrayOop HeapShared::root_segment(int segment_idx) {
if (CDSConfig::is_dumping_heap()) {
assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread");
if (!HeapShared::can_write()) {
@@ -235,17 +238,35 @@ objArrayOop HeapShared::roots() {
assert(CDSConfig::is_using_archive(), "must be");
}
- objArrayOop roots = (objArrayOop)_roots.resolve();
- assert(roots != nullptr, "should have been initialized");
- return roots;
+ objArrayOop segment = (objArrayOop)_root_segments->at(segment_idx).resolve();
+ assert(segment != nullptr, "should have been initialized");
+ return segment;
+}
+
+void HeapShared::get_segment_indexes(int idx, int& seg_idx, int& int_idx) {
+ assert(_root_segment_max_size_elems > 0, "sanity");
+
+ // Try to avoid divisions for the common case.
+ if (idx < _root_segment_max_size_elems) {
+ seg_idx = 0;
+ int_idx = idx;
+ } else {
+ seg_idx = idx / _root_segment_max_size_elems;
+ int_idx = idx % _root_segment_max_size_elems;
+ }
+
+ assert(idx == seg_idx * _root_segment_max_size_elems + int_idx,
+ "sanity: %d index maps to %d segment and %d internal", idx, seg_idx, int_idx);
}
// Returns an objArray that contains all the roots of the archived objects
oop HeapShared::get_root(int index, bool clear) {
assert(index >= 0, "sanity");
assert(!CDSConfig::is_dumping_heap() && CDSConfig::is_using_archive(), "runtime only");
- assert(!_roots.is_empty(), "must have loaded shared heap");
- oop result = roots()->obj_at(index);
+ assert(!_root_segments->is_empty(), "must have loaded shared heap");
+ int seg_idx, int_idx;
+ get_segment_indexes(index, seg_idx, int_idx);
+ oop result = root_segment(seg_idx)->obj_at(int_idx);
if (clear) {
clear_root(index);
}
@@ -256,11 +277,13 @@ void HeapShared::clear_root(int index) {
assert(index >= 0, "sanity");
assert(CDSConfig::is_using_archive(), "must be");
if (ArchiveHeapLoader::is_in_use()) {
+ int seg_idx, int_idx;
+ get_segment_indexes(index, seg_idx, int_idx);
if (log_is_enabled(Debug, cds, heap)) {
- oop old = roots()->obj_at(index);
+ oop old = root_segment(seg_idx)->obj_at(int_idx);
log_debug(cds, heap)("Clearing root %d: was " PTR_FORMAT, index, p2i(old));
}
- roots()->obj_at_put(index, nullptr);
+ root_segment(seg_idx)->obj_at_put(int_idx, nullptr);
}
}
@@ -363,6 +386,13 @@ void HeapShared::set_scratch_java_mirror(Klass* k, oop mirror) {
}
void HeapShared::remove_scratch_objects(Klass* k) {
+ // Klass is being deallocated. Java mirror can still be alive, and it should not
+ // point to dead klass. We need to break the link from mirror to the Klass.
+ // See how InstanceKlass::deallocate_contents does it for normal mirrors.
+ oop mirror = _scratch_java_mirror_table->get_oop(k);
+ if (mirror != nullptr) {
+ java_lang_Class::set_klass(mirror, nullptr);
+ }
_scratch_java_mirror_table->remove_oop(k);
if (k->is_instance_klass()) {
_scratch_references_table->remove(InstanceKlass::cast(k)->constants());
@@ -461,11 +491,13 @@ void HeapShared::archive_objects(ArchiveHeapInfo *heap_info) {
// Cache for recording where the archived objects are copied to
create_archived_object_cache();
- log_info(cds)("Heap range = [" PTR_FORMAT " - " PTR_FORMAT "]",
- UseCompressedOops ? p2i(CompressedOops::begin()) :
- p2i((address)G1CollectedHeap::heap()->reserved().start()),
- UseCompressedOops ? p2i(CompressedOops::end()) :
- p2i((address)G1CollectedHeap::heap()->reserved().end()));
+ if (UseCompressedOops || UseG1GC) {
+ log_info(cds)("Heap range = [" PTR_FORMAT " - " PTR_FORMAT "]",
+ UseCompressedOops ? p2i(CompressedOops::begin()) :
+ p2i((address)G1CollectedHeap::heap()->reserved().start()),
+ UseCompressedOops ? p2i(CompressedOops::end()) :
+ p2i((address)G1CollectedHeap::heap()->reserved().end()));
+ }
copy_objects();
CDSHeapVerifier::verify();
@@ -764,11 +796,17 @@ void HeapShared::write_subgraph_info_table() {
}
}
-void HeapShared::init_roots(oop roots_oop) {
- if (roots_oop != nullptr) {
- assert(ArchiveHeapLoader::is_in_use(), "must be");
- _roots = OopHandle(Universe::vm_global(), roots_oop);
+void HeapShared::add_root_segment(objArrayOop segment_oop) {
+ assert(segment_oop != nullptr, "must be");
+ assert(ArchiveHeapLoader::is_in_use(), "must be");
+ if (_root_segments == nullptr) {
+ _root_segments = new GrowableArrayCHeap(10);
}
+ _root_segments->push(OopHandle(Universe::vm_global(), segment_oop));
+}
+
+void HeapShared::init_root_segment_sizes(int max_size_elems) {
+ _root_segment_max_size_elems = max_size_elems;
}
void HeapShared::serialize_tables(SerializeClosure* soc) {
@@ -855,6 +893,17 @@ void HeapShared::initialize_from_archived_subgraph(JavaThread* current, Klass* k
return; // nothing to do
}
+ if (k->name()->equals("jdk/internal/module/ArchivedModuleGraph") &&
+ !CDSConfig::is_using_optimized_module_handling() &&
+ // archive was created with --module-path
+ ClassLoaderExt::num_module_paths() > 0) {
+ // ArchivedModuleGraph was created with a --module-path that's different than the runtime --module-path.
+ // Thus, it might contain references to modules that do not exist at runtime. We cannot use it.
+ log_info(cds, heap)("Skip initializing ArchivedModuleGraph subgraph: is_using_optimized_module_handling=%s num_module_paths=%d",
+ BOOL_TO_STR(CDSConfig::is_using_optimized_module_handling()), ClassLoaderExt::num_module_paths());
+ return;
+ }
+
ExceptionMark em(THREAD);
const ArchivedKlassSubGraphInfoRecord* record =
resolve_or_init_classes_for_subgraph_of(k, /*do_init=*/true, THREAD);
@@ -1103,6 +1152,13 @@ bool HeapShared::archive_reachable_objects_from(int level,
// these objects that are referenced (directly or indirectly) by static fields.
ResourceMark rm;
log_error(cds, heap)("Cannot archive object of class %s", orig_obj->klass()->external_name());
+ if (log_is_enabled(Trace, cds, heap)) {
+ WalkOopAndArchiveClosure* walker = WalkOopAndArchiveClosure::current();
+ if (walker != nullptr) {
+ LogStream ls(Log(cds, heap)::trace());
+ CDSHeapVerifier::trace_to_root(&ls, walker->referencing_obj());
+ }
+ }
MetaspaceShared::unrecoverable_writing_error();
}
@@ -1304,6 +1360,9 @@ void HeapShared::check_default_subgraph_classes() {
name == vmSymbols::java_lang_ArithmeticException() ||
name == vmSymbols::java_lang_NullPointerException() ||
name == vmSymbols::java_lang_InternalError() ||
+ name == vmSymbols::java_lang_ArrayIndexOutOfBoundsException() ||
+ name == vmSymbols::java_lang_ArrayStoreException() ||
+ name == vmSymbols::java_lang_ClassCastException() ||
name == vmSymbols::object_array_signature() ||
name == vmSymbols::byte_array_signature() ||
name == vmSymbols::char_array_signature(),
@@ -1554,7 +1613,6 @@ void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
// by any of these static fields.
// At runtime, these classes are initialized before X's archived fields
// are restored by HeapShared::initialize_from_archived_subgraph().
- int i;
for (int i = 0; fields[i].valid(); ) {
ArchivableStaticFieldInfo* info = &fields[i];
const char* klass_name = info->klass_name;
@@ -1645,30 +1703,6 @@ class FindEmbeddedNonNullPointers: public BasicOopIterateClosure {
};
#endif
-#ifndef PRODUCT
-ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) {
- size_t num_bits = region.byte_size() / (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop));
- ResourceBitMap oopmap(num_bits);
-
- HeapWord* p = region.start();
- HeapWord* end = region.end();
- FindEmbeddedNonNullPointers finder((void*)p, &oopmap);
-
- int num_objs = 0;
- while (p < end) {
- oop o = cast_to_oop(p);
- o->oop_iterate(&finder);
- p += o->size();
- ++ num_objs;
- }
-
- log_info(cds, heap)("calculate_oopmap: objects = %6d, oop fields = %7d (nulls = %7d)",
- num_objs, finder.num_total_oops(), finder.num_null_oops());
- return oopmap;
-}
-
-#endif // !PRODUCT
-
void HeapShared::count_allocation(size_t size) {
_total_obj_count ++;
_total_obj_size += size;
diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp
index fa34289a38e..317b791f5d3 100644
--- a/src/hotspot/share/cds/heapShared.hpp
+++ b/src/hotspot/share/cds/heapShared.hpp
@@ -143,13 +143,18 @@ class HeapShared: AllStatic {
friend class VerifySharedOopClosure;
public:
- // Can this VM write a heap region into the CDS archive? Currently only G1+compressed{oops,cp}
+ // Can this VM write a heap region into the CDS archive?
static bool can_write() {
CDS_JAVA_HEAP_ONLY(
if (_disable_writing) {
return false;
}
- return (UseG1GC && UseCompressedClassPointers);
+ // Need compressed class pointers for heap region dump.
+ if (!UseCompressedClassPointers) {
+ return false;
+ }
+ // Almost all GCs support heap region dump, except ZGC (so far).
+ return !UseZGC;
)
NOT_CDS_JAVA_HEAP(return false;)
}
@@ -290,7 +295,8 @@ class HeapShared: AllStatic {
static KlassSubGraphInfo* _default_subgraph_info;
static GrowableArrayCHeap* _pending_roots;
- static OopHandle _roots;
+ static GrowableArrayCHeap* _root_segments;
+ static int _root_segment_max_size_elems;
static OopHandle _scratch_basic_type_mirrors[T_VOID+1];
static MetaspaceObjToOopHandleTable* _scratch_java_mirror_table;
static MetaspaceObjToOopHandleTable* _scratch_references_table;
@@ -371,7 +377,6 @@ class HeapShared: AllStatic {
KlassSubGraphInfo* subgraph_info,
oop orig_obj);
- static ResourceBitMap calculate_oopmap(MemRegion region); // marks all the oop pointers
static void add_to_dumped_interned_strings(oop string);
// Scratch objects for archiving Klass::java_mirror()
@@ -400,12 +405,14 @@ class HeapShared: AllStatic {
static GrowableArrayCHeap* pending_roots() { return _pending_roots; }
// Dump-time and runtime
- static objArrayOop roots();
+ static objArrayOop root_segment(int segment_idx);
static oop get_root(int index, bool clear=false);
// Run-time only
static void clear_root(int index);
+ static void get_segment_indexes(int index, int& segment_index, int& internal_index);
+
static void setup_test_class(const char* test_class_name) PRODUCT_RETURN;
#endif // INCLUDE_CDS_JAVA_HEAP
@@ -423,10 +430,13 @@ class HeapShared: AllStatic {
static void init_for_dumping(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
static void write_subgraph_info_table() NOT_CDS_JAVA_HEAP_RETURN;
- static void init_roots(oop roots_oop) NOT_CDS_JAVA_HEAP_RETURN;
+ static void add_root_segment(objArrayOop segment_oop) NOT_CDS_JAVA_HEAP_RETURN;
+ static void init_root_segment_sizes(int max_size_elems) NOT_CDS_JAVA_HEAP_RETURN;
static void serialize_tables(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
+#ifndef PRODUCT
static bool is_a_test_class_in_unnamed_module(Klass* ik) NOT_CDS_JAVA_HEAP_RETURN_(false);
+#endif
};
#if INCLUDE_CDS_JAVA_HEAP
diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp
index 4d978a7ad88..efd7a906a46 100644
--- a/src/hotspot/share/cds/metaspaceShared.cpp
+++ b/src/hotspot/share/cds/metaspaceShared.cpp
@@ -77,6 +77,7 @@
#include "runtime/globals.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/handles.inline.hpp"
+#include "runtime/javaCalls.hpp"
#include "runtime/os.inline.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "runtime/sharedRuntime.hpp"
@@ -300,6 +301,7 @@ void MetaspaceShared::post_initialize(TRAPS) {
}
ClassLoaderExt::init_paths_start_index(info->app_class_paths_start_index());
ClassLoaderExt::init_app_module_paths_start_index(info->app_module_paths_start_index());
+ ClassLoaderExt::init_num_module_paths(info->header()->num_module_paths());
}
}
}
@@ -749,12 +751,21 @@ void MetaspaceShared::preload_classes(TRAPS) {
}
}
- // Exercise the manifest processing code to ensure classes used by CDS at runtime
- // are always archived
+ // Some classes are used at CDS runtime but are not loaded, and therefore archived, at
+ // dumptime. We can perform dummmy calls to these classes at dumptime to ensure they
+ // are archived.
+ exercise_runtime_cds_code(CHECK);
+
+ log_info(cds)("Loading classes to share: done.");
+}
+
+void MetaspaceShared::exercise_runtime_cds_code(TRAPS) {
+ // Exercise the manifest processing code
const char* dummy = "Manifest-Version: 1.0\n";
CDSProtectionDomain::create_jar_manifest(dummy, strlen(dummy), CHECK);
- log_info(cds)("Loading classes to share: done.");
+ // Exercise FileSystem and URL code
+ CDSProtectionDomain::to_file_URL("dummy.jar", Handle(), CHECK);
}
void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) {
@@ -791,6 +802,9 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS
// Do this at the very end, when no Java code will be executed. Otherwise
// some new strings may be added to the intern table.
StringTable::allocate_shared_strings_array(CHECK);
+ } else {
+ log_info(cds)("Not dumping heap, reset CDSConfig::_is_using_optimized_module_handling");
+ CDSConfig::stop_using_optimized_module_handling();
}
#endif
@@ -1299,7 +1313,7 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
assert(base_address == nullptr ||
(address)archive_space_rs.base() == base_address, "Sanity");
// Register archive space with NMT.
- MemTracker::record_virtual_memory_type(archive_space_rs.base(), mtClassShared);
+ MemTracker::record_virtual_memory_tag(archive_space_rs.base(), mtClassShared);
return archive_space_rs.base();
}
return nullptr;
@@ -1361,8 +1375,8 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
return nullptr;
}
// NMT: fix up the space tags
- MemTracker::record_virtual_memory_type(archive_space_rs.base(), mtClassShared);
- MemTracker::record_virtual_memory_type(class_space_rs.base(), mtClass);
+ MemTracker::record_virtual_memory_tag(archive_space_rs.base(), mtClassShared);
+ MemTracker::record_virtual_memory_tag(class_space_rs.base(), mtClass);
} else {
if (use_archive_base_addr && base_address != nullptr) {
total_space_rs = ReservedSpace(total_range_size, base_address_alignment,
diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp
index f26af21676a..ecc158cc3ef 100644
--- a/src/hotspot/share/cds/metaspaceShared.hpp
+++ b/src/hotspot/share/cds/metaspaceShared.hpp
@@ -75,6 +75,7 @@ class MetaspaceShared : AllStatic {
#endif
private:
+ static void exercise_runtime_cds_code(TRAPS) NOT_CDS_RETURN;
static void preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) NOT_CDS_RETURN;
static void preload_classes(TRAPS) NOT_CDS_RETURN;
diff --git a/src/hotspot/share/ci/ciConstantPoolCache.cpp b/src/hotspot/share/ci/ciConstantPoolCache.cpp
index 8dc9cfc75e1..e831516b0f7 100644
--- a/src/hotspot/share/ci/ciConstantPoolCache.cpp
+++ b/src/hotspot/share/ci/ciConstantPoolCache.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
@@ -37,7 +37,7 @@
ciConstantPoolCache::ciConstantPoolCache(Arena* arena,
int expected_size) {
_elements =
- new (arena) GrowableArray(arena, expected_size, 0, 0);
+ new (arena) GrowableArray(arena, expected_size, 0, nullptr);
_keys = new (arena) GrowableArray(arena, expected_size, 0, 0);
}
diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp
index 3079d469ebe..155ce032400 100644
--- a/src/hotspot/share/ci/ciEnv.cpp
+++ b/src/hotspot/share/ci/ciEnv.cpp
@@ -100,10 +100,6 @@ ciSymbol* ciEnv::_unloaded_cisymbol = nullptr;
ciInstanceKlass* ciEnv::_unloaded_ciinstance_klass = nullptr;
ciObjArrayKlass* ciEnv::_unloaded_ciobjarrayklass = nullptr;
-jobject ciEnv::_ArrayIndexOutOfBoundsException_handle = nullptr;
-jobject ciEnv::_ArrayStoreException_handle = nullptr;
-jobject ciEnv::_ClassCastException_handle = nullptr;
-
#ifndef PRODUCT
static bool firstEnv = true;
#endif /* PRODUCT */
@@ -158,10 +154,16 @@ ciEnv::ciEnv(CompileTask* task)
o = Universe::arithmetic_exception_instance();
assert(o != nullptr, "should have been initialized");
_ArithmeticException_instance = get_object(o)->as_instance();
+ o = Universe::array_index_out_of_bounds_exception_instance();
+ assert(o != nullptr, "should have been initialized");
+ _ArrayIndexOutOfBoundsException_instance = get_object(o)->as_instance();
+ o = Universe::array_store_exception_instance();
+ assert(o != nullptr, "should have been initialized");
+ _ArrayStoreException_instance = get_object(o)->as_instance();
+ o = Universe::class_cast_exception_instance();
+ assert(o != nullptr, "should have been initialized");
+ _ClassCastException_instance = get_object(o)->as_instance();
- _ArrayIndexOutOfBoundsException_instance = nullptr;
- _ArrayStoreException_instance = nullptr;
- _ClassCastException_instance = nullptr;
_the_null_string = nullptr;
_the_min_jint_string = nullptr;
@@ -363,29 +365,6 @@ void ciEnv::cache_dtrace_flags() {
_dtrace_alloc_probes = DTraceAllocProbes;
}
-// ------------------------------------------------------------------
-// helper for lazy exception creation
-ciInstance* ciEnv::get_or_create_exception(jobject& handle, Symbol* name) {
- VM_ENTRY_MARK;
- if (handle == nullptr) {
- // Cf. universe.cpp, creation of Universe::_null_ptr_exception_instance.
- InstanceKlass* ik = SystemDictionary::find_instance_klass(THREAD, name, Handle(), Handle());
- jobject objh = nullptr;
- if (ik != nullptr) {
- oop obj = ik->allocate_instance(THREAD);
- if (!HAS_PENDING_EXCEPTION)
- objh = JNIHandles::make_global(Handle(THREAD, obj));
- }
- if (HAS_PENDING_EXCEPTION) {
- CLEAR_PENDING_EXCEPTION;
- } else {
- handle = objh;
- }
- }
- oop obj = JNIHandles::resolve(handle);
- return obj == nullptr? nullptr: get_object(obj)->as_instance();
-}
-
ciInstanceKlass* ciEnv::get_box_klass_for_primitive_type(BasicType type) {
switch (type) {
case T_BOOLEAN: return Boolean_klass();
@@ -403,31 +382,6 @@ ciInstanceKlass* ciEnv::get_box_klass_for_primitive_type(BasicType type) {
}
}
-ciInstance* ciEnv::ArrayIndexOutOfBoundsException_instance() {
- if (_ArrayIndexOutOfBoundsException_instance == nullptr) {
- _ArrayIndexOutOfBoundsException_instance
- = get_or_create_exception(_ArrayIndexOutOfBoundsException_handle,
- vmSymbols::java_lang_ArrayIndexOutOfBoundsException());
- }
- return _ArrayIndexOutOfBoundsException_instance;
-}
-ciInstance* ciEnv::ArrayStoreException_instance() {
- if (_ArrayStoreException_instance == nullptr) {
- _ArrayStoreException_instance
- = get_or_create_exception(_ArrayStoreException_handle,
- vmSymbols::java_lang_ArrayStoreException());
- }
- return _ArrayStoreException_instance;
-}
-ciInstance* ciEnv::ClassCastException_instance() {
- if (_ClassCastException_instance == nullptr) {
- _ClassCastException_instance
- = get_or_create_exception(_ClassCastException_handle,
- vmSymbols::java_lang_ClassCastException());
- }
- return _ClassCastException_instance;
-}
-
ciInstance* ciEnv::the_null_string() {
if (_the_null_string == nullptr) {
VM_ENTRY_MARK;
@@ -1662,7 +1616,10 @@ void ciEnv::dump_replay_data_helper(outputStream* out) {
for (int i = 0; i < objects->length(); i++) {
objects->at(i)->dump_replay_data(out);
}
- dump_compile_data(out);
+
+ if (this->task() != nullptr) {
+ dump_compile_data(out);
+ }
out->flush();
}
diff --git a/src/hotspot/share/ci/ciEnv.hpp b/src/hotspot/share/ci/ciEnv.hpp
index 5ee9b420033..6c66633ee17 100644
--- a/src/hotspot/share/ci/ciEnv.hpp
+++ b/src/hotspot/share/ci/ciEnv.hpp
@@ -94,10 +94,6 @@ class ciEnv : StackObj {
static ciInstanceKlass* _unloaded_ciinstance_klass;
static ciObjArrayKlass* _unloaded_ciobjarrayklass;
- static jobject _ArrayIndexOutOfBoundsException_handle;
- static jobject _ArrayStoreException_handle;
- static jobject _ClassCastException_handle;
-
ciInstance* _NullPointerException_instance;
ciInstance* _ArithmeticException_instance;
ciInstance* _ArrayIndexOutOfBoundsException_instance;
@@ -230,8 +226,6 @@ class ciEnv : StackObj {
ciMethod* get_method_from_handle(Method* method);
- ciInstance* get_or_create_exception(jobject& handle, Symbol* name);
-
// Get a ciMethod representing either an unfound method or
// a method with an unloaded holder. Ensures uniqueness of
// the result.
@@ -402,11 +396,18 @@ class ciEnv : StackObj {
assert(_ArithmeticException_instance != nullptr, "initialization problem");
return _ArithmeticException_instance;
}
-
- // Lazy constructors:
- ciInstance* ArrayIndexOutOfBoundsException_instance();
- ciInstance* ArrayStoreException_instance();
- ciInstance* ClassCastException_instance();
+ ciInstance* ArrayIndexOutOfBoundsException_instance() {
+ assert(_ArrayIndexOutOfBoundsException_instance != nullptr, "initialization problem");
+ return _ArrayIndexOutOfBoundsException_instance;
+ }
+ ciInstance* ArrayStoreException_instance() {
+ assert(_ArrayStoreException_instance != nullptr, "initialization problem");
+ return _ArrayStoreException_instance;
+ }
+ ciInstance* ClassCastException_instance() {
+ assert(_ClassCastException_instance != nullptr, "initialization problem");
+ return _ClassCastException_instance;
+ }
ciInstance* the_null_string();
ciInstance* the_min_jint_string();
diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp
index 240bb25ae3a..a9342eeada4 100644
--- a/src/hotspot/share/ci/ciInstanceKlass.cpp
+++ b/src/hotspot/share/ci/ciInstanceKlass.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
@@ -59,7 +59,7 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
AccessFlags access_flags = ik->access_flags();
_flags = ciFlags(access_flags);
- _has_finalizer = access_flags.has_finalizer();
+ _has_finalizer = ik->has_finalizer();
_has_subklass = flags().is_final() ? subklass_false : subklass_unknown;
_init_state = ik->init_state();
_has_nonstatic_fields = ik->has_nonstatic_fields();
diff --git a/src/hotspot/share/ci/ciKlass.cpp b/src/hotspot/share/ci/ciKlass.cpp
index 6e70d69f05d..efdd2512f90 100644
--- a/src/hotspot/share/ci/ciKlass.cpp
+++ b/src/hotspot/share/ci/ciKlass.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
@@ -226,6 +226,15 @@ jint ciKlass::access_flags() {
)
}
+// ------------------------------------------------------------------
+// ciKlass::misc_flags
+klass_flags_t ciKlass::misc_flags() {
+ assert(is_loaded(), "not loaded");
+ GUARDED_VM_ENTRY(
+ return get_Klass()->misc_flags();
+ )
+}
+
// ------------------------------------------------------------------
// ciKlass::print_impl
//
diff --git a/src/hotspot/share/ci/ciKlass.hpp b/src/hotspot/share/ci/ciKlass.hpp
index 2dd5a5e2c0b..10d8395ed7f 100644
--- a/src/hotspot/share/ci/ciKlass.hpp
+++ b/src/hotspot/share/ci/ciKlass.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -107,6 +107,13 @@ class ciKlass : public ciType {
return false;
}
+ bool is_in_encoding_range() {
+ Klass* k = get_Klass();
+ bool is_in_encoding_range = CompressedKlassPointers::is_encodable(k);
+ assert(is_in_encoding_range || k->is_interface() || k->is_abstract(), "sanity");
+ return is_in_encoding_range;
+ }
+
// Attempt to get a klass using this ciKlass's loader.
ciKlass* find_klass(ciSymbol* klass_name);
// Note: To find a class from its name string, use ciSymbol::make,
@@ -121,6 +128,9 @@ class ciKlass : public ciType {
// Fetch Klass::access_flags.
jint access_flags();
+ // Fetch Klass::misc_flags.
+ klass_flags_t misc_flags();
+
// What kind of ciObject is this?
bool is_klass() const { return true; }
diff --git a/src/hotspot/share/ci/ciMethod.cpp b/src/hotspot/share/ci/ciMethod.cpp
index b2ac3a8b217..a74a812c6a2 100644
--- a/src/hotspot/share/ci/ciMethod.cpp
+++ b/src/hotspot/share/ci/ciMethod.cpp
@@ -781,6 +781,22 @@ bool ciMethod::can_omit_stack_trace() const {
return _can_omit_stack_trace;
}
+// ------------------------------------------------------------------
+// ciMethod::equals
+//
+// Returns true if the methods are the same, taking redefined methods
+// into account.
+bool ciMethod::equals(const ciMethod* m) const {
+ if (this == m) return true;
+ VM_ENTRY_MARK;
+ Method* m1 = this->get_Method();
+ Method* m2 = m->get_Method();
+ if (m1->is_old()) m1 = m1->get_new_method();
+ if (m2->is_old()) m2 = m2->get_new_method();
+ return m1 == m2;
+}
+
+
// ------------------------------------------------------------------
// ciMethod::resolve_invoke
//
@@ -1233,7 +1249,6 @@ bool ciMethod::has_jsrs () const { FETCH_FLAG_FROM_VM(has_jsrs);
bool ciMethod::is_getter () const { FETCH_FLAG_FROM_VM(is_getter); }
bool ciMethod::is_setter () const { FETCH_FLAG_FROM_VM(is_setter); }
bool ciMethod::is_accessor () const { FETCH_FLAG_FROM_VM(is_accessor); }
-bool ciMethod::is_initializer () const { FETCH_FLAG_FROM_VM(is_initializer); }
bool ciMethod::is_empty () const { FETCH_FLAG_FROM_VM(is_empty_method); }
bool ciMethod::is_boxing_method() const {
diff --git a/src/hotspot/share/ci/ciMethod.hpp b/src/hotspot/share/ci/ciMethod.hpp
index 5a4a1dd1c7f..cc524930192 100644
--- a/src/hotspot/share/ci/ciMethod.hpp
+++ b/src/hotspot/share/ci/ciMethod.hpp
@@ -352,7 +352,6 @@ class ciMethod : public ciMetadata {
bool is_getter () const;
bool is_setter () const;
bool is_accessor () const;
- bool is_initializer () const;
bool is_empty () const;
bool can_be_statically_bound() const { return _can_be_statically_bound; }
bool has_reserved_stack_access() const { return _has_reserved_stack_access; }
@@ -366,6 +365,8 @@ class ciMethod : public ciMetadata {
bool can_omit_stack_trace() const;
+ bool equals(const ciMethod* m) const;
+
// Replay data methods
static void dump_name_as_ascii(outputStream* st, Method* method);
void dump_name_as_ascii(outputStream* st);
diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp
index 3ed71806b07..fd29e0cf857 100644
--- a/src/hotspot/share/ci/ciReplay.cpp
+++ b/src/hotspot/share/ci/ciReplay.cpp
@@ -132,6 +132,7 @@ class CompileReplay : public StackObj {
char* _bufptr;
char* _buffer;
int _buffer_length;
+ ReallocMark _nesting; // Safety checks for arena reallocation
// "compile" data
ciKlass* _iklass;
@@ -601,6 +602,7 @@ class CompileReplay : public StackObj {
int buffer_pos = 0;
while(c != EOF) {
if (buffer_pos + 1 >= _buffer_length) {
+ _nesting.check(); // Check if a reallocation in the resource arena is safe
int new_length = _buffer_length * 2;
// Next call will throw error in case of OOM.
_buffer = REALLOC_RESOURCE_ARRAY(char, _buffer, _buffer_length, new_length);
diff --git a/src/hotspot/share/ci/ciStreams.cpp b/src/hotspot/share/ci/ciStreams.cpp
index 8220910d74c..18d2a46a686 100644
--- a/src/hotspot/share/ci/ciStreams.cpp
+++ b/src/hotspot/share/ci/ciStreams.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
@@ -135,7 +135,7 @@ Bytecodes::Code ciBytecodeStream::next_wide_or_table(Bytecodes::Code bc) {
// ------------------------------------------------------------------
// ciBytecodeStream::reset_to_bci
void ciBytecodeStream::reset_to_bci( int bci ) {
- _bc_start=_was_wide=0;
+ _bc_start = _was_wide = nullptr;
_pc = _start+bci;
}
diff --git a/src/hotspot/share/ci/ciTypeFlow.cpp b/src/hotspot/share/ci/ciTypeFlow.cpp
index 520eeeb10d5..2d80a18f16b 100644
--- a/src/hotspot/share/ci/ciTypeFlow.cpp
+++ b/src/hotspot/share/ci/ciTypeFlow.cpp
@@ -720,12 +720,18 @@ void ciTypeFlow::StateVector::do_jsr(ciBytecodeStream* str) {
void ciTypeFlow::StateVector::do_ldc(ciBytecodeStream* str) {
if (str->is_in_error()) {
trap(str, nullptr, Deoptimization::make_trap_request(Deoptimization::Reason_unhandled,
- Deoptimization::Action_none));
+ Deoptimization::Action_none));
return;
}
ciConstant con = str->get_constant();
if (con.is_valid()) {
int cp_index = str->get_constant_pool_index();
+ if (!con.is_loaded()) {
+ trap(str, nullptr, Deoptimization::make_trap_request(Deoptimization::Reason_unloaded,
+ Deoptimization::Action_reinterpret,
+ cp_index));
+ return;
+ }
BasicType basic_type = str->get_basic_type_for_constant_at(cp_index);
if (is_reference_type(basic_type)) {
ciObject* obj = con.as_object();
@@ -2207,11 +2213,10 @@ bool ciTypeFlow::can_trap(ciBytecodeStream& str) {
if (!Bytecodes::can_trap(str.cur_bc())) return false;
switch (str.cur_bc()) {
- // %%% FIXME: ldc of Class can generate an exception
case Bytecodes::_ldc:
case Bytecodes::_ldc_w:
case Bytecodes::_ldc2_w:
- return str.is_in_error();
+ return str.is_in_error() || !str.get_constant().is_loaded();
case Bytecodes::_aload_0:
// These bytecodes can trap for rewriting. We need to assume that
diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp
index 535b67887fc..dd7cecdd9c2 100644
--- a/src/hotspot/share/classfile/classFileParser.cpp
+++ b/src/hotspot/share/classfile/classFileParser.cpp
@@ -411,23 +411,6 @@ static inline Symbol* check_symbol_at(const ConstantPool* cp, int index) {
return nullptr;
}
-#ifdef ASSERT
-PRAGMA_DIAG_PUSH
-PRAGMA_FORMAT_NONLITERAL_IGNORED
-void ClassFileParser::report_assert_property_failure(const char* msg, TRAPS) const {
- ResourceMark rm(THREAD);
- fatal(msg, _class_name->as_C_string());
-}
-
-void ClassFileParser::report_assert_property_failure(const char* msg,
- int index,
- TRAPS) const {
- ResourceMark rm(THREAD);
- fatal(msg, index, _class_name->as_C_string());
-}
-PRAGMA_DIAG_POP
-#endif
-
void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
ConstantPool* const cp,
const int length,
@@ -462,10 +445,10 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
if (!_need_verify) break;
const int klass_ref_index = cp->uncached_klass_ref_index_at(index);
const int name_and_type_ref_index = cp->uncached_name_and_type_ref_index_at(index);
- check_property(valid_klass_reference_at(klass_ref_index),
+ guarantee_property(valid_klass_reference_at(klass_ref_index),
"Invalid constant pool index %u in class file %s",
klass_ref_index, CHECK);
- check_property(valid_cp_range(name_and_type_ref_index, length) &&
+ guarantee_property(valid_cp_range(name_and_type_ref_index, length) &&
cp->tag_at(name_and_type_ref_index).is_name_and_type(),
"Invalid constant pool index %u in class file %s",
name_and_type_ref_index, CHECK);
@@ -482,7 +465,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
case JVM_CONSTANT_Long:
case JVM_CONSTANT_Double: {
index++;
- check_property(
+ guarantee_property(
(index < length && cp->tag_at(index).is_invalid()),
"Improper constant pool long/double index %u in class file %s",
index, CHECK);
@@ -492,10 +475,10 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
if (!_need_verify) break;
const int name_ref_index = cp->name_ref_index_at(index);
const int signature_ref_index = cp->signature_ref_index_at(index);
- check_property(valid_symbol_at(name_ref_index),
+ guarantee_property(valid_symbol_at(name_ref_index),
"Invalid constant pool index %u in class file %s",
name_ref_index, CHECK);
- check_property(valid_symbol_at(signature_ref_index),
+ guarantee_property(valid_symbol_at(signature_ref_index),
"Invalid constant pool index %u in class file %s",
signature_ref_index, CHECK);
break;
@@ -509,7 +492,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
}
case JVM_CONSTANT_ClassIndex: {
const int class_index = cp->klass_index_at(index);
- check_property(valid_symbol_at(class_index),
+ guarantee_property(valid_symbol_at(class_index),
"Invalid constant pool index %u in class file %s",
class_index, CHECK);
cp->unresolved_klass_at_put(index, class_index, num_klasses++);
@@ -517,7 +500,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
}
case JVM_CONSTANT_StringIndex: {
const int string_index = cp->string_index_at(index);
- check_property(valid_symbol_at(string_index),
+ guarantee_property(valid_symbol_at(string_index),
"Invalid constant pool index %u in class file %s",
string_index, CHECK);
Symbol* const sym = cp->symbol_at(string_index);
@@ -526,7 +509,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
}
case JVM_CONSTANT_MethodHandle: {
const int ref_index = cp->method_handle_index_at(index);
- check_property(valid_cp_range(ref_index, length),
+ guarantee_property(valid_cp_range(ref_index, length),
"Invalid constant pool index %u in class file %s",
ref_index, CHECK);
const constantTag tag = cp->tag_at(ref_index);
@@ -537,7 +520,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
case JVM_REF_getStatic:
case JVM_REF_putField:
case JVM_REF_putStatic: {
- check_property(
+ guarantee_property(
tag.is_field(),
"Invalid constant pool index %u in class file %s (not a field)",
ref_index, CHECK);
@@ -545,7 +528,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
}
case JVM_REF_invokeVirtual:
case JVM_REF_newInvokeSpecial: {
- check_property(
+ guarantee_property(
tag.is_method(),
"Invalid constant pool index %u in class file %s (not a method)",
ref_index, CHECK);
@@ -553,7 +536,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
}
case JVM_REF_invokeStatic:
case JVM_REF_invokeSpecial: {
- check_property(
+ guarantee_property(
tag.is_method() ||
((_major_version >= JAVA_8_VERSION) && tag.is_interface_method()),
"Invalid constant pool index %u in class file %s (not a method)",
@@ -561,7 +544,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
break;
}
case JVM_REF_invokeInterface: {
- check_property(
+ guarantee_property(
tag.is_interface_method(),
"Invalid constant pool index %u in class file %s (not an interface method)",
ref_index, CHECK);
@@ -579,7 +562,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
} // case MethodHandle
case JVM_CONSTANT_MethodType: {
const int ref_index = cp->method_type_index_at(index);
- check_property(valid_symbol_at(ref_index),
+ guarantee_property(valid_symbol_at(ref_index),
"Invalid constant pool index %u in class file %s",
ref_index, CHECK);
break;
@@ -588,7 +571,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
const int name_and_type_ref_index =
cp->bootstrap_name_and_type_ref_index_at(index);
- check_property(valid_cp_range(name_and_type_ref_index, length) &&
+ guarantee_property(valid_cp_range(name_and_type_ref_index, length) &&
cp->tag_at(name_and_type_ref_index).is_name_and_type(),
"Invalid constant pool index %u in class file %s",
name_and_type_ref_index, CHECK);
@@ -603,7 +586,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
const int name_and_type_ref_index =
cp->bootstrap_name_and_type_ref_index_at(index);
- check_property(valid_cp_range(name_and_type_ref_index, length) &&
+ guarantee_property(valid_cp_range(name_and_type_ref_index, length) &&
cp->tag_at(name_and_type_ref_index).is_name_and_type(),
"Invalid constant pool index %u in class file %s",
name_and_type_ref_index, CHECK);
@@ -821,7 +804,7 @@ void ClassFileParser::parse_interfaces(const ClassFileStream* const stream,
for (index = 0; index < itfs_len; index++) {
const u2 interface_index = stream->get_u2(CHECK);
Klass* interf;
- check_property(
+ guarantee_property(
valid_klass_reference_at(interface_index),
"Interface name has bad constant pool index %u in class file %s",
interface_index, CHECK);
@@ -835,14 +818,12 @@ void ClassFileParser::parse_interfaces(const ClassFileStream* const stream,
guarantee_property(unresolved_klass->char_at(0) != JVM_SIGNATURE_ARRAY,
"Bad interface name in class file %s", CHECK);
- // Call resolve_super so class circularity is checked
- interf = SystemDictionary::resolve_super_or_fail(
- _class_name,
- unresolved_klass,
- Handle(THREAD, _loader_data->class_loader()),
- _protection_domain,
- false,
- CHECK);
+ // Call resolve on the interface class name with class circularity checking
+ interf = SystemDictionary::resolve_super_or_fail(_class_name,
+ unresolved_klass,
+ Handle(THREAD, _loader_data->class_loader()),
+ _protection_domain,
+ false, CHECK);
}
if (!interf->is_interface()) {
@@ -1152,30 +1133,40 @@ static void parse_annotations(const ConstantPool* const cp,
if (AnnotationCollector::_unknown == id) continue;
coll->set_annotation(id);
if (AnnotationCollector::_java_lang_Deprecated == id) {
- assert(count <= 2, "change this if more element-value pairs are added to the @Deprecated annotation");
- // @Deprecated can specify forRemoval=true
+ // @Deprecated can specify forRemoval=true, which we need
+ // to record for JFR to use. If the annotation is not well-formed
+ // then we may not be able to determine that.
const u1* offset = abase + member_off;
- for (int i = 0; i < count; ++i) {
+ // There are only 2 members in @Deprecated.
+ int n_members = MIN2(count, 2);
+ for (int i = 0; i < n_members; ++i) {
int member_index = Bytes::get_Java_u2((address)offset);
offset += 2;
member = check_symbol_at(cp, member_index);
- if (member == vmSymbols::since()) {
- assert(*((address)offset) == s_tag_val, "invariant");
+ if (member == vmSymbols::since() &&
+ (*((address)offset) == s_tag_val)) {
+ // Found `since` first so skip over it
offset += 3;
- continue;
}
- if (member == vmSymbols::for_removal()) {
- assert(*((address)offset) == b_tag_val, "invariant");
+ else if (member == vmSymbols::for_removal() &&
+ (*((address)offset) == b_tag_val)) {
const u2 boolean_value_index = Bytes::get_Java_u2((address)offset + 1);
- if (cp->int_at(boolean_value_index) == 1) {
+ // No guarantee the entry is valid so check it refers to an int in the CP.
+ if (cp->is_within_bounds(boolean_value_index) &&
+ cp->tag_at(boolean_value_index).is_int() &&
+ cp->int_at(boolean_value_index) == 1) {
// forRemoval == true
coll->set_annotation(AnnotationCollector::_java_lang_Deprecated_for_removal);
}
+ break; // no need to check further
+ }
+ else {
+ // This @Deprecated annotation is malformed so we don't try to
+ // determine whether forRemoval is set.
break;
}
-
}
- continue;
+ continue; // proceed to next annotation
}
if (AnnotationCollector::_jdk_internal_vm_annotation_Contended == id) {
@@ -1196,11 +1187,21 @@ static void parse_annotations(const ConstantPool* const cp,
&& s_tag_val == *(abase + tag_off)
&& member == vmSymbols::value_name()) {
group_index = Bytes::get_Java_u2((address)abase + s_con_off);
- if (cp->symbol_at(group_index)->utf8_length() == 0) {
- group_index = 0; // default contended group
+ // No guarantee the group_index is valid so check it refers to a
+ // symbol in the CP.
+ if (cp->is_within_bounds(group_index) &&
+ cp->tag_at(group_index).is_utf8()) {
+ // Seems valid, so check for empty string and reset
+ if (cp->symbol_at(group_index)->utf8_length() == 0) {
+ group_index = 0; // default contended group
+ }
+ } else {
+ // Not valid so use the default
+ group_index = 0;
}
}
coll->set_contended_group(group_index);
+ continue; // proceed to next annotation
}
}
}
@@ -1227,12 +1228,8 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs,
bool is_synthetic = false;
const u1* runtime_visible_annotations = nullptr;
int runtime_visible_annotations_length = 0;
- const u1* runtime_invisible_annotations = nullptr;
- int runtime_invisible_annotations_length = 0;
const u1* runtime_visible_type_annotations = nullptr;
int runtime_visible_type_annotations_length = 0;
- const u1* runtime_invisible_type_annotations = nullptr;
- int runtime_invisible_type_annotations_length = 0;
bool runtime_invisible_annotations_exists = false;
bool runtime_invisible_type_annotations_exists = false;
const ConstantPool* const cp = _cp;
@@ -1241,10 +1238,10 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs,
cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length
const u2 attribute_name_index = cfs->get_u2_fast();
const u4 attribute_length = cfs->get_u4_fast();
- check_property(valid_symbol_at(attribute_name_index),
- "Invalid field attribute index %u in class file %s",
- attribute_name_index,
- CHECK);
+ guarantee_property(valid_symbol_at(attribute_name_index),
+ "Invalid field attribute index %u in class file %s",
+ attribute_name_index,
+ CHECK);
const Symbol* const attribute_name = cp->symbol_at(attribute_name_index);
if (is_static && attribute_name == vmSymbols::tag_constant_value()) {
@@ -1253,7 +1250,7 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs,
classfile_parse_error("Duplicate ConstantValue attribute in class file %s", THREAD);
return;
}
- check_property(
+ guarantee_property(
attribute_length == 2,
"Invalid ConstantValue field attribute length %u in class file %s",
attribute_length, CHECK);
@@ -1315,11 +1312,6 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs,
return;
}
runtime_invisible_annotations_exists = true;
- if (PreserveAllAnnotations) {
- runtime_invisible_annotations_length = attribute_length;
- runtime_invisible_annotations = cfs->current();
- assert(runtime_invisible_annotations != nullptr, "null invisible annotations");
- }
cfs->skip_u1(attribute_length, CHECK);
} else if (attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) {
if (runtime_visible_type_annotations != nullptr) {
@@ -1339,11 +1331,6 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs,
} else {
runtime_invisible_type_annotations_exists = true;
}
- if (PreserveAllAnnotations) {
- runtime_invisible_type_annotations_length = attribute_length;
- runtime_invisible_type_annotations = cfs->current();
- assert(runtime_invisible_type_annotations != nullptr, "null invisible type annotations");
- }
cfs->skip_u1(attribute_length, CHECK);
} else {
cfs->skip_u1(attribute_length, CHECK); // Skip unknown attributes
@@ -1356,121 +1343,28 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs,
*constantvalue_index_addr = constantvalue_index;
*is_synthetic_addr = is_synthetic;
*generic_signature_index_addr = generic_signature_index;
- AnnotationArray* a = assemble_annotations(runtime_visible_annotations,
+ AnnotationArray* a = allocate_annotations(runtime_visible_annotations,
runtime_visible_annotations_length,
- runtime_invisible_annotations,
- runtime_invisible_annotations_length,
CHECK);
parsed_annotations->set_field_annotations(a);
- a = assemble_annotations(runtime_visible_type_annotations,
+ a = allocate_annotations(runtime_visible_type_annotations,
runtime_visible_type_annotations_length,
- runtime_invisible_type_annotations,
- runtime_invisible_type_annotations_length,
CHECK);
parsed_annotations->set_field_type_annotations(a);
return;
}
-// Field allocation types. Used for computing field offsets.
-
-enum FieldAllocationType {
- STATIC_OOP, // Oops
- STATIC_BYTE, // Boolean, Byte, char
- STATIC_SHORT, // shorts
- STATIC_WORD, // ints
- STATIC_DOUBLE, // aligned long or double
- NONSTATIC_OOP,
- NONSTATIC_BYTE,
- NONSTATIC_SHORT,
- NONSTATIC_WORD,
- NONSTATIC_DOUBLE,
- MAX_FIELD_ALLOCATION_TYPE,
- BAD_ALLOCATION_TYPE = -1
-};
-
-static FieldAllocationType _basic_type_to_atype[2 * (T_CONFLICT + 1)] = {
- BAD_ALLOCATION_TYPE, // 0
- BAD_ALLOCATION_TYPE, // 1
- BAD_ALLOCATION_TYPE, // 2
- BAD_ALLOCATION_TYPE, // 3
- NONSTATIC_BYTE , // T_BOOLEAN = 4,
- NONSTATIC_SHORT, // T_CHAR = 5,
- NONSTATIC_WORD, // T_FLOAT = 6,
- NONSTATIC_DOUBLE, // T_DOUBLE = 7,
- NONSTATIC_BYTE, // T_BYTE = 8,
- NONSTATIC_SHORT, // T_SHORT = 9,
- NONSTATIC_WORD, // T_INT = 10,
- NONSTATIC_DOUBLE, // T_LONG = 11,
- NONSTATIC_OOP, // T_OBJECT = 12,
- NONSTATIC_OOP, // T_ARRAY = 13,
- BAD_ALLOCATION_TYPE, // T_VOID = 14,
- BAD_ALLOCATION_TYPE, // T_ADDRESS = 15,
- BAD_ALLOCATION_TYPE, // T_NARROWOOP = 16,
- BAD_ALLOCATION_TYPE, // T_METADATA = 17,
- BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18,
- BAD_ALLOCATION_TYPE, // T_CONFLICT = 19,
- BAD_ALLOCATION_TYPE, // 0
- BAD_ALLOCATION_TYPE, // 1
- BAD_ALLOCATION_TYPE, // 2
- BAD_ALLOCATION_TYPE, // 3
- STATIC_BYTE , // T_BOOLEAN = 4,
- STATIC_SHORT, // T_CHAR = 5,
- STATIC_WORD, // T_FLOAT = 6,
- STATIC_DOUBLE, // T_DOUBLE = 7,
- STATIC_BYTE, // T_BYTE = 8,
- STATIC_SHORT, // T_SHORT = 9,
- STATIC_WORD, // T_INT = 10,
- STATIC_DOUBLE, // T_LONG = 11,
- STATIC_OOP, // T_OBJECT = 12,
- STATIC_OOP, // T_ARRAY = 13,
- BAD_ALLOCATION_TYPE, // T_VOID = 14,
- BAD_ALLOCATION_TYPE, // T_ADDRESS = 15,
- BAD_ALLOCATION_TYPE, // T_NARROWOOP = 16,
- BAD_ALLOCATION_TYPE, // T_METADATA = 17,
- BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18,
- BAD_ALLOCATION_TYPE, // T_CONFLICT = 19,
-};
-
-static FieldAllocationType basic_type_to_atype(bool is_static, BasicType type) {
- assert(type >= T_BOOLEAN && type < T_VOID, "only allowable values");
- FieldAllocationType result = _basic_type_to_atype[type + (is_static ? (T_CONFLICT + 1) : 0)];
- assert(result != BAD_ALLOCATION_TYPE, "bad type");
- return result;
-}
-
-class ClassFileParser::FieldAllocationCount : public ResourceObj {
- public:
- u2 count[MAX_FIELD_ALLOCATION_TYPE];
-
- FieldAllocationCount() {
- for (int i = 0; i < MAX_FIELD_ALLOCATION_TYPE; i++) {
- count[i] = 0;
- }
- }
-
- void update(bool is_static, BasicType type) {
- FieldAllocationType atype = basic_type_to_atype(is_static, type);
- if (atype != BAD_ALLOCATION_TYPE) {
- // Make sure there is no overflow with injected fields.
- assert(count[atype] < 0xFFFF, "More than 65535 fields");
- count[atype]++;
- }
- }
-};
-
// Side-effects: populates the _fields, _fields_annotations,
// _fields_type_annotations fields
void ClassFileParser::parse_fields(const ClassFileStream* const cfs,
bool is_interface,
- FieldAllocationCount* const fac,
ConstantPool* cp,
const int cp_size,
u2* const java_fields_count_ptr,
TRAPS) {
assert(cfs != nullptr, "invariant");
- assert(fac != nullptr, "invariant");
assert(cp != nullptr, "invariant");
assert(java_fields_count_ptr != nullptr, "invariant");
@@ -1502,14 +1396,14 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs,
FieldInfo::FieldFlags fieldFlags(0);
const u2 name_index = cfs->get_u2_fast();
- check_property(valid_symbol_at(name_index),
+ guarantee_property(valid_symbol_at(name_index),
"Invalid constant pool index %u for field name in class file %s",
name_index, CHECK);
const Symbol* const name = cp->symbol_at(name_index);
verify_legal_field_name(name, CHECK);
const u2 signature_index = cfs->get_u2_fast();
- check_property(valid_symbol_at(signature_index),
+ guarantee_property(valid_symbol_at(signature_index),
"Invalid constant pool index %u for field signature in class file %s",
signature_index, CHECK);
const Symbol* const sig = cp->symbol_at(signature_index);
@@ -1564,8 +1458,10 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs,
const BasicType type = cp->basic_type_for_signature_at(signature_index);
- // Update FieldAllocationCount for this kind of field
- fac->update(is_static, type);
+ // Update number of static oop fields.
+ if (is_static && is_reference_type(type)) {
+ _static_oop_count++;
+ }
FieldInfo fi(access_flags, name_index, signature_index, constantvalue_index, fieldFlags);
fi.set_index(n);
@@ -1610,10 +1506,6 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs,
FieldInfo fi(aflags, (u2)(injected[n].name_index), (u2)(injected[n].signature_index), 0, fflags);
fi.set_index(index);
_temp_field_info->append(fi);
-
- // Update FieldAllocationCount for this kind of field
- const BasicType type = Signature::basic_type(injected[n].signature());
- fac->update(false, type);
index++;
}
}
@@ -1689,7 +1581,7 @@ void ClassFileParser::parse_linenumber_table(u4 code_attribute_length,
const unsigned int length_in_bytes = num_entries * (sizeof(u2) * 2);
// Verify line number attribute and table length
- check_property(
+ guarantee_property(
code_attribute_length == sizeof(u2) + length_in_bytes,
"LineNumberTable attribute has wrong length in class file %s", CHECK);
@@ -1879,7 +1771,7 @@ const ClassFileParser::unsafe_u2* ClassFileParser::parse_checked_exceptions(cons
cfs->guarantee_more(2 * len, CHECK_NULL);
for (int i = 0; i < len; i++) {
checked_exception = cfs->get_u2_fast();
- check_property(
+ guarantee_property(
valid_klass_reference_at(checked_exception),
"Exception name has bad type at constant pool %u in class file %s",
checked_exception, CHECK_NULL);
@@ -2164,57 +2056,40 @@ void ClassFileParser::copy_localvariable_table(const ConstMethod* cm,
void ClassFileParser::copy_method_annotations(ConstMethod* cm,
const u1* runtime_visible_annotations,
int runtime_visible_annotations_length,
- const u1* runtime_invisible_annotations,
- int runtime_invisible_annotations_length,
const u1* runtime_visible_parameter_annotations,
int runtime_visible_parameter_annotations_length,
- const u1* runtime_invisible_parameter_annotations,
- int runtime_invisible_parameter_annotations_length,
const u1* runtime_visible_type_annotations,
int runtime_visible_type_annotations_length,
- const u1* runtime_invisible_type_annotations,
- int runtime_invisible_type_annotations_length,
const u1* annotation_default,
int annotation_default_length,
TRAPS) {
AnnotationArray* a;
- if (runtime_visible_annotations_length +
- runtime_invisible_annotations_length > 0) {
- a = assemble_annotations(runtime_visible_annotations,
+ if (runtime_visible_annotations_length > 0) {
+ a = allocate_annotations(runtime_visible_annotations,
runtime_visible_annotations_length,
- runtime_invisible_annotations,
- runtime_invisible_annotations_length,
CHECK);
cm->set_method_annotations(a);
}
- if (runtime_visible_parameter_annotations_length +
- runtime_invisible_parameter_annotations_length > 0) {
- a = assemble_annotations(runtime_visible_parameter_annotations,
+ if (runtime_visible_parameter_annotations_length > 0) {
+ a = allocate_annotations(runtime_visible_parameter_annotations,
runtime_visible_parameter_annotations_length,
- runtime_invisible_parameter_annotations,
- runtime_invisible_parameter_annotations_length,
CHECK);
cm->set_parameter_annotations(a);
}
if (annotation_default_length > 0) {
- a = assemble_annotations(annotation_default,
+ a = allocate_annotations(annotation_default,
annotation_default_length,
- nullptr,
- 0,
CHECK);
cm->set_default_annotations(a);
}
- if (runtime_visible_type_annotations_length +
- runtime_invisible_type_annotations_length > 0) {
- a = assemble_annotations(runtime_visible_type_annotations,
+ if (runtime_visible_type_annotations_length > 0) {
+ a = allocate_annotations(runtime_visible_type_annotations,
runtime_visible_type_annotations_length,
- runtime_invisible_type_annotations,
- runtime_invisible_type_annotations_length,
CHECK);
cm->set_type_annotations(a);
}
@@ -2245,7 +2120,7 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
int flags = cfs->get_u2_fast();
const u2 name_index = cfs->get_u2_fast();
const int cp_size = cp->length();
- check_property(
+ guarantee_property(
valid_symbol_at(name_index),
"Illegal constant pool index %u for method name in class file %s",
name_index, CHECK_NULL);
@@ -2296,7 +2171,7 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
u2 max_stack = 0;
u2 max_locals = 0;
u4 code_length = 0;
- const u1* code_start = 0;
+ const u1* code_start = nullptr;
u2 exception_table_length = 0;
const unsafe_u2* exception_table_start = nullptr; // (potentially unaligned) pointer to array of u2 elements
Array* exception_handlers = Universe::the_empty_int_array();
@@ -2327,16 +2202,10 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
MethodAnnotationCollector parsed_annotations;
const u1* runtime_visible_annotations = nullptr;
int runtime_visible_annotations_length = 0;
- const u1* runtime_invisible_annotations = nullptr;
- int runtime_invisible_annotations_length = 0;
const u1* runtime_visible_parameter_annotations = nullptr;
int runtime_visible_parameter_annotations_length = 0;
- const u1* runtime_invisible_parameter_annotations = nullptr;
- int runtime_invisible_parameter_annotations_length = 0;
const u1* runtime_visible_type_annotations = nullptr;
int runtime_visible_type_annotations_length = 0;
- const u1* runtime_invisible_type_annotations = nullptr;
- int runtime_invisible_type_annotations_length = 0;
bool runtime_invisible_annotations_exists = false;
bool runtime_invisible_type_annotations_exists = false;
bool runtime_invisible_parameter_annotations_exists = false;
@@ -2349,7 +2218,7 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
cfs->guarantee_more(6, CHECK_NULL); // method_attribute_name_index, method_attribute_length
const u2 method_attribute_name_index = cfs->get_u2_fast();
const u4 method_attribute_length = cfs->get_u4_fast();
- check_property(
+ guarantee_property(
valid_symbol_at(method_attribute_name_index),
"Invalid method attribute name index %u in class file %s",
method_attribute_name_index, CHECK_NULL);
@@ -2424,10 +2293,10 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
calculated_attribute_length += code_attribute_length +
(unsigned)sizeof(code_attribute_name_index) +
(unsigned)sizeof(code_attribute_length);
- check_property(valid_symbol_at(code_attribute_name_index),
- "Invalid code attribute name index %u in class file %s",
- code_attribute_name_index,
- CHECK_NULL);
+ guarantee_property(valid_symbol_at(code_attribute_name_index),
+ "Invalid code attribute name index %u in class file %s",
+ code_attribute_name_index,
+ CHECK_NULL);
if (LoadLineNumberTables &&
cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) {
// Parse and compress line number table
@@ -2607,11 +2476,6 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
return nullptr;
}
runtime_invisible_annotations_exists = true;
- if (PreserveAllAnnotations) {
- runtime_invisible_annotations_length = method_attribute_length;
- runtime_invisible_annotations = cfs->current();
- assert(runtime_invisible_annotations != nullptr, "null invisible annotations");
- }
cfs->skip_u1(method_attribute_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_visible_parameter_annotations()) {
if (runtime_visible_parameter_annotations != nullptr) {
@@ -2632,12 +2496,6 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
return nullptr;
}
runtime_invisible_parameter_annotations_exists = true;
- if (PreserveAllAnnotations) {
- runtime_invisible_parameter_annotations_length = method_attribute_length;
- runtime_invisible_parameter_annotations = cfs->current();
- assert(runtime_invisible_parameter_annotations != nullptr,
- "null invisible parameter annotations");
- }
cfs->skip_u1(method_attribute_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_annotation_default()) {
if (annotation_default != nullptr) {
@@ -2668,14 +2526,8 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
"Multiple RuntimeInvisibleTypeAnnotations attributes for method in class file %s",
THREAD);
return nullptr;
- } else {
- runtime_invisible_type_annotations_exists = true;
- }
- if (PreserveAllAnnotations) {
- runtime_invisible_type_annotations_length = method_attribute_length;
- runtime_invisible_type_annotations = cfs->current();
- assert(runtime_invisible_type_annotations != nullptr, "null invisible type annotations");
}
+ runtime_invisible_type_annotations_exists = true;
cfs->skip_u1(method_attribute_length, CHECK_NULL);
} else {
// Skip unknown attributes
@@ -2709,12 +2561,9 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
checked_exceptions_length,
method_parameters_length,
generic_signature_index,
- runtime_visible_annotations_length +
- runtime_invisible_annotations_length,
- runtime_visible_parameter_annotations_length +
- runtime_invisible_parameter_annotations_length,
- runtime_visible_type_annotations_length +
- runtime_invisible_type_annotations_length,
+ runtime_visible_annotations_length,
+ runtime_visible_parameter_annotations_length,
+ runtime_visible_type_annotations_length,
annotation_default_length,
0);
@@ -2806,16 +2655,10 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
copy_method_annotations(m->constMethod(),
runtime_visible_annotations,
runtime_visible_annotations_length,
- runtime_invisible_annotations,
- runtime_invisible_annotations_length,
runtime_visible_parameter_annotations,
runtime_visible_parameter_annotations_length,
- runtime_invisible_parameter_annotations,
- runtime_invisible_parameter_annotations_length,
runtime_visible_type_annotations,
runtime_visible_type_annotations_length,
- runtime_invisible_type_annotations,
- runtime_invisible_type_annotations_length,
annotation_default,
annotation_default_length,
CHECK_NULL);
@@ -2938,7 +2781,7 @@ u2 ClassFileParser::parse_generic_signature_attribute(const ClassFileStream* con
cfs->guarantee_more(2, CHECK_0); // generic_signature_index
const u2 generic_signature_index = cfs->get_u2_fast();
- check_property(
+ guarantee_property(
valid_symbol_at(generic_signature_index),
"Invalid Signature attribute at constant pool index %u in class file %s",
generic_signature_index, CHECK_0);
@@ -2952,7 +2795,7 @@ void ClassFileParser::parse_classfile_sourcefile_attribute(const ClassFileStream
cfs->guarantee_more(2, CHECK); // sourcefile_index
const u2 sourcefile_index = cfs->get_u2_fast();
- check_property(
+ guarantee_property(
valid_symbol_at(sourcefile_index),
"Invalid SourceFile attribute at constant pool index %u in class file %s",
sourcefile_index, CHECK);
@@ -3099,13 +2942,13 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ClassFileStrea
for (int n = 0; n < length; n++) {
// Inner class index
const u2 inner_class_info_index = cfs->get_u2_fast();
- check_property(
+ guarantee_property(
valid_klass_reference_at(inner_class_info_index),
"inner_class_info_index %u has bad constant type in class file %s",
inner_class_info_index, CHECK_0);
// Outer class index
const u2 outer_class_info_index = cfs->get_u2_fast();
- check_property(
+ guarantee_property(
outer_class_info_index == 0 ||
valid_klass_reference_at(outer_class_info_index),
"outer_class_info_index %u has bad constant type in class file %s",
@@ -3119,7 +2962,7 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ClassFileStrea
}
// Inner class name
const u2 inner_name_index = cfs->get_u2_fast();
- check_property(
+ guarantee_property(
inner_name_index == 0 || valid_symbol_at(inner_name_index),
"inner_name_index %u has bad constant type in class file %s",
inner_name_index, CHECK_0);
@@ -3195,7 +3038,7 @@ u2 ClassFileParser::parse_classfile_nest_members_attribute(const ClassFileStream
cfs->guarantee_more(2 * length, CHECK_0);
for (int n = 0; n < length; n++) {
const u2 class_info_index = cfs->get_u2_fast();
- check_property(
+ guarantee_property(
valid_klass_reference_at(class_info_index),
"Nest member class_info_index %u has bad constant type in class file %s",
class_info_index, CHECK_0);
@@ -3228,7 +3071,7 @@ u2 ClassFileParser::parse_classfile_permitted_subclasses_attribute(const ClassFi
cfs->guarantee_more(2 * length, CHECK_0);
for (int n = 0; n < length; n++) {
const u2 class_info_index = cfs->get_u2_fast();
- check_property(
+ guarantee_property(
valid_klass_reference_at(class_info_index),
"Permitted subclass class_info_index %u has bad constant type in class file %s",
class_info_index, CHECK_0);
@@ -3277,14 +3120,14 @@ u4 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* cons
cfs->guarantee_more(6, CHECK_0); // name_index, descriptor_index, attributes_count
const u2 name_index = cfs->get_u2_fast();
- check_property(valid_symbol_at(name_index),
+ guarantee_property(valid_symbol_at(name_index),
"Invalid constant pool index %u for name in Record attribute in class file %s",
name_index, CHECK_0);
const Symbol* const name = cp->symbol_at(name_index);
verify_legal_field_name(name, CHECK_0);
const u2 descriptor_index = cfs->get_u2_fast();
- check_property(valid_symbol_at(descriptor_index),
+ guarantee_property(valid_symbol_at(descriptor_index),
"Invalid constant pool index %u for descriptor in Record attribute in class file %s",
descriptor_index, CHECK_0);
const Symbol* const descr = cp->symbol_at(descriptor_index);
@@ -3295,13 +3138,9 @@ u4 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* cons
u2 generic_sig_index = 0;
const u1* runtime_visible_annotations = nullptr;
int runtime_visible_annotations_length = 0;
- const u1* runtime_invisible_annotations = nullptr;
- int runtime_invisible_annotations_length = 0;
bool runtime_invisible_annotations_exists = false;
const u1* runtime_visible_type_annotations = nullptr;
int runtime_visible_type_annotations_length = 0;
- const u1* runtime_invisible_type_annotations = nullptr;
- int runtime_invisible_type_annotations_length = 0;
bool runtime_invisible_type_annotations_exists = false;
// Expected attributes for record components are Signature, Runtime(In)VisibleAnnotations,
@@ -3311,7 +3150,7 @@ u4 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* cons
const u2 attribute_name_index = cfs->get_u2_fast();
const u4 attribute_length = cfs->get_u4_fast();
calculate_attr_size += 6;
- check_property(
+ guarantee_property(
valid_symbol_at(attribute_name_index),
"Invalid Record attribute name index %u in class file %s",
attribute_name_index, CHECK_0);
@@ -3352,11 +3191,6 @@ u4 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* cons
return 0;
}
runtime_invisible_annotations_exists = true;
- if (PreserveAllAnnotations) {
- runtime_invisible_annotations_length = attribute_length;
- runtime_invisible_annotations = cfs->current();
- assert(runtime_invisible_annotations != nullptr, "null record component invisible annotation");
- }
cfs->skip_u1(attribute_length, CHECK_0);
} else if (attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) {
@@ -3379,11 +3213,6 @@ u4 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* cons
return 0;
}
runtime_invisible_type_annotations_exists = true;
- if (PreserveAllAnnotations) {
- runtime_invisible_type_annotations_length = attribute_length;
- runtime_invisible_type_annotations = cfs->current();
- assert(runtime_invisible_type_annotations != nullptr, "null record component invisible type annotation");
- }
cfs->skip_u1(attribute_length, CHECK_0);
} else {
@@ -3393,15 +3222,11 @@ u4 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* cons
calculate_attr_size += attribute_length;
} // End of attributes For loop
- AnnotationArray* annotations = assemble_annotations(runtime_visible_annotations,
+ AnnotationArray* annotations = allocate_annotations(runtime_visible_annotations,
runtime_visible_annotations_length,
- runtime_invisible_annotations,
- runtime_invisible_annotations_length,
CHECK_0);
- AnnotationArray* type_annotations = assemble_annotations(runtime_visible_type_annotations,
+ AnnotationArray* type_annotations = allocate_annotations(runtime_visible_type_annotations,
runtime_visible_type_annotations_length,
- runtime_invisible_type_annotations,
- runtime_invisible_type_annotations_length,
CHECK_0);
RecordComponent* record_component =
@@ -3423,7 +3248,7 @@ void ClassFileParser::parse_classfile_signature_attribute(const ClassFileStream*
assert(cfs != nullptr, "invariant");
const u2 signature_index = cfs->get_u2(CHECK);
- check_property(
+ guarantee_property(
valid_symbol_at(signature_index),
"Invalid constant pool index %u in Signature attribute in class file %s",
signature_index, CHECK);
@@ -3481,7 +3306,7 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
cfs->guarantee_more(sizeof(u2) * 2, CHECK); // bsm, argc
const u2 bootstrap_method_index = cfs->get_u2_fast();
const u2 argument_count = cfs->get_u2_fast();
- check_property(
+ guarantee_property(
valid_cp_range(bootstrap_method_index, cp_size) &&
cp->tag_at(bootstrap_method_index).is_method_handle(),
"bootstrap_method_index %u has bad constant type in class file %s",
@@ -3498,7 +3323,7 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
cfs->guarantee_more(sizeof(u2) * argument_count, CHECK); // argv[argc]
for (int j = 0; j < argument_count; j++) {
const u2 argument_index = cfs->get_u2_fast();
- check_property(
+ guarantee_property(
valid_cp_range(argument_index, cp_size) &&
cp->tag_at(argument_index).is_loadable_constant(),
"argument_index %u has bad constant type in class file %s",
@@ -3538,12 +3363,8 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
bool parsed_bootstrap_methods_attribute = false;
const u1* runtime_visible_annotations = nullptr;
int runtime_visible_annotations_length = 0;
- const u1* runtime_invisible_annotations = nullptr;
- int runtime_invisible_annotations_length = 0;
const u1* runtime_visible_type_annotations = nullptr;
int runtime_visible_type_annotations_length = 0;
- const u1* runtime_invisible_type_annotations = nullptr;
- int runtime_invisible_type_annotations_length = 0;
bool runtime_invisible_type_annotations_exists = false;
bool runtime_invisible_annotations_exists = false;
bool parsed_source_debug_ext_annotations_exist = false;
@@ -3563,7 +3384,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length
const u2 attribute_name_index = cfs->get_u2_fast();
const u4 attribute_length = cfs->get_u4_fast();
- check_property(
+ guarantee_property(
valid_symbol_at(attribute_name_index),
"Attribute name has bad constant pool index %u in class file %s",
attribute_name_index, CHECK);
@@ -3656,11 +3477,6 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
return;
}
runtime_invisible_annotations_exists = true;
- if (PreserveAllAnnotations) {
- runtime_invisible_annotations_length = attribute_length;
- runtime_invisible_annotations = cfs->current();
- assert(runtime_invisible_annotations != nullptr, "null invisible annotations");
- }
cfs->skip_u1(attribute_length, CHECK);
} else if (tag == vmSymbols::tag_enclosing_method()) {
if (parsed_enclosingmethod_attribute) {
@@ -3680,7 +3496,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
return;
}
// Validate the constant pool indices and types
- check_property(valid_klass_reference_at(enclosing_method_class_index),
+ guarantee_property(valid_klass_reference_at(enclosing_method_class_index),
"Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK);
if (enclosing_method_method_index != 0 &&
(!cp->is_within_bounds(enclosing_method_method_index) ||
@@ -3712,14 +3528,8 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
classfile_parse_error(
"Multiple RuntimeInvisibleTypeAnnotations attributes in class file %s", THREAD);
return;
- } else {
- runtime_invisible_type_annotations_exists = true;
- }
- if (PreserveAllAnnotations) {
- runtime_invisible_type_annotations_length = attribute_length;
- runtime_invisible_type_annotations = cfs->current();
- assert(runtime_invisible_type_annotations != nullptr, "null invisible type annotations");
}
+ runtime_invisible_type_annotations_exists = true;
cfs->skip_u1(attribute_length, CHECK);
} else if (_major_version >= JAVA_11_VERSION) {
if (tag == vmSymbols::tag_nest_members()) {
@@ -3753,7 +3563,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
}
cfs->guarantee_more(2, CHECK);
u2 class_info_index = cfs->get_u2_fast();
- check_property(
+ guarantee_property(
valid_klass_reference_at(class_info_index),
"Nest-host class_info_index %u has bad constant type in class file %s",
class_info_index, CHECK);
@@ -3799,15 +3609,11 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
cfs->skip_u1(attribute_length, CHECK);
}
}
- _class_annotations = assemble_annotations(runtime_visible_annotations,
+ _class_annotations = allocate_annotations(runtime_visible_annotations,
runtime_visible_annotations_length,
- runtime_invisible_annotations,
- runtime_invisible_annotations_length,
CHECK);
- _class_type_annotations = assemble_annotations(runtime_visible_type_annotations,
+ _class_type_annotations = allocate_annotations(runtime_visible_type_annotations,
runtime_visible_type_annotations_length,
- runtime_invisible_type_annotations,
- runtime_invisible_type_annotations_length,
CHECK);
if (parsed_innerclasses_attribute || parsed_enclosingmethod_attribute) {
@@ -3943,28 +3749,16 @@ void ClassFileParser::apply_parsed_class_metadata(
clear_class_metadata();
}
-AnnotationArray* ClassFileParser::assemble_annotations(const u1* const runtime_visible_annotations,
- int runtime_visible_annotations_length,
- const u1* const runtime_invisible_annotations,
- int runtime_invisible_annotations_length,
+AnnotationArray* ClassFileParser::allocate_annotations(const u1* const anno,
+ int anno_length,
TRAPS) {
AnnotationArray* annotations = nullptr;
- if (runtime_visible_annotations != nullptr ||
- runtime_invisible_annotations != nullptr) {
+ if (anno != nullptr) {
annotations = MetadataFactory::new_array(_loader_data,
- runtime_visible_annotations_length +
- runtime_invisible_annotations_length,
- CHECK_(annotations));
- if (runtime_visible_annotations != nullptr) {
- for (int i = 0; i < runtime_visible_annotations_length; i++) {
- annotations->at_put(i, runtime_visible_annotations[i]);
- }
- }
- if (runtime_invisible_annotations != nullptr) {
- for (int i = 0; i < runtime_invisible_annotations_length; i++) {
- int append = runtime_visible_annotations_length+i;
- annotations->at_put(append, runtime_invisible_annotations[i]);
- }
+ anno_length,
+ CHECK_(annotations));
+ for (int i = 0; i < anno_length; i++) {
+ annotations->at_put(i, anno[i]);
}
}
return annotations;
@@ -3978,15 +3772,15 @@ const InstanceKlass* ClassFileParser::parse_super_class(ConstantPool* const cp,
const InstanceKlass* super_klass = nullptr;
if (super_class_index == 0) {
- check_property(_class_name == vmSymbols::java_lang_Object(),
- "Invalid superclass index %u in class file %s",
- super_class_index,
- CHECK_NULL);
+ guarantee_property(_class_name == vmSymbols::java_lang_Object(),
+ "Invalid superclass index %u in class file %s",
+ super_class_index,
+ CHECK_NULL);
} else {
- check_property(valid_klass_reference_at(super_class_index),
- "Invalid superclass index %u in class file %s",
- super_class_index,
- CHECK_NULL);
+ guarantee_property(valid_klass_reference_at(super_class_index),
+ "Invalid superclass index %u in class file %s",
+ super_class_index,
+ CHECK_NULL);
// The class name should be legal because it is checked when parsing constant pool.
// However, make sure it is not an array type.
bool is_array = false;
@@ -4265,26 +4059,6 @@ void ClassFileParser::check_super_class_access(const InstanceKlass* this_klass,
return;
}
- // If the loader is not the boot loader then throw an exception if its
- // superclass is in package jdk.internal.reflect and its loader is not a
- // special reflection class loader
- if (!this_klass->class_loader_data()->is_the_null_class_loader_data()) {
- PackageEntry* super_package = super->package();
- if (super_package != nullptr &&
- super_package->name()->fast_compare(vmSymbols::jdk_internal_reflect()) == 0 &&
- !java_lang_ClassLoader::is_reflection_class_loader(this_klass->class_loader())) {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(
- THREAD_AND_LOCATION,
- vmSymbols::java_lang_IllegalAccessError(),
- "class %s loaded by %s cannot access jdk/internal/reflect superclass %s",
- this_klass->external_name(),
- this_klass->class_loader_data()->loader_name_and_id(),
- super->external_name());
- return;
- }
- }
-
Reflection::VerifyClassAccessResults vca_result =
Reflection::verify_class_access(this_klass, InstanceKlass::cast(super), false);
if (vca_result != Reflection::ACCESS_OK) {
@@ -4677,7 +4451,8 @@ void ClassFileParser::verify_legal_utf8(const unsigned char* buffer,
int length,
TRAPS) const {
assert(_need_verify, "only called when _need_verify is true");
- if (!UTF8::is_legal_utf8(buffer, length, _major_version <= 47)) {
+ // Note: 0 <= length < 64K, as it comes from a u2 entry in the CP.
+ if (!UTF8::is_legal_utf8(buffer, static_cast(length), _major_version <= 47)) {
classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", THREAD);
}
}
@@ -5234,8 +5009,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
// Not yet: supers are done below to support the new subtype-checking fields
ik->set_nonstatic_field_size(_field_info->_nonstatic_field_size);
ik->set_has_nonstatic_fields(_field_info->_has_nonstatic_fields);
- assert(_fac != nullptr, "invariant");
- ik->set_static_oop_field_count(_fac->count[STATIC_OOP]);
+ ik->set_static_oop_field_count(_static_oop_count);
// this transfers ownership of a lot of arrays from
// the parser onto the InstanceKlass*
@@ -5291,13 +5065,11 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
ik->set_has_nonstatic_concrete_methods(_has_nonstatic_concrete_methods);
ik->set_declares_nonstatic_concrete_methods(_declares_nonstatic_concrete_methods);
- if (_is_hidden) {
- ik->set_is_hidden();
- }
+ assert(!_is_hidden || ik->is_hidden(), "must be set already");
// Set PackageEntry for this_klass
oop cl = ik->class_loader();
- Handle clh = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(cl));
+ Handle clh = Handle(THREAD, cl);
ClassLoaderData* cld = ClassLoaderData::class_loader_data_or_null(clh());
ik->set_package(cld, nullptr, CHECK);
@@ -5479,6 +5251,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_is_hidden(cl_info->is_hidden()),
_can_access_vm_annotations(cl_info->can_access_vm_annotations()),
_orig_cp_size(0),
+ _static_oop_count(0),
_super_klass(),
_cp(nullptr),
_fieldinfo_stream(nullptr),
@@ -5499,7 +5272,6 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_klass(nullptr),
_klass_to_deallocate(nullptr),
_parsed_annotations(nullptr),
- _fac(nullptr),
_field_info(nullptr),
_temp_field_info(nullptr),
_method_ordering(nullptr),
@@ -5734,7 +5506,7 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
// This class and superclass
_this_class_index = stream->get_u2_fast();
- check_property(
+ guarantee_property(
valid_cp_range(_this_class_index, cp_size) &&
cp->tag_at(_this_class_index).is_unresolved_klass(),
"Invalid this class index %u in constant pool in class file %s",
@@ -5825,10 +5597,8 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
assert(_local_interfaces != nullptr, "invariant");
// Fields (offsets are filled in later)
- _fac = new FieldAllocationCount();
parse_fields(stream,
_access_flags.is_interface(),
- _fac,
cp,
cp_size,
&_java_fields_count,
@@ -5917,9 +5687,9 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st
assert(_loader_data != nullptr, "invariant");
if (_class_name == vmSymbols::java_lang_Object()) {
- check_property(_local_interfaces == Universe::the_empty_instance_klass_array(),
- "java.lang.Object cannot implement an interface in class file %s",
- CHECK);
+ guarantee_property(_local_interfaces == Universe::the_empty_instance_klass_array(),
+ "java.lang.Object cannot implement an interface in class file %s",
+ CHECK);
}
// We check super class after class file is parsed and format is checked
if (_super_class_index > 0 && nullptr == _super_klass) {
@@ -5986,7 +5756,6 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st
_itable_size = _access_flags.is_interface() ? 0 :
klassItable::compute_itable_size(_transitive_interfaces);
- assert(_fac != nullptr, "invariant");
assert(_parsed_annotations != nullptr, "invariant");
_field_info = new FieldLayoutInfo();
diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp
index f43303722a8..a8a388f8ded 100644
--- a/src/hotspot/share/classfile/classFileParser.hpp
+++ b/src/hotspot/share/classfile/classFileParser.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
@@ -86,7 +86,6 @@ class ClassFileParser {
friend class FieldLayout;
class ClassAnnotationCollector;
- class FieldAllocationCount;
class FieldAnnotationCollector;
public:
@@ -116,6 +115,7 @@ class ClassFileParser {
const bool _is_hidden;
const bool _can_access_vm_annotations;
int _orig_cp_size;
+ unsigned int _static_oop_count;
// Metadata created before the instance klass is created. Must be deallocated
// if not transferred to the InstanceKlass upon successful class loading
@@ -141,7 +141,6 @@ class ClassFileParser {
InstanceKlass* _klass_to_deallocate; // an InstanceKlass* to be destroyed
ClassAnnotationCollector* _parsed_annotations;
- FieldAllocationCount* _fac;
FieldLayoutInfo* _field_info;
GrowableArray* _temp_field_info;
const intArray* _method_ordering;
@@ -260,7 +259,6 @@ class ClassFileParser {
void parse_fields(const ClassFileStream* const cfs,
bool is_interface,
- FieldAllocationCount* const fac,
ConstantPool* cp,
const int cp_size,
u2* const java_fields_count_ptr,
@@ -347,10 +345,8 @@ class ClassFileParser {
TRAPS);
// Annotations handling
- AnnotationArray* assemble_annotations(const u1* const runtime_visible_annotations,
- int runtime_visible_annotations_length,
- const u1* const runtime_invisible_annotations,
- int runtime_invisible_annotations_length,
+ AnnotationArray* allocate_annotations(const u1* const anno,
+ int anno_length,
TRAPS);
void set_precomputed_flags(InstanceKlass* k);
@@ -382,44 +378,6 @@ class ClassFileParser {
if (!b) { classfile_parse_error(msg, THREAD); return; }
}
- void report_assert_property_failure(const char* msg, TRAPS) const PRODUCT_RETURN;
- void report_assert_property_failure(const char* msg, int index, TRAPS) const PRODUCT_RETURN;
-
- inline void assert_property(bool b, const char* msg, TRAPS) const {
-#ifdef ASSERT
- if (!b) {
- report_assert_property_failure(msg, THREAD);
- }
-#endif
- }
-
- inline void assert_property(bool b, const char* msg, int index, TRAPS) const {
-#ifdef ASSERT
- if (!b) {
- report_assert_property_failure(msg, index, THREAD);
- }
-#endif
- }
-
- inline void check_property(bool property,
- const char* msg,
- int index,
- TRAPS) const {
- if (_need_verify) {
- guarantee_property(property, msg, index, CHECK);
- } else {
- assert_property(property, msg, index, CHECK);
- }
- }
-
- inline void check_property(bool property, const char* msg, TRAPS) const {
- if (_need_verify) {
- guarantee_property(property, msg, CHECK);
- } else {
- assert_property(property, msg, CHECK);
- }
- }
-
inline void guarantee_property(bool b,
const char* msg,
int index,
@@ -514,16 +472,10 @@ class ClassFileParser {
void copy_method_annotations(ConstMethod* cm,
const u1* runtime_visible_annotations,
int runtime_visible_annotations_length,
- const u1* runtime_invisible_annotations,
- int runtime_invisible_annotations_length,
const u1* runtime_visible_parameter_annotations,
int runtime_visible_parameter_annotations_length,
- const u1* runtime_invisible_parameter_annotations,
- int runtime_invisible_parameter_annotations_length,
const u1* runtime_visible_type_annotations,
int runtime_visible_type_annotations_length,
- const u1* runtime_invisible_type_annotations,
- int runtime_invisible_type_annotations_length,
const u1* annotation_default,
int annotation_default_length,
TRAPS);
@@ -557,6 +509,7 @@ class ClassFileParser {
bool is_hidden() const { return _is_hidden; }
bool is_interface() const { return _access_flags.is_interface(); }
+ bool is_abstract() const { return _access_flags.is_abstract(); }
ClassLoaderData* loader_data() const { return _loader_data; }
const Symbol* class_name() const { return _class_name; }
diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp
index e410824e300..9a68e264044 100644
--- a/src/hotspot/share/classfile/classLoader.cpp
+++ b/src/hotspot/share/classfile/classLoader.cpp
@@ -81,6 +81,9 @@
#include "utilities/ostream.hpp"
#include "utilities/utf8.hpp"
+#include
+#include
+
// Entry point in java.dll for path canonicalization
typedef int (*canonicalize_fn_t)(const char *orig, char *out, int len);
@@ -579,6 +582,8 @@ void ClassLoader::setup_module_search_path(JavaThread* current, const char* path
new_entry = create_class_path_entry(current, path, &st,
false /*is_boot_append */, false /* from_class_path_attr */);
if (new_entry != nullptr) {
+ // ClassLoaderExt::process_module_table() filters out non-jar entries before calling this function.
+ assert(new_entry->is_jar_file(), "module path entry %s is not a jar file", new_entry->name());
add_to_module_path_entries(path, new_entry);
}
}
@@ -834,7 +839,8 @@ bool ClassLoader::add_to_app_classpath_entries(JavaThread* current,
ClassPathEntry* e = _app_classpath_entries;
if (check_for_duplicates) {
while (e != nullptr) {
- if (strcmp(e->name(), entry->name()) == 0) {
+ if (strcmp(e->name(), entry->name()) == 0 &&
+ e->from_class_path_attr() == entry->from_class_path_attr()) {
// entry already exists
return false;
}
@@ -1208,7 +1214,7 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, PackageEntry* pkg_entry, bo
}
#if INCLUDE_CDS
-char* ClassLoader::skip_uri_protocol(char* source) {
+static const char* skip_uri_protocol(const char* source) {
if (strncmp(source, "file:", 5) == 0) {
// file: protocol path could start with file:/ or file:///
// locate the char after all the forward slashes
@@ -1227,6 +1233,47 @@ char* ClassLoader::skip_uri_protocol(char* source) {
return source;
}
+static char decode_percent_encoded(const char *str, size_t& index) {
+ if (str[index] == '%'
+ && isxdigit(str[index + 1])
+ && isxdigit(str[index + 2])) {
+ char hex[3];
+ hex[0] = str[index + 1];
+ hex[1] = str[index + 2];
+ hex[2] = '\0';
+ index += 2;
+ return (char) strtol(hex, NULL, 16);
+ }
+ return str[index];
+}
+
+char* ClassLoader::uri_to_path(const char* uri) {
+ const size_t len = strlen(uri) + 1;
+ char* path = NEW_RESOURCE_ARRAY(char, len);
+
+ uri = skip_uri_protocol(uri);
+
+ if (strncmp(uri, "//", 2) == 0) {
+ // Skip the empty "authority" part
+ uri += 2;
+ }
+
+#ifdef _WINDOWS
+ if (uri[0] == '/') {
+ // Absolute path name on Windows does not begin with a slash
+ uri += 1;
+ }
+#endif
+
+ size_t path_index = 0;
+ for (size_t i = 0; i < strlen(uri); ++i) {
+ char decoded = decode_percent_encoded(uri, i);
+ path[path_index++] = decoded;
+ }
+ path[path_index] = '\0';
+ return path;
+}
+
// Record the shared classpath index and loader type for classes loaded
// by the builtin loaders at dump time.
void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik,
@@ -1260,7 +1307,7 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik,
// Save the path from the file: protocol or the module name from the jrt: protocol
// if no protocol prefix is found, path is the same as stream->source(). This path
// must be valid since the class has been successfully parsed.
- char* path = skip_uri_protocol(src);
+ const char* path = ClassLoader::uri_to_path(src);
assert(path != nullptr, "sanity");
for (int i = 0; i < FileMapInfo::get_number_of_shared_paths(); i++) {
SharedClassPathEntry* ent = FileMapInfo::shared_path(i);
diff --git a/src/hotspot/share/classfile/classLoader.hpp b/src/hotspot/share/classfile/classLoader.hpp
index af625082dda..e44059b7247 100644
--- a/src/hotspot/share/classfile/classLoader.hpp
+++ b/src/hotspot/share/classfile/classLoader.hpp
@@ -382,7 +382,7 @@ class ClassLoader: AllStatic {
// entries during shared classpath setup time.
static int num_module_path_entries();
static void exit_with_path_failure(const char* error, const char* message);
- static char* skip_uri_protocol(char* source);
+ static char* uri_to_path(const char* uri);
static void record_result(JavaThread* current, InstanceKlass* ik,
const ClassFileStream* stream, bool redefined);
#endif
diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp
index de4490e73f3..de0b16a907a 100644
--- a/src/hotspot/share/classfile/classLoaderData.cpp
+++ b/src/hotspot/share/classfile/classLoaderData.cpp
@@ -141,7 +141,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool has_class_mirror_ho
// A non-strong hidden class loader data doesn't have anything to keep
// it from being unloaded during parsing of the non-strong hidden class.
// The null-class-loader should always be kept alive.
- _keep_alive((has_class_mirror_holder || h_class_loader.is_null()) ? 1 : 0),
+ _keep_alive_ref_count((has_class_mirror_holder || h_class_loader.is_null()) ? 1 : 0),
_claim(0),
_handles(),
_klasses(nullptr), _packages(nullptr), _modules(nullptr), _unnamed_module(nullptr), _dictionary(nullptr),
@@ -345,26 +345,26 @@ void ClassLoaderData::demote_strong_roots() {
// while the class is being parsed, and if the class appears on the module fixup list.
// Due to the uniqueness that no other class shares the hidden class' name or
// ClassLoaderData, no other non-GC thread has knowledge of the hidden class while
-// it is being defined, therefore _keep_alive is not volatile or atomic.
-void ClassLoaderData::inc_keep_alive() {
+// it is being defined, therefore _keep_alive_ref_count is not volatile or atomic.
+void ClassLoaderData::inc_keep_alive_ref_count() {
if (has_class_mirror_holder()) {
- assert(_keep_alive > 0, "Invalid keep alive increment count");
- _keep_alive++;
+ assert(_keep_alive_ref_count > 0, "Invalid keep alive increment count");
+ _keep_alive_ref_count++;
}
}
-void ClassLoaderData::dec_keep_alive() {
+void ClassLoaderData::dec_keep_alive_ref_count() {
if (has_class_mirror_holder()) {
- assert(_keep_alive > 0, "Invalid keep alive decrement count");
- if (_keep_alive == 1) {
- // When the keep_alive counter is 1, the oop handle area is a strong root,
+ assert(_keep_alive_ref_count > 0, "Invalid keep alive decrement count");
+ if (_keep_alive_ref_count == 1) {
+ // When the keep_alive_ref_count counter is 1, the oop handle area is a strong root,
// acting as input to the GC tracing. Such strong roots are part of the
// snapshot-at-the-beginning, and can not just be pulled out from the
// system when concurrent GCs are running at the same time, without
// invoking the right barriers.
demote_strong_roots();
}
- _keep_alive--;
+ _keep_alive_ref_count--;
}
}
@@ -644,8 +644,6 @@ Dictionary* ClassLoaderData::create_dictionary() {
int size;
if (_the_null_class_loader_data == nullptr) {
size = _boot_loader_dictionary_size;
- } else if (class_loader()->is_a(vmClasses::reflect_DelegatingClassLoader_klass())) {
- size = 1; // there's only one class in relection class loader and no initiated classes
} else if (is_system_class_loader_data()) {
size = _boot_loader_dictionary_size;
} else {
@@ -680,8 +678,8 @@ oop ClassLoaderData::holder_no_keepalive() const {
// Unloading support
bool ClassLoaderData::is_alive() const {
- bool alive = keep_alive() // null class loader and incomplete non-strong hidden class.
- || (_holder.peek() != nullptr); // and not cleaned by the GC weak handle processing.
+ bool alive = (_keep_alive_ref_count > 0) // null class loader and incomplete non-strong hidden class.
+ || (_holder.peek() != nullptr); // and not cleaned by the GC weak handle processing.
return alive;
}
@@ -815,8 +813,6 @@ ClassLoaderMetaspace* ClassLoaderData::metaspace_non_null() {
metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::BootMetaspaceType);
} else if (has_class_mirror_holder()) {
metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::ClassMirrorHolderMetaspaceType);
- } else if (class_loader()->is_a(vmClasses::reflect_DelegatingClassLoader_klass())) {
- metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType);
} else {
metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::StandardMetaspaceType);
}
@@ -1009,7 +1005,7 @@ void ClassLoaderData::print_on(outputStream* out) const {
out->print_cr(" - unloading %s", _unloading ? "true" : "false");
out->print_cr(" - class mirror holder %s", _has_class_mirror_holder ? "true" : "false");
out->print_cr(" - modified oops %s", _modified_oops ? "true" : "false");
- out->print_cr(" - keep alive %d", _keep_alive);
+ out->print_cr(" - _keep_alive_ref_count %d", _keep_alive_ref_count);
out->print (" - claim ");
switch(_claim) {
case _claim_none: out->print_cr("none"); break;
diff --git a/src/hotspot/share/classfile/classLoaderData.hpp b/src/hotspot/share/classfile/classLoaderData.hpp
index c9d025aded1..19dbb0b1b36 100644
--- a/src/hotspot/share/classfile/classLoaderData.hpp
+++ b/src/hotspot/share/classfile/classLoaderData.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -125,10 +125,10 @@ class ClassLoaderData : public CHeapObj {
// Remembered sets support for the oops in the class loader data.
bool _modified_oops; // Card Table Equivalent
- int _keep_alive; // if this CLD is kept alive.
- // Used for non-strong hidden classes and the
- // boot class loader. _keep_alive does not need to be volatile or
- // atomic since there is one unique CLD per non-strong hidden class.
+ int _keep_alive_ref_count; // if this CLD should not be considered eligible for unloading.
+ // Used for non-strong hidden classes and the
+ // boot class loader. _keep_alive_ref_count does not need to be volatile or
+ // atomic since there is one unique CLD per non-strong hidden class.
volatile int _claim; // non-zero if claimed, for example during GC traces.
// To avoid applying oop closure more than once.
@@ -205,12 +205,14 @@ class ClassLoaderData : public CHeapObj {
bool has_modified_oops() { return _modified_oops; }
oop holder_no_keepalive() const;
+ // Resolving the holder keeps this CLD alive for the current GC cycle.
oop holder() const;
+ void keep_alive() const { (void)holder(); }
void classes_do(void f(Klass* const));
private:
- bool keep_alive() const { return _keep_alive > 0; }
+ int keep_alive_ref_count() const { return _keep_alive_ref_count; }
void loaded_classes_do(KlassClosure* klass_closure);
void classes_do(void f(InstanceKlass*));
@@ -302,9 +304,10 @@ class ClassLoaderData : public CHeapObj {
return _unloading;
}
- // Used to refcount a non-strong hidden class's s CLD in order to indicate their aliveness.
- void inc_keep_alive();
- void dec_keep_alive();
+ // Used to refcount a non-strong hidden class's CLD in order to force its aliveness during
+ // loading, when gc tracing may not find this CLD alive through the holder.
+ void inc_keep_alive_ref_count();
+ void dec_keep_alive_ref_count();
void initialize_holder(Handle holder);
@@ -335,8 +338,8 @@ class ClassLoaderData : public CHeapObj {
bool modules_defined() { return (_modules != nullptr); }
// Offsets
- static ByteSize holder_offset() { return byte_offset_of(ClassLoaderData, _holder); }
- static ByteSize keep_alive_offset() { return byte_offset_of(ClassLoaderData, _keep_alive); }
+ static ByteSize holder_offset() { return byte_offset_of(ClassLoaderData, _holder); }
+ static ByteSize keep_alive_ref_count_offset() { return byte_offset_of(ClassLoaderData, _keep_alive_ref_count); }
// Loaded class dictionary
Dictionary* dictionary() const { return _dictionary; }
diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.cpp b/src/hotspot/share/classfile/classLoaderDataGraph.cpp
index adec6dbdeee..c7051cd58e7 100644
--- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp
+++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -201,7 +201,7 @@ void ClassLoaderDataGraph::cld_do(CLDClosure* cl) {
void ClassLoaderDataGraph::roots_cld_do(CLDClosure* strong, CLDClosure* weak) {
assert_is_safepoint_or_gc();
for (ClassLoaderData* cld = Atomic::load_acquire(&_head); cld != nullptr; cld = cld->next()) {
- CLDClosure* closure = cld->keep_alive() ? strong : weak;
+ CLDClosure* closure = (cld->keep_alive_ref_count() > 0) ? strong : weak;
if (closure != nullptr) {
closure->do_cld(cld);
}
@@ -309,8 +309,7 @@ void ClassLoaderDataGraph::modules_do_keepalive(void f(ModuleEntry*)) {
assert_locked_or_safepoint(Module_lock);
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
- // Keep the holder alive.
- (void)cld->holder();
+ cld->keep_alive();
cld->modules_do(f);
}
}
@@ -334,8 +333,7 @@ void ClassLoaderDataGraph::packages_do(void f(PackageEntry*)) {
void ClassLoaderDataGraph::loaded_classes_do_keepalive(KlassClosure* klass_closure) {
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
- // Keep the holder alive.
- (void)cld->holder();
+ cld->keep_alive();
cld->loaded_classes_do(klass_closure);
}
}
diff --git a/src/hotspot/share/classfile/classLoaderExt.cpp b/src/hotspot/share/classfile/classLoaderExt.cpp
index 78e29f990d7..16981669deb 100644
--- a/src/hotspot/share/classfile/classLoaderExt.cpp
+++ b/src/hotspot/share/classfile/classLoaderExt.cpp
@@ -55,6 +55,7 @@
jshort ClassLoaderExt::_app_class_paths_start_index = ClassLoaderExt::max_classpath_index;
jshort ClassLoaderExt::_app_module_paths_start_index = ClassLoaderExt::max_classpath_index;
jshort ClassLoaderExt::_max_used_path_index = 0;
+int ClassLoaderExt::_num_module_paths = 0;
bool ClassLoaderExt::_has_app_classes = false;
bool ClassLoaderExt::_has_platform_classes = false;
bool ClassLoaderExt::_has_non_jar_in_classpath = false;
@@ -89,23 +90,25 @@ void ClassLoaderExt::setup_app_search_path(JavaThread* current) {
os::free(app_class_path);
}
+int ClassLoaderExt::compare_module_path_by_name(const char** p1, const char** p2) {
+ return strcmp(*p1, *p2);
+}
+
void ClassLoaderExt::process_module_table(JavaThread* current, ModuleEntryTable* met) {
ResourceMark rm(current);
- GrowableArray* module_paths = new GrowableArray(5);
+ GrowableArray* module_paths = new GrowableArray(5);
class ModulePathsGatherer : public ModuleClosure {
JavaThread* _current;
- GrowableArray