diff --git a/.github/actions/get-msys2/action.yml b/.github/actions/get-msys2/action.yml
index 3e6c3417a31..f6de676a327 100644
--- a/.github/actions/get-msys2/action.yml
+++ b/.github/actions/get-msys2/action.yml
@@ -34,11 +34,11 @@ runs:
with:
install: 'autoconf tar unzip zip make'
path-type: minimal
- location: msys2
+ location: ${{ runner.tool_cache }}/msys2
# We can't run bash until this is completed, so stick with pwsh
- name: 'Set MSYS2 path'
run: |
# Prepend msys2/msys64/usr/bin to the PATH
- echo "$env:GITHUB_WORKSPACE/msys2/msys64/usr/bin" >> $env:GITHUB_PATH
+ echo "$env:RUNNER_TOOL_CACHE/msys2/msys64/usr/bin" >> $env:GITHUB_PATH
shell: pwsh
diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml
index e57db3b63e8..8973219f0ab 100644
--- a/.github/workflows/build-windows.yml
+++ b/.github/workflows/build-windows.yml
@@ -125,6 +125,7 @@ jobs:
# We need a minimal PATH on Windows
# Set PATH to "", so just GITHUB_PATH is included
PATH: ''
+ shell: env /usr/bin/bash --login -eo pipefail {0}
- name: 'Build'
id: build
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index ab22d1c7f45..cf6d69afefd 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -35,7 +35,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'
+ default: 'linux-x64, linux-x86, linux-x64-variants, linux-cross-compile, macos-x64, macos-aarch64, windows-x64, windows-aarch64, docs'
configure-arguments:
description: 'Additional configure arguments'
required: false
@@ -65,6 +65,7 @@ jobs:
macos-aarch64: ${{ steps.include.outputs.macos-aarch64 }}
windows-x64: ${{ steps.include.outputs.windows-x64 }}
windows-aarch64: ${{ steps.include.outputs.windows-aarch64 }}
+ docs: ${{ steps.include.outputs.docs }}
steps:
# This function must be inlined in main.yml, or we'd be forced to checkout the repo
@@ -77,19 +78,17 @@ jobs:
# 'false' otherwise.
# arg $1: platform name or names to look for
function check_platform() {
- if [[ '${{ !secrets.JDK_SUBMIT_FILTER || startsWith(github.ref, 'refs/heads/submit/') }}' == 'false' ]]; then
- # If JDK_SUBMIT_FILTER is set, and this is not a "submit/" branch, don't run anything
- echo 'false'
- return
- fi
-
if [[ $GITHUB_EVENT_NAME == workflow_dispatch ]]; then
input='${{ github.event.inputs.platforms }}'
elif [[ $GITHUB_EVENT_NAME == push ]]; then
- input='${{ secrets.JDK_SUBMIT_PLATFORMS }}'
- else
- echo 'Internal error in GHA'
- exit 1
+ if [[ '${{ !secrets.JDK_SUBMIT_FILTER || startsWith(github.ref, 'refs/heads/submit/') }}' == 'false' ]]; then
+ # If JDK_SUBMIT_FILTER is set, and this is not a "submit/" branch, don't run anything
+ >&2 echo 'JDK_SUBMIT_FILTER is set and not a "submit/" branch'
+ echo 'false'
+ return
+ else
+ input='${{ secrets.JDK_SUBMIT_PLATFORMS }}'
+ fi
fi
normalized_input="$(echo ,$input, | tr -d ' ')"
@@ -118,6 +117,7 @@ jobs:
echo "macos-aarch64=$(check_platform macos-aarch64 macos aarch64)" >> $GITHUB_OUTPUT
echo "windows-x64=$(check_platform windows-x64 windows x64)" >> $GITHUB_OUTPUT
echo "windows-aarch64=$(check_platform windows-aarch64 windows aarch64)" >> $GITHUB_OUTPUT
+ echo "docs=$(check_platform docs)" >> $GITHUB_OUTPUT
###
### Build jobs
@@ -278,6 +278,23 @@ jobs:
make-arguments: ${{ github.event.inputs.make-arguments }}
if: needs.select.outputs.windows-aarch64 == 'true'
+ build-docs:
+ name: docs
+ needs: select
+ uses: ./.github/workflows/build-linux.yml
+ with:
+ platform: linux-x64
+ debug-levels: '[ "debug" ]'
+ make-target: 'docs-jdk-bundles'
+ # Make sure we never try to make full docs, since that would require a
+ # build JDK, and we do not need the additional testing of the graphs.
+ extra-conf-options: '--disable-full-docs'
+ gcc-major-version: '10'
+ apt-gcc-version: '10.4.0-4ubuntu1~22.04'
+ configure-arguments: ${{ github.event.inputs.configure-arguments }}
+ make-arguments: ${{ github.event.inputs.make-arguments }}
+ if: needs.select.outputs.docs == 'true'
+
###
### Test jobs
###
diff --git a/.jcheck/conf b/.jcheck/conf
index 6f2de4d3805..8993c274fe0 100644
--- a/.jcheck/conf
+++ b/.jcheck/conf
@@ -1,7 +1,7 @@
[general]
project=jdk
jbs=JDK
-version=20
+version=21
[checks]
error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists
diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html
index 6aa6047ede9..777d69b0a2e 100644
--- a/doc/hotspot-style.html
+++ b/doc/hotspot-style.html
@@ -72,6 +72,7 @@
HotSpot Coding Style
Expression
SFINAE
enum
+alignas
thread_local
nullptr
<atomic>
@@ -598,7 +599,7 @@ C++ Standard Library
std::numeric_limits
.
#include <type_traits>
.
#include <cstddef>
to use
-std::nullptr_t
.
+std::nullptr_t
and std::max_align_t
.
TODO: Rather than directly #including (permitted) Standard Library
headers, use a convention of #including wrapper headers (in some
@@ -670,6 +671,53 @@
enum
constant members. Compilers having such bugs are no longer supported.
Except where an enum is semantically appropriate, new code should use
integral constants.
+alignas
+Alignment-specifiers (alignas
n2341)
+are permitted, with restrictions.
+Alignment-specifiers are permitted when the requested
+alignment is a fundamental alignment (not greater than
+alignof(std::max_align_t)
C++14
+3.11/2).
+Alignment-specifiers with an extended alignment
+(greater than alignof(std::max_align_t)
C++14
+3.11/3) may only be used to align variables with static or automatic
+storage duration (C++14
+3.7.1, 3.7.3). As a consequence, over-aligned types are
+forbidden; this may change if HotSpot updates to using C++17 or later
+(p0035r4).
+Large extended alignments should be avoided, particularly
+for stack allocated objects. What is a large value may depend on the
+platform and configuration. There may also be hard limits for some
+platforms.
+An alignment-specifier must always be applied to a
+definition (C++14
+10.6.2/6). (C++ allows an alignment-specifier to optionally
+also be applied to a declaration, so long as the definition has
+equivalent alignment. There isn't any known benefit from duplicating the
+alignment in a non-definition declaration, so such duplication should be
+avoided in HotSpot code.)
+Enumerations are forbidden from having alignment-specifiers.
+Aligned enumerations were originally permitted but insufficiently
+specified, and were later (C++20) removed (CWG 2354).
+Permitting such usage in HotSpot now would just cause problems in the
+future.
+Alignment-specifiers are forbidden in typedef
+and alias-declarations. This may work or may have worked in
+some versions of some compilers, but was later (C++14) explicitly
+disallowed (CWG
+1437).
+The HotSpot macro ATTRIBUTE_ALIGNED
provides similar
+capabilities for platforms that define it. This macro predates the use
+by HotSpot of C++ versions providing alignas
. New code
+should use alignas
.
thread_local
Avoid use of thread_local
(n2659);
diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md
index eeb9d21e74c..555453498d3 100644
--- a/doc/hotspot-style.md
+++ b/doc/hotspot-style.md
@@ -573,7 +573,7 @@ There are a few exceptions to this rule.
* `#include ` to use placement `new`, `std::nothrow`, and `std::nothrow_t`.
* `#include ` to use `std::numeric_limits`.
* `#include `.
-* `#include ` to use `std::nullptr_t`.
+* `#include ` to use `std::nullptr_t` and `std::max_align_t`.
TODO: Rather than directly \#including (permitted) Standard Library
headers, use a convention of \#including wrapper headers (in some
@@ -651,6 +651,51 @@ constant members. Compilers having such bugs are no longer supported.
Except where an enum is semantically appropriate, new code should use
integral constants.
+### alignas
+
+_Alignment-specifiers_ (`alignas`
+[n2341](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf))
+are permitted, with restrictions.
+
+_Alignment-specifiers_ are permitted when the requested alignment is a
+_fundamental alignment_ (not greater than `alignof(std::max_align_t)`
+[C++14 3.11/2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf)).
+
+_Alignment-specifiers_ with an _extended alignment_ (greater than
+`alignof(std::max_align_t)`
+[C++14 3.11/3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf))
+may only be used to align variables with static or automatic storage duration
+([C++14 3.7.1, 3.7.3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf)).
+As a consequence, _over-aligned types_ are forbidden; this may change if
+HotSpot updates to using C++17 or later
+([p0035r4](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0035r4.html)).
+
+Large _extended alignments_ should be avoided, particularly for stack
+allocated objects. What is a large value may depend on the platform and
+configuration. There may also be hard limits for some platforms.
+
+An _alignment-specifier_ must always be applied to a definition
+([C++14 10.6.2/6](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf)).
+(C++ allows an _alignment-specifier_ to optionally also be applied to a
+declaration, so long as the definition has equivalent alignment. There isn't
+any known benefit from duplicating the alignment in a non-definition
+declaration, so such duplication should be avoided in HotSpot code.)
+
+Enumerations are forbidden from having _alignment-specifiers_. Aligned
+enumerations were originally permitted but insufficiently specified, and were
+later (C++20) removed
+([CWG 2354](https://cplusplus.github.io/CWG/issues/2354.html)).
+Permitting such usage in HotSpot now would just cause problems in the future.
+
+_Alignment-specifiers_ are forbidden in `typedef` and _alias-declarations_.
+This may work or may have worked in some versions of some compilers, but was
+later (C++14) explicitly disallowed
+([CWG 1437](https://cplusplus.github.io/CWG/issues/1437.html)).
+
+The HotSpot macro `ATTRIBUTE_ALIGNED` provides similar capabilities for
+platforms that define it. This macro predates the use by HotSpot of C++
+versions providing `alignas`. New code should use `alignas`.
+
### thread_local
Avoid use of `thread_local`
diff --git a/doc/testing.html b/doc/testing.html
index b88eb0c5024..9962b6b3415 100644
--- a/doc/testing.html
+++ b/doc/testing.html
@@ -494,6 +494,9 @@ REPEAT_COUNT
Repeat the tests up to a set number of times, stopping at first
failure. This helps to reproduce intermittent test failures. Defaults to
0.
+REPORT
+Use this report style when reporting test results (sent to JTReg as
+-report
). Defaults to files
.
Gtest keywords
REPEAT
The number of times to repeat the tests
diff --git a/doc/testing.md b/doc/testing.md
index db6c39db3cf..9535388346b 100644
--- a/doc/testing.md
+++ b/doc/testing.md
@@ -484,6 +484,11 @@ Repeat the tests up to a set number of times, stopping at first failure.
This helps to reproduce intermittent test failures.
Defaults to 0.
+#### REPORT
+
+Use this report style when reporting test results (sent to JTReg as `-report`).
+Defaults to `files`.
+
### Gtest keywords
#### REPEAT
diff --git a/make/Docs.gmk b/make/Docs.gmk
index 0cc5309813f..33d531ee4d2 100644
--- a/make/Docs.gmk
+++ b/make/Docs.gmk
@@ -102,6 +102,10 @@ REFERENCE_TAGS := $(JAVADOC_TAGS)
JAVADOC_DISABLED_DOCLINT_WARNINGS := missing
JAVADOC_DISABLED_DOCLINT_PACKAGES := org.w3c.* javax.smartcardio
+# Allow overriding on the command line
+# (intentionally sharing name with the javac option)
+JAVA_WARNINGS_ARE_ERRORS ?= -Werror
+
# The initial set of options for javadoc
JAVADOC_OPTIONS := -use -keywords -notimestamp \
-encoding ISO-8859-1 -docencoding UTF-8 -breakiterator \
@@ -333,6 +337,7 @@ define SetupApiDocsGenerationBody
# Ignore the doclint warnings in certain packages
$1_OPTIONS += -Xdoclint/package:$$(call CommaList, $$(addprefix -, \
$$(JAVADOC_DISABLED_DOCLINT_PACKAGES)))
+ $1_OPTIONS += $$(JAVA_WARNINGS_ARE_ERRORS)
$1_DOC_TITLE := $$($1_LONG_NAME)
Version $$(VERSION_SPECIFICATION) API \
Specification
@@ -614,7 +619,7 @@ $(foreach n, 0 1 2, \
$(eval specs_bottom_rel_path := $(specs_bottom_rel_path)../) \
)
-SPECS_TOP := $(if $(filter true, $(IS_DRAFT)), )
+SPECS_TOP := $(if $(filter true, $(IS_DRAFT)), )
# For all html files in $module/share/specs directories, copy and add the
# copyright footer.
diff --git a/make/RunTests.gmk b/make/RunTests.gmk
index 5fa0c381ebb..894e09528e0 100644
--- a/make/RunTests.gmk
+++ b/make/RunTests.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -196,11 +196,12 @@ $(eval $(call SetTestOpt,JAVA_OPTIONS,JTREG))
$(eval $(call SetTestOpt,JOBS,JTREG))
$(eval $(call SetTestOpt,TIMEOUT_FACTOR,JTREG))
$(eval $(call SetTestOpt,FAILURE_HANDLER_TIMEOUT,JTREG))
+$(eval $(call SetTestOpt,REPORT,JTREG))
$(eval $(call ParseKeywordVariable, JTREG, \
SINGLE_KEYWORDS := JOBS TIMEOUT_FACTOR FAILURE_HANDLER_TIMEOUT \
TEST_MODE ASSERT VERBOSE RETAIN MAX_MEM RUN_PROBLEM_LISTS \
- RETRY_COUNT REPEAT_COUNT MAX_OUTPUT $(CUSTOM_JTREG_SINGLE_KEYWORDS), \
+ RETRY_COUNT REPEAT_COUNT MAX_OUTPUT REPORT $(CUSTOM_JTREG_SINGLE_KEYWORDS), \
STRING_KEYWORDS := OPTIONS JAVA_OPTIONS VM_OPTIONS KEYWORDS \
EXTRA_PROBLEM_LISTS LAUNCHER_OPTIONS \
$(CUSTOM_JTREG_STRING_KEYWORDS), \
@@ -352,7 +353,7 @@ ExpandJtregPath = \
# with test id: dir/Test.java#selection -> Test.java#selection -> .java#selection -> #selection
# without: dir/Test.java -> Test.java -> .java -> <>
TestID = \
- $(subst .java,,$(suffix $(notdir $1)))
+ $(subst .sh,,$(subst .html,,$(subst .java,,$(suffix $(notdir $1)))))
# The test id starting with a hash (#testid) will be stripped by all
# evals in ParseJtregTestSelectionInner and will be reinserted by calling
@@ -745,6 +746,7 @@ define SetupRunJtregTestBody
JTREG_RUN_PROBLEM_LISTS ?= false
JTREG_RETRY_COUNT ?= 0
JTREG_REPEAT_COUNT ?= 0
+ JTREG_REPORT ?= files
ifneq ($$(JTREG_RETRY_COUNT), 0)
ifneq ($$(JTREG_REPEAT_COUNT), 0)
@@ -857,6 +859,7 @@ define SetupRunJtregTestBody
-dir:$$(JTREG_TOPDIR) \
-reportDir:$$($1_TEST_RESULTS_DIR) \
-workDir:$$($1_TEST_SUPPORT_DIR) \
+ -report:$${JTREG_REPORT} \
$$$${JTREG_STATUS} \
$$(JTREG_OPTIONS) \
$$(JTREG_FAILURE_HANDLER_OPTIONS) \
diff --git a/make/ZipSource.gmk b/make/ZipSource.gmk
index 49d13433372..341af7e9847 100644
--- a/make/ZipSource.gmk
+++ b/make/ZipSource.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@ include JavaCompilation.gmk
include Modules.gmk
SRC_ZIP_WORK_DIR := $(SUPPORT_OUTPUTDIR)/src
+$(if $(filter $(TOPDIR)/%, $(SUPPORT_OUTPUTDIR)), $(eval SRC_ZIP_BASE := $(TOPDIR)), $(eval SRC_ZIP_BASE := $(SUPPORT_OUTPUTDIR)))
# Hook to include the corresponding custom file, if present.
$(eval $(call IncludeCustomExtension, ZipSource.gmk))
@@ -45,10 +46,10 @@ ALL_MODULES := $(FindAllModules)
# again to create src.zip.
$(foreach m, $(ALL_MODULES), \
$(foreach d, $(call FindModuleSrcDirs, $m), \
- $(eval $d_TARGET := $(SRC_ZIP_WORK_DIR)/$(patsubst $(TOPDIR)/%,%,$d)/$m) \
+ $(eval $d_TARGET := $(SRC_ZIP_WORK_DIR)/$(patsubst $(TOPDIR)/%,%,$(patsubst $(SUPPORT_OUTPUTDIR)/%,%,$d))/$m) \
$(if $(SRC_GENERATED), , \
$(eval $$($d_TARGET): $d ; \
- $$(if $(filter $(TOPDIR)/%, $d), $$(link-file-relative), $$(link-file-absolute)) \
+ $$(if $(filter $(SRC_ZIP_BASE)/%, $d), $$(link-file-relative), $$(link-file-absolute)) \
) \
) \
$(eval SRC_ZIP_SRCS += $$($d_TARGET)) \
diff --git a/make/autoconf/build-aux/config.guess b/make/autoconf/build-aux/config.guess
index b08072b556c..daf45ae414d 100644
--- a/make/autoconf/build-aux/config.guess
+++ b/make/autoconf/build-aux/config.guess
@@ -29,7 +29,40 @@
# and fix the broken property, if needed.
DIR=`dirname $0`
-OUT=`. $DIR/autoconf-config.guess`
+OUT=`. $DIR/autoconf-config.guess 2> /dev/null`
+
+# Handle some cases that autoconf-config.guess is not capable of
+if [ "x$OUT" = x ]; then
+ if [ `uname -s` = Linux ]; then
+ # Test and fix little endian MIPS.
+ if [ `uname -m` = mipsel ]; then
+ OUT=mipsel-unknown-linux-gnu
+ elif [ `uname -m` = mips64el ]; then
+ OUT=mips64el-unknown-linux-gnu
+ # Test and fix little endian PowerPC64.
+ elif [ `uname -m` = ppc64le ]; then
+ OUT=powerpc64le-unknown-linux-gnu
+ # Test and fix LoongArch64.
+ elif [ `uname -m` = loongarch64 ]; then
+ OUT=loongarch64-unknown-linux-gnu
+ # Test and fix RISC-V.
+ elif [ `uname -m` = riscv64 ]; then
+ OUT=riscv64-unknown-linux-gnu
+ fi
+ # Test and fix cygwin machine arch .x86_64
+ elif [[ `uname -s` = CYGWIN* ]]; then
+ if [ `uname -m` = ".x86_64" ]; then
+ OUT=x86_64-unknown-cygwin
+ fi
+ fi
+
+ if [ "x$OUT" = x ]; then
+ # Run autoconf-config.guess again to get the error message.
+ . $DIR/autoconf-config.guess > /dev/null
+ else
+ printf "guessed by custom config.guess... " >&2
+ fi
+fi
# Detect C library.
# Use '-gnu' suffix on systems that use glibc.
@@ -81,45 +114,6 @@ if test $? = 0; then
OUT=powerpc$KERNEL_BITMODE`echo $OUT | sed -e 's/[^-]*//'`
fi
-# Test and fix little endian PowerPC64.
-# TODO: should be handled by autoconf-config.guess.
-if [ "x$OUT" = x ]; then
- if [ `uname -m` = ppc64le ]; then
- if [ `uname -s` = Linux ]; then
- OUT=powerpc64le-unknown-linux-gnu
- fi
- fi
-fi
-
-# Test and fix little endian MIPS.
-if [ "x$OUT" = x ]; then
- if [ `uname -s` = Linux ]; then
- if [ `uname -m` = mipsel ]; then
- OUT=mipsel-unknown-linux-gnu
- elif [ `uname -m` = mips64el ]; then
- OUT=mips64el-unknown-linux-gnu
- fi
- fi
-fi
-
-# Test and fix LoongArch64.
-if [ "x$OUT" = x ]; then
- if [ `uname -s` = Linux ]; then
- if [ `uname -m` = loongarch64 ]; then
- OUT=loongarch64-unknown-linux-gnu
- fi
- fi
-fi
-
-# Test and fix RISC-V.
-if [ "x$OUT" = x ]; then
- if [ `uname -s` = Linux ]; then
- if [ `uname -m` = riscv64 ]; then
- OUT=riscv64-unknown-linux-gnu
- fi
- fi
-fi
-
# Test and fix cpu on macos-aarch64, uname -p reports arm, buildsys expects aarch64
echo $OUT | grep arm-apple-darwin > /dev/null 2> /dev/null
if test $? != 0; then
diff --git a/make/autoconf/configure.ac b/make/autoconf/configure.ac
index fd3723b4683..05f2a51a7ed 100644
--- a/make/autoconf/configure.ac
+++ b/make/autoconf/configure.ac
@@ -215,6 +215,9 @@ JDKOPT_SETUP_CODE_COVERAGE
# AddressSanitizer
JDKOPT_SETUP_ADDRESS_SANITIZER
+# UndefinedBehaviorSanitizer
+JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER
+
###############################################################################
#
# Check dependencies for external and internal libraries.
diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4
index ebae9e8f00f..1fdd0143adf 100644
--- a/make/autoconf/flags-cflags.m4
+++ b/make/autoconf/flags-cflags.m4
@@ -532,7 +532,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
# Suggested additions: -qsrcmsg to get improved error reporting
# set -qtbtable=full for a better traceback table/better stacks in hs_err when xlc16 is used
TOOLCHAIN_CFLAGS_JDK="-qtbtable=full -qchars=signed -qfullpath -qsaveopt -qstackprotect" # add on both CFLAGS
- TOOLCHAIN_CFLAGS_JVM="-qtbtable=full -qtune=balanced \
+ TOOLCHAIN_CFLAGS_JVM="-qtbtable=full -qtune=balanced -fno-exceptions \
-qalias=noansi -qstrict -qtls=default -qnortti -qnoeh -qignerrno -qstackprotect"
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
TOOLCHAIN_CFLAGS_JVM="-nologo -MD -Zc:preprocessor -Zc:strictStrings -MP"
diff --git a/make/autoconf/flags.m4 b/make/autoconf/flags.m4
index 9b5cb4b3751..ddb2b4c8e0a 100644
--- a/make/autoconf/flags.m4
+++ b/make/autoconf/flags.m4
@@ -503,14 +503,14 @@ UTIL_DEFUN_NAMED([FLAGS_CXX_COMPILER_CHECK_ARGUMENTS],
UTIL_DEFUN_NAMED([FLAGS_COMPILER_CHECK_ARGUMENTS],
[*ARGUMENT IF_TRUE IF_FALSE PREFIX], [$@],
[
- FLAGS_C_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [ARG_ARGUMENT],
+ FLAGS_C_COMPILER_CHECK_ARGUMENTS(ARGUMENT: ARG_ARGUMENT,
IF_TRUE: [C_COMP_SUPPORTS="yes"],
IF_FALSE: [C_COMP_SUPPORTS="no"],
- PREFIX: [ARG_PREFIX])
- FLAGS_CXX_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [ARG_ARGUMENT],
+ PREFIX: ARG_PREFIX)
+ FLAGS_CXX_COMPILER_CHECK_ARGUMENTS(ARGUMENT: ARG_ARGUMENT,
IF_TRUE: [CXX_COMP_SUPPORTS="yes"],
IF_FALSE: [CXX_COMP_SUPPORTS="no"],
- PREFIX: [ARG_PREFIX])
+ PREFIX: ARG_PREFIX)
AC_MSG_CHECKING([if both ARG_PREFIX[CC] and ARG_PREFIX[CXX] support "ARG_ARGUMENT"])
supports=no
diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4
index 05bff5d5001..64f1bf09010 100644
--- a/make/autoconf/jdk-options.m4
+++ b/make/autoconf/jdk-options.m4
@@ -445,6 +445,41 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_ADDRESS_SANITIZER],
AC_SUBST(ASAN_ENABLED)
])
+###############################################################################
+#
+# UndefinedBehaviorSanitizer
+#
+AC_DEFUN_ONCE([JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER],
+[
+ UTIL_ARG_ENABLE(NAME: ubsan, DEFAULT: false, RESULT: UBSAN_ENABLED,
+ DESC: [enable UndefinedBehaviorSanitizer],
+ CHECK_AVAILABLE: [
+ AC_MSG_CHECKING([if UndefinedBehaviorSanitizer (ubsan) is available])
+ if test "x$TOOLCHAIN_TYPE" = "xgcc" ||
+ test "x$TOOLCHAIN_TYPE" = "xclang"; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ AVAILABLE=false
+ fi
+ ],
+ IF_ENABLED: [
+ # GCC reports lots of likely false positives for stringop-truncation and format-overflow.
+ # Silence them for now.
+ UBSAN_CFLAGS="-fsanitize=undefined -fsanitize=float-divide-by-zero -Wno-stringop-truncation -Wno-format-overflow -fno-omit-frame-pointer -DUNDEFINED_BEHAVIOR_SANITIZER"
+ UBSAN_LDFLAGS="-fsanitize=undefined -fsanitize=float-divide-by-zero"
+ JVM_CFLAGS="$JVM_CFLAGS $UBSAN_CFLAGS"
+ JVM_LDFLAGS="$JVM_LDFLAGS $UBSAN_LDFLAGS"
+ CFLAGS_JDKLIB="$CFLAGS_JDKLIB $UBSAN_CFLAGS"
+ CFLAGS_JDKEXE="$CFLAGS_JDKEXE $UBSAN_CFLAGS"
+ CXXFLAGS_JDKLIB="$CXXFLAGS_JDKLIB $UBSAN_CFLAGS"
+ CXXFLAGS_JDKEXE="$CXXFLAGS_JDKEXE $UBSAN_CFLAGS"
+ LDFLAGS_JDKLIB="$LDFLAGS_JDKLIB $UBSAN_LDFLAGS"
+ LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE $UBSAN_LDFLAGS"
+ ])
+ AC_SUBST(UBSAN_ENABLED)
+])
+
################################################################################
#
# Static build support. When enabled will generate static
@@ -781,7 +816,7 @@ AC_DEFUN([JDKOPT_SETUP_MACOSX_SIGNING],
# Check for user provided code signing identity.
UTIL_ARG_WITH(NAME: macosx-codesign-identity, TYPE: string,
- DEFAULT: openjdk_codesign, CHECK_VALUE: UTIL_CHECK_STRING_NON_EMPTY,
+ DEFAULT: openjdk_codesign, CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY],
DESC: [specify the macosx code signing identity],
CHECKING_MSG: [for macosx code signing identity]
)
diff --git a/make/autoconf/jdk-version.m4 b/make/autoconf/jdk-version.m4
index 41f4b1fb121..3639299105e 100644
--- a/make/autoconf/jdk-version.m4
+++ b/make/autoconf/jdk-version.m4
@@ -69,149 +69,132 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS],
AC_SUBST(JDK_RC_PLATFORM_NAME)
AC_SUBST(HOTSPOT_VM_DISTRO)
+ # Note: UTIL_ARG_WITH treats empty strings as valid values when OPTIONAL is false!
+
+ # Outer [ ] to quote m4.
+ [ USERNAME=`$ECHO "$USER" | $TR -d -c '[a-z][A-Z][0-9]'` ]
+
# Setup username (for use in adhoc version strings etc)
- AC_ARG_WITH([build-user], [AS_HELP_STRING([--with-build-user],
- [build username to use in version strings])])
- if test "x$with_build_user" = xyes || test "x$with_build_user" = xno; then
- AC_MSG_ERROR([--with-build-user must have a value])
- elif test "x$with_build_user" != x; then
- USERNAME="$with_build_user"
- else
- # Outer [ ] to quote m4.
- [ USERNAME=`$ECHO "$USER" | $TR -d -c '[a-z][A-Z][0-9]'` ]
- fi
+ UTIL_ARG_WITH(NAME: build-user, TYPE: string,
+ RESULT: USERNAME,
+ DEFAULT: $USERNAME,
+ DESC: [build username to use in version strings],
+ DEFAULT_DESC: [current username, sanitized],
+ CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY])
AC_SUBST(USERNAME)
# Set the JDK RC name
- AC_ARG_WITH(jdk-rc-name, [AS_HELP_STRING([--with-jdk-rc-name],
- [Set JDK RC name. This is used for FileDescription and ProductName properties
- of MS Windows binaries. @<:@not specified@:>@])])
- if test "x$with_jdk_rc_name" = xyes || test "x$with_jdk_rc_name" = xno; then
- AC_MSG_ERROR([--with-jdk-rc-name must have a value])
- elif [ ! [[ $with_jdk_rc_name =~ ^[[:print:]]*$ ]] ]; then
- AC_MSG_ERROR([--with-jdk-rc-name contains non-printing characters: $with_jdk_rc_name])
- elif test "x$with_jdk_rc_name" != x; then
- # Set JDK_RC_NAME to a custom value if '--with-jdk-rc-name' was used and is not empty.
- JDK_RC_NAME="$with_jdk_rc_name"
- else
- # Otherwise calculate from "branding.conf" included above.
- JDK_RC_NAME="$PRODUCT_NAME $JDK_RC_PLATFORM_NAME"
- fi
+ # Otherwise calculate from "branding.conf" included above.
+ 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.],
+ DEFAULT_DESC: [from branding.conf],
+ CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE])
AC_SUBST(JDK_RC_NAME)
# The vendor name, if any
- AC_ARG_WITH(vendor-name, [AS_HELP_STRING([--with-vendor-name],
- [Set vendor name. Among others, used to set the 'java.vendor'
- and 'java.vm.vendor' system properties. @<:@not specified@:>@])])
- if test "x$with_vendor_name" = xyes || test "x$with_vendor_name" = xno; then
- AC_MSG_ERROR([--with-vendor-name must have a value])
- elif [ ! [[ $with_vendor_name =~ ^[[:print:]]*$ ]] ]; then
- AC_MSG_ERROR([--with-vendor-name contains non-printing characters: $with_vendor_name])
- elif test "x$with_vendor_name" != x; then
- # Only set COMPANY_NAME if '--with-vendor-name' was used and is not empty.
- # Otherwise we will use the value from "branding.conf" included above.
- COMPANY_NAME="$with_vendor_name"
- fi
+ # Only set COMPANY_NAME if '--with-vendor-name' was used and is not empty.
+ # Otherwise we will use the value from "branding.conf" included above.
+ UTIL_ARG_WITH(NAME: vendor-name, TYPE: string,
+ RESULT: COMPANY_NAME,
+ DEFAULT: $COMPANY_NAME,
+ DESC: [Set vendor name. Among others, used to set the 'java.vendor'
+ and 'java.vm.vendor' system properties.],
+ DEFAULT_DESC: [from branding.conf],
+ CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE])
AC_SUBST(COMPANY_NAME)
# The vendor URL, if any
- AC_ARG_WITH(vendor-url, [AS_HELP_STRING([--with-vendor-url],
- [Set the 'java.vendor.url' system property @<:@not specified@:>@])])
- if test "x$with_vendor_url" = xyes || test "x$with_vendor_url" = xno; then
- AC_MSG_ERROR([--with-vendor-url must have a value])
- elif [ ! [[ $with_vendor_url =~ ^[[:print:]]*$ ]] ]; then
- AC_MSG_ERROR([--with-vendor-url contains non-printing characters: $with_vendor_url])
- elif test "x$with_vendor_url" != x; then
- # Only set VENDOR_URL if '--with-vendor-url' was used and is not empty.
- # Otherwise we will use the value from "branding.conf" included above.
- VENDOR_URL="$with_vendor_url"
- fi
+ # Only set VENDOR_URL if '--with-vendor-url' was used and is not empty.
+ # Otherwise we will use the value from "branding.conf" included above.
+ UTIL_ARG_WITH(NAME: vendor-url, TYPE: string,
+ DEFAULT: $VENDOR_URL,
+ DESC: [Set the 'java.vendor.url' system property],
+ DEFAULT_DESC: [from branding.conf],
+ CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE])
AC_SUBST(VENDOR_URL)
# The vendor bug URL, if any
- AC_ARG_WITH(vendor-bug-url, [AS_HELP_STRING([--with-vendor-bug-url],
- [Set the 'java.vendor.url.bug' system property @<:@not specified@:>@])])
- if test "x$with_vendor_bug_url" = xyes || test "x$with_vendor_bug_url" = xno; then
- AC_MSG_ERROR([--with-vendor-bug-url must have a value])
- elif [ ! [[ $with_vendor_bug_url =~ ^[[:print:]]*$ ]] ]; then
- AC_MSG_ERROR([--with-vendor-bug-url contains non-printing characters: $with_vendor_bug_url])
- elif test "x$with_vendor_bug_url" != x; then
- # Only set VENDOR_URL_BUG if '--with-vendor-bug-url' was used and is not empty.
- # Otherwise we will use the value from "branding.conf" included above.
- VENDOR_URL_BUG="$with_vendor_bug_url"
- fi
+ # Only set VENDOR_URL_BUG if '--with-vendor-bug-url' was used and is not empty.
+ # Otherwise we will use the value from "branding.conf" included above.
+ UTIL_ARG_WITH(NAME: vendor-bug-url, TYPE: string,
+ RESULT: VENDOR_URL_BUG,
+ DEFAULT: $VENDOR_URL_BUG,
+ DESC: [Set the 'java.vendor.url.bug' system property],
+ DEFAULT_DESC: [from branding.conf],
+ CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE])
AC_SUBST(VENDOR_URL_BUG)
# The vendor VM bug URL, if any
- AC_ARG_WITH(vendor-vm-bug-url, [AS_HELP_STRING([--with-vendor-vm-bug-url],
- [Sets the bug URL which will be displayed when the VM crashes @<:@not specified@:>@])])
- if test "x$with_vendor_vm_bug_url" = xyes || test "x$with_vendor_vm_bug_url" = xno; then
- AC_MSG_ERROR([--with-vendor-vm-bug-url must have a value])
- elif [ ! [[ $with_vendor_vm_bug_url =~ ^[[:print:]]*$ ]] ]; then
- AC_MSG_ERROR([--with-vendor-vm-bug-url contains non-printing characters: $with_vendor_vm_bug_url])
- elif test "x$with_vendor_vm_bug_url" != x; then
- # Only set VENDOR_URL_VM_BUG if '--with-vendor-vm-bug-url' was used and is not empty.
- # Otherwise we will use the value from "branding.conf" included above.
- VENDOR_URL_VM_BUG="$with_vendor_vm_bug_url"
- fi
+ # Only set VENDOR_URL_VM_BUG if '--with-vendor-vm-bug-url' was used and is not empty.
+ # Otherwise we will use the value from "branding.conf" included above.
+ UTIL_ARG_WITH(NAME: vendor-vm-bug-url, TYPE: string,
+ RESULT: VENDOR_URL_VM_BUG,
+ DEFAULT: $VENDOR_URL_VM_BUG,
+ DESC: [Sets the bug URL which will be displayed when the VM crashes],
+ DEFAULT_DESC: [from branding.conf],
+ CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE])
AC_SUBST(VENDOR_URL_VM_BUG)
# Override version from arguments
# If --with-version-string is set, process it first. It is possible to
# override parts with more specific flags, since these are processed later.
- AC_ARG_WITH(version-string, [AS_HELP_STRING([--with-version-string],
- [Set version string @<:@calculated@:>@])])
- if test "x$with_version_string" = xyes || test "x$with_version_string" = xno; then
- AC_MSG_ERROR([--with-version-string must have a value])
- elif test "x$with_version_string" != x; then
- # Additional [] needed to keep m4 from mangling shell constructs.
- if [ [[ $with_version_string =~ ^([0-9]+)(\.([0-9]+))?(\.([0-9]+))?(\.([0-9]+))?(\.([0-9]+))?(\.([0-9]+))?(\.([0-9]+))?(-([a-zA-Z0-9]+))?(((\+)([0-9]*))?(-([-a-zA-Z0-9.]+))?)?$ ]] ]; then
- VERSION_FEATURE=${BASH_REMATCH[[1]]}
- VERSION_INTERIM=${BASH_REMATCH[[3]]}
- VERSION_UPDATE=${BASH_REMATCH[[5]]}
- VERSION_PATCH=${BASH_REMATCH[[7]]}
- VERSION_EXTRA1=${BASH_REMATCH[[9]]}
- VERSION_EXTRA2=${BASH_REMATCH[[11]]}
- VERSION_EXTRA3=${BASH_REMATCH[[13]]}
- VERSION_PRE=${BASH_REMATCH[[15]]}
- version_plus_separator=${BASH_REMATCH[[18]]}
- VERSION_BUILD=${BASH_REMATCH[[19]]}
- VERSION_OPT=${BASH_REMATCH[[21]]}
- # Unspecified numerical fields are interpreted as 0.
- if test "x$VERSION_INTERIM" = x; then
- VERSION_INTERIM=0
- fi
- if test "x$VERSION_UPDATE" = x; then
- VERSION_UPDATE=0
- fi
- if test "x$VERSION_PATCH" = x; then
- VERSION_PATCH=0
- fi
- if test "x$VERSION_EXTRA1" = x; then
- VERSION_EXTRA1=0
+ UTIL_ARG_WITH(NAME: version-string, TYPE: string,
+ DEFAULT: [],
+ DESC: [Set version string],
+ DEFAULT_DESC: [calculated],
+ CHECK_VALUE: [
+ if test "x$RESULT" != x; then
+ # Additional [] needed to keep m4 from mangling shell constructs.
+ if [ [[ $RESULT =~ ^([0-9]+)(\.([0-9]+))?(\.([0-9]+))?(\.([0-9]+))?(\.([0-9]+))?(\.([0-9]+))?(\.([0-9]+))?(-([a-zA-Z0-9]+))?(((\+)([0-9]*))?(-([-a-zA-Z0-9.]+))?)?$ ]] ]; then
+ VERSION_FEATURE=${BASH_REMATCH[[1]]}
+ VERSION_INTERIM=${BASH_REMATCH[[3]]}
+ VERSION_UPDATE=${BASH_REMATCH[[5]]}
+ VERSION_PATCH=${BASH_REMATCH[[7]]}
+ VERSION_EXTRA1=${BASH_REMATCH[[9]]}
+ VERSION_EXTRA2=${BASH_REMATCH[[11]]}
+ VERSION_EXTRA3=${BASH_REMATCH[[13]]}
+ VERSION_PRE=${BASH_REMATCH[[15]]}
+ version_plus_separator=${BASH_REMATCH[[18]]}
+ VERSION_BUILD=${BASH_REMATCH[[19]]}
+ VERSION_OPT=${BASH_REMATCH[[21]]}
+ # Unspecified numerical fields are interpreted as 0.
+ if test "x$VERSION_INTERIM" = x; then
+ VERSION_INTERIM=0
+ fi
+ if test "x$VERSION_UPDATE" = x; then
+ VERSION_UPDATE=0
+ fi
+ if test "x$VERSION_PATCH" = x; then
+ VERSION_PATCH=0
+ fi
+ if test "x$VERSION_EXTRA1" = x; then
+ VERSION_EXTRA1=0
+ fi
+ if test "x$VERSION_EXTRA2" = x; then
+ VERSION_EXTRA2=0
+ fi
+ if test "x$VERSION_EXTRA3" = x; then
+ VERSION_EXTRA3=0
+ fi
+ if test "x$version_plus_separator" != x \
+ && test "x$VERSION_BUILD$VERSION_OPT" = x; then
+ AC_MSG_ERROR([Version string contains + but both 'BUILD' and 'OPT' are missing])
+ fi
+ if test "x$VERSION_BUILD" = x0; then
+ AC_MSG_WARN([Version build 0 is interpreted as no build number])
+ VERSION_BUILD=
+ fi
+ # Stop the version part process from setting default values.
+ # We still allow them to explicitly override though.
+ NO_DEFAULT_VERSION_PARTS=true
+ else
+ FAILURE="--with-version-string fails to parse as a valid version string: $RESULT"
+ fi
fi
- if test "x$VERSION_EXTRA2" = x; then
- VERSION_EXTRA2=0
- fi
- if test "x$VERSION_EXTRA3" = x; then
- VERSION_EXTRA3=0
- fi
- if test "x$version_plus_separator" != x \
- && test "x$VERSION_BUILD$VERSION_OPT" = x; then
- AC_MSG_ERROR([Version string contains + but both 'BUILD' and 'OPT' are missing])
- fi
- if test "x$VERSION_BUILD" = x0; then
- AC_MSG_WARN([Version build 0 is interpreted as no build number])
- VERSION_BUILD=
- fi
- # Stop the version part process from setting default values.
- # We still allow them to explicitly override though.
- NO_DEFAULT_VERSION_PARTS=true
- else
- AC_MSG_ERROR([--with-version-string fails to parse as a valid version string: $with_version_string])
- fi
- fi
+ ])
AC_ARG_WITH(version-pre, [AS_HELP_STRING([--with-version-pre],
[Set the base part of the version 'PRE' field (pre-release identifier) @<:@'internal'@:>@])],
@@ -290,23 +273,19 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS],
fi
fi
- AC_ARG_WITH(version-feature, [AS_HELP_STRING([--with-version-feature],
- [Set version 'FEATURE' field (first number) @<:@current source value@:>@])],
- [with_version_feature_present=true], [with_version_feature_present=false])
-
- if test "x$with_version_feature_present" = xtrue; then
- if test "x$with_version_feature" = xyes || test "x$with_version_feature" = xno; then
- AC_MSG_ERROR([--with-version-feature must have a value])
- else
- JDKVER_CHECK_AND_SET_NUMBER(VERSION_FEATURE, $with_version_feature)
- fi
- else
- if test "x$NO_DEFAULT_VERSION_PARTS" != xtrue; then
- # Default is to get value from version-numbers.conf
- VERSION_FEATURE="$DEFAULT_VERSION_FEATURE"
- fi
+ # Default is to get value from version-numbers.conf
+ if test "x$NO_DEFAULT_VERSION_PARTS" = xtrue; then
+ DEFAULT_VERSION_FEATURE="$VERSION_FEATURE"
fi
+ UTIL_ARG_WITH(NAME: version-feature, TYPE: string,
+ DEFAULT: $DEFAULT_VERSION_FEATURE,
+ DESC: [Set version 'FEATURE' field (first number)],
+ DEFAULT_DESC: [current source value],
+ CHECK_VALUE: [
+ JDKVER_CHECK_AND_SET_NUMBER(VERSION_FEATURE, $RESULT)
+ ])
+
AC_ARG_WITH(version-interim, [AS_HELP_STRING([--with-version-interim],
[Set version 'INTERIM' field (second number) @<:@current source value@:>@])],
[with_version_interim_present=true], [with_version_interim_present=false])
@@ -480,91 +459,81 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS],
VERSION_SHORT=$VERSION_NUMBER${VERSION_PRE:+-$VERSION_PRE}
# The version date
- AC_ARG_WITH(version-date, [AS_HELP_STRING([--with-version-date],
- [Set version date @<:@current source value@:>@])])
- if test "x$with_version_date" = xyes || test "x$with_version_date" = xno; then
- AC_MSG_ERROR([--with-version-date must have a value])
- elif test "x$with_version_date" != x; then
- if [ ! [[ $with_version_date =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] ]; then
- AC_MSG_ERROR(["$with_version_date" is not a valid version date])
- else
- VERSION_DATE="$with_version_date"
- fi
- else
- VERSION_DATE="$DEFAULT_VERSION_DATE"
- fi
+ UTIL_ARG_WITH(NAME: version-date, TYPE: string,
+ DEFAULT: $DEFAULT_VERSION_DATE,
+ DESC: [Set version date],
+ DEFAULT_DESC: [current source value],
+ CHECK_VALUE: [
+ if test "x$RESULT" = x; then
+ FAILURE="--with-version-date cannot be empty"
+ elif [ ! [[ $RESULT =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] ]; then
+ FAILURE="\"$RESULT\" is not a valid version date"
+ fi
+ ])
# The vendor version string, if any
- AC_ARG_WITH(vendor-version-string, [AS_HELP_STRING([--with-vendor-version-string],
- [Set vendor version string @<:@not specified@:>@])])
- if test "x$with_vendor_version_string" = xyes; then
- AC_MSG_ERROR([--with-vendor-version-string must have a value])
- elif [ ! [[ $with_vendor_version_string =~ ^[[:graph:]]*$ ]] ]; then
- AC_MSG_ERROR([--with--vendor-version-string contains non-graphical characters: $with_vendor_version_string])
- elif test "x$with_vendor_version_string" != xno; then
- # Set vendor version string if --without is not passed
- # Check not required if an empty value is passed, since VENDOR_VERSION_STRING
- # would then be set to ""
- VENDOR_VERSION_STRING="$with_vendor_version_string"
+ # DEFAULT is set to an empty string in the case of --with-vendor-version-string without
+ # any value, which would set VENDOR_VERSION_STRING_ENABLED to true and ultimately also
+ # cause VENDOR_VERSION_STRING to fall back to the value in DEFAULT
+ UTIL_ARG_WITH(NAME: vendor-version-string, TYPE: string,
+ DEFAULT: [],
+ OPTIONAL: true,
+ DESC: [Set vendor version string],
+ DEFAULT_DESC: [not specified])
+
+ if test "x$VENDOR_VERSION_STRING_ENABLED" = xtrue; then
+ if [ ! [[ $VENDOR_VERSION_STRING =~ ^[[:graph:]]*$ ]] ]; then
+ AC_MSG_ERROR([--with--vendor-version-string contains non-graphical characters: $VENDOR_VERSION_STRING])
+ fi
fi
# Set the MACOSX Bundle Name base
- AC_ARG_WITH(macosx-bundle-name-base, [AS_HELP_STRING([--with-macosx-bundle-name-base],
- [Set the MacOSX Bundle Name base. This is the base name for calculating MacOSX Bundle Names.
- @<:@not specified@:>@])])
- if test "x$with_macosx_bundle_name_base" = xyes || test "x$with_macosx_bundle_name_base" = xno; then
- AC_MSG_ERROR([--with-macosx-bundle-name-base must have a value])
- elif [ ! [[ $with_macosx_bundle_name_base =~ ^[[:print:]]*$ ]] ]; then
- AC_MSG_ERROR([--with-macosx-bundle-name-base contains non-printing characters: $with_macosx_bundle_name_base])
- elif test "x$with_macosx_bundle_name_base" != x; then
- # Set MACOSX_BUNDLE_NAME_BASE to the configured value.
- MACOSX_BUNDLE_NAME_BASE="$with_macosx_bundle_name_base"
- fi
+ UTIL_ARG_WITH(NAME: macosx-bundle-name-base, TYPE: string,
+ DEFAULT: $MACOSX_BUNDLE_NAME_BASE,
+ DESC: [Set the MacOSX Bundle Name base. This is the base name for calculating MacOSX Bundle Names.],
+ DEFAULT_DESC: [from branding.conf],
+ CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE])
AC_SUBST(MACOSX_BUNDLE_NAME_BASE)
- # Set the MACOSX Bundle ID base
- AC_ARG_WITH(macosx-bundle-id-base, [AS_HELP_STRING([--with-macosx-bundle-id-base],
- [Set the MacOSX Bundle ID base. This is the base ID for calculating MacOSX Bundle IDs.
- @<:@not specified@:>@])])
- if test "x$with_macosx_bundle_id_base" = xyes || test "x$with_macosx_bundle_id_base" = xno; then
- AC_MSG_ERROR([--with-macosx-bundle-id-base must have a value])
- elif [ ! [[ $with_macosx_bundle_id_base =~ ^[[:print:]]*$ ]] ]; then
- AC_MSG_ERROR([--with-macosx-bundle-id-base contains non-printing characters: $with_macosx_bundle_id_base])
- elif test "x$with_macosx_bundle_id_base" != x; then
- # Set MACOSX_BUNDLE_ID_BASE to the configured value.
- MACOSX_BUNDLE_ID_BASE="$with_macosx_bundle_id_base"
- else
- # If using the default value, append the VERSION_PRE if there is one
- # to make it possible to tell official builds apart from developer builds
- if test "x$VERSION_PRE" != x; then
- MACOSX_BUNDLE_ID_BASE="$MACOSX_BUNDLE_ID_BASE-$VERSION_PRE"
- fi
+ # If using the default value, append the VERSION_PRE if there is one
+ # to make it possible to tell official builds apart from developer builds
+ if test "x$VERSION_PRE" != x; then
+ MACOSX_BUNDLE_ID_BASE="$MACOSX_BUNDLE_ID_BASE-$VERSION_PRE"
fi
+
+ # Set the MACOSX Bundle ID base
+ UTIL_ARG_WITH(NAME: macosx-bundle-id-base, TYPE: string,
+ DEFAULT: $MACOSX_BUNDLE_ID_BASE,
+ DESC: [Set the MacOSX Bundle ID base. This is the base ID for calculating MacOSX Bundle IDs.],
+ DEFAULT_DESC: [based on branding.conf and VERSION_PRE],
+ CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE])
AC_SUBST(MACOSX_BUNDLE_ID_BASE)
- # Set the MACOSX CFBundleVersion field
- AC_ARG_WITH(macosx-bundle-build-version, [AS_HELP_STRING([--with-macosx-bundle-build-version],
- [Set the MacOSX Bundle CFBundleVersion field. This key is a machine-readable
- string composed of one to three period-separated integers and should represent the
- build version. Defaults to the build number.])])
- if test "x$with_macosx_bundle_build_version" = xyes || test "x$with_macosx_bundle_build_version" = xno; then
- AC_MSG_ERROR([--with-macosx-bundle-build-version must have a value])
- elif [ ! [[ $with_macosx_bundle_build_version =~ ^[0-9\.]*$ ]] ]; then
- AC_MSG_ERROR([--with-macosx-bundle-build-version contains non numbers and periods: $with_macosx_bundle_build_version])
- elif test "x$with_macosx_bundle_build_version" != x; then
- MACOSX_BUNDLE_BUILD_VERSION="$with_macosx_bundle_build_version"
+ if test "x$VERSION_BUILD" != x; then
+ MACOSX_BUNDLE_BUILD_VERSION="$VERSION_BUILD"
else
- if test "x$VERSION_BUILD" != x; then
- MACOSX_BUNDLE_BUILD_VERSION="$VERSION_BUILD"
- else
- MACOSX_BUNDLE_BUILD_VERSION=0
- fi
+ MACOSX_BUNDLE_BUILD_VERSION=0
+ fi
- # If VERSION_OPT consists of only numbers and periods, add it.
- if [ [[ $VERSION_OPT =~ ^[0-9\.]+$ ]] ]; then
- MACOSX_BUNDLE_BUILD_VERSION="$MACOSX_BUNDLE_BUILD_VERSION.$VERSION_OPT"
- fi
+ # If VERSION_OPT consists of only numbers and periods, add it.
+ if [ [[ $VERSION_OPT =~ ^[0-9\.]+$ ]] ]; then
+ MACOSX_BUNDLE_BUILD_VERSION="$MACOSX_BUNDLE_BUILD_VERSION.$VERSION_OPT"
fi
+
+ # Set the MACOSX CFBundleVersion field
+ UTIL_ARG_WITH(NAME: macosx-bundle-build-version, TYPE: string,
+ DEFAULT: $MACOSX_BUNDLE_BUILD_VERSION,
+ DESC: [Set the MacOSX Bundle CFBundleVersion field. This key is a machine-readable
+ string composed of one to three period-separated integers and should represent the
+ build version.],
+ DEFAULT_DESC: [the build number],
+ CHECK_VALUE: [
+ if test "x$RESULT" = x; then
+ FAILURE="--with-macosx-bundle-build-version must have a value"
+ elif [ ! [[ $RESULT =~ ^[0-9\.]*$ ]] ]; then
+ FAILURE="--with-macosx-bundle-build-version contains non numbers and periods: $RESULT"
+ fi
+ ])
AC_SUBST(MACOSX_BUNDLE_BUILD_VERSION)
# We could define --with flags for these, if really needed
diff --git a/make/autoconf/lib-tests.m4 b/make/autoconf/lib-tests.m4
index 0b4b138ccd7..9d3080d2050 100644
--- a/make/autoconf/lib-tests.m4
+++ b/make/autoconf/lib-tests.m4
@@ -28,7 +28,7 @@
################################################################################
# Minimum supported version
-JTREG_MINIMUM_VERSION=7.1
+JTREG_MINIMUM_VERSION=7.1.1
###############################################################################
#
diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in
index 9448cb9b7e8..1daed61c983 100644
--- a/make/autoconf/spec.gmk.in
+++ b/make/autoconf/spec.gmk.in
@@ -455,6 +455,9 @@ ifeq ($(ASAN_ENABLED), yes)
endif
endif
+# UndefinedBehaviorSanitizer
+UBSAN_ENABLED:=@UBSAN_ENABLED@
+
# Necessary additional compiler flags to compile X11
X_CFLAGS:=@X_CFLAGS@
X_LIBS:=@X_LIBS@
diff --git a/make/autoconf/util.m4 b/make/autoconf/util.m4
index d2171338d00..83349aea99d 100644
--- a/make/autoconf/util.m4
+++ b/make/autoconf/util.m4
@@ -52,7 +52,7 @@ m4_include([util_paths.m4])
AC_DEFUN([UTIL_DEFUN_NAMED],
[
AC_DEFUN($1, [
- m4_foreach(arg, m4_split(m4_normalize($2)), [
+ m4_foreach([arg], m4_split(m4_normalize($2)), [
m4_if(m4_bregexp(arg, [^\*]), -1,
[
m4_set_add(legal_named_args, arg)
@@ -64,13 +64,18 @@ AC_DEFUN([UTIL_DEFUN_NAMED],
)
])
- m4_foreach([arg], [$3], [
- m4_if(m4_bregexp(arg, [: ]), -1, m4_define([arg], m4_bpatsubst(arg, [:], [: ])))
- m4_define(arg_name, m4_substr(arg, 0, m4_bregexp(arg, [: ])))
+ # Delicate quoting and unquoting sequence to ensure the actual value is passed along unchanged
+ # For details on how this works, see https://git.openjdk.org/jdk/pull/11458#discussion_r1038173051
+ # WARNING: Proceed at the risk of your own sanity, getting this to work has made me completely
+ # incapable of feeling love or any other positive emotion
+ # ~Julian
+ m4_foreach([arg], m4_dquote(m4_dquote_elt($3)), [
+ m4_if(m4_index(arg, [: ]), -1, [m4_define([arg], m4_dquote(m4_bpatsubst(m4_dquote(arg), [:], [: ])))])
+ m4_define(arg_name, m4_substr(arg, 0, m4_index(arg, [: ])))
m4_set_contains(legal_named_args, arg_name, [],[AC_MSG_ERROR([Internal error: m4_if(arg_name, , arg, arg_name) is not a valid named argument to [$1]. Valid arguments are 'm4_set_contents(defined_args, [ ]) m4_set_contents(legal_named_args, [ ])'.])])
m4_set_remove(required_named_args, arg_name)
m4_set_remove(legal_named_args, arg_name)
- m4_pushdef([ARG_][]arg_name, m4_bpatsubst(m4_substr(arg, m4_incr(m4_incr(m4_bregexp(arg, [: ])))), [^\s*], []))
+ m4_pushdef([ARG_][]arg_name, m4_bpatsubst(m4_bpatsubst(m4_dquote(m4_dquote(arg)), arg_name[: ]), [^\s*]))
m4_set_add(defined_args, arg_name)
m4_undefine([arg_name])
])
@@ -376,18 +381,18 @@ UTIL_DEFUN_NAMED([UTIL_ARG_ENABLE],
m4_define(ARG_GIVEN, m4_translit(ARG_NAME, [a-z-], [A-Z_])[_GIVEN])
# If DESC is not specified, set it to a generic description.
- m4_define([ARG_DESC], m4_if(ARG_DESC, , [Enable the ARG_NAME feature], m4_normalize(ARG_DESC)))
+ m4_define([ARG_DESC], m4_if(m4_quote(ARG_DESC), , [[Enable the ARG_NAME feature]], [m4_normalize(ARG_DESC)]))
# If CHECKING_MSG is not specified, set it to a generic description.
- m4_define([ARG_CHECKING_MSG], m4_if(ARG_CHECKING_MSG, , [for --enable-ARG_NAME], m4_normalize(ARG_CHECKING_MSG)))
+ m4_define([ARG_CHECKING_MSG], m4_if(m4_quote(ARG_CHECKING_MSG), , [[for --enable-ARG_NAME]], [m4_normalize(ARG_CHECKING_MSG)]))
# If the code blocks are not given, set them to the empty statements to avoid
# tripping up bash.
- m4_define([ARG_CHECK_AVAILABLE], m4_if(ARG_CHECK_AVAILABLE, , :, ARG_CHECK_AVAILABLE))
- m4_define([ARG_IF_GIVEN], m4_if(ARG_IF_GIVEN, , :, ARG_IF_GIVEN))
- m4_define([ARG_IF_NOT_GIVEN], m4_if(ARG_IF_NOT_GIVEN, , :, ARG_IF_NOT_GIVEN))
- m4_define([ARG_IF_ENABLED], m4_if(ARG_IF_ENABLED, , :, ARG_IF_ENABLED))
- m4_define([ARG_IF_DISABLED], m4_if(ARG_IF_DISABLED, , :, ARG_IF_DISABLED))
+ m4_if(ARG_CHECK_AVAILABLE, , [m4_define([ARG_CHECK_AVAILABLE], [:])])
+ m4_if(ARG_IF_GIVEN, , [m4_define([ARG_IF_GIVEN], [:])])
+ m4_if(ARG_IF_NOT_GIVEN, , [m4_define([ARG_IF_NOT_GIVEN], [:])])
+ m4_if(ARG_IF_ENABLED, , [m4_define([ARG_IF_ENABLED], [:])])
+ m4_if(ARG_IF_DISABLED, , [m4_define([ARG_IF_DISABLED], [:])])
##########################
# Part 2: Set up autoconf shell code
@@ -650,21 +655,21 @@ UTIL_DEFUN_NAMED([UTIL_ARG_WITH],
m4_define(ARG_GIVEN, m4_translit(ARG_NAME, [a-z-], [A-Z_])[_GIVEN])
# If DESC is not specified, set it to a generic description.
- m4_define([ARG_DESC], m4_if(ARG_DESC, , [Give a value for the ARG_NAME feature], m4_normalize(ARG_DESC)))
+ m4_define([ARG_DESC], m4_if(m4_quote(ARG_DESC), , [[Give a value for the ARG_NAME feature]], [m4_normalize(ARG_DESC)]))
# If CHECKING_MSG is not specified, set it to a generic description.
- m4_define([ARG_CHECKING_MSG], m4_if(ARG_CHECKING_MSG, , [for --with-ARG_NAME], m4_normalize(ARG_CHECKING_MSG)))
+ m4_define([ARG_CHECKING_MSG], m4_if(m4_quote(ARG_CHECKING_MSG), , [[for --with-ARG_NAME]], [m4_normalize(ARG_CHECKING_MSG)]))
m4_define([ARG_HAS_AUTO_BLOCK], m4_if(ARG_IF_AUTO, , false, true))
# If the code blocks are not given, set them to the empty statements to avoid
# tripping up bash.
- m4_define([ARG_CHECK_AVAILABLE], m4_if(ARG_CHECK_AVAILABLE, , :, ARG_CHECK_AVAILABLE))
- m4_define([ARG_CHECK_VALUE], m4_if(ARG_CHECK_VALUE, , :, ARG_CHECK_VALUE))
- m4_define([ARG_CHECK_FOR_FILES], m4_if(ARG_CHECK_FOR_FILES, , :, ARG_CHECK_FOR_FILES))
- m4_define([ARG_IF_AUTO], m4_if(ARG_IF_AUTO, , :, ARG_IF_AUTO))
- m4_define([ARG_IF_GIVEN], m4_if(ARG_IF_GIVEN, , :, ARG_IF_GIVEN))
- m4_define([ARG_IF_NOT_GIVEN], m4_if(ARG_IF_NOT_GIVEN, , :, ARG_IF_NOT_GIVEN))
+ m4_if(ARG_CHECK_AVAILABLE, , [m4_define([ARG_CHECK_AVAILABLE], [:])])
+ m4_if(ARG_CHECK_VALUE, , [m4_define([ARG_CHECK_VALUE], [:])])
+ m4_if(ARG_CHECK_FOR_FILES, , [m4_define([ARG_CHECK_FOR_FILES], [:])])
+ m4_if(ARG_IF_AUTO, , [m4_define([ARG_IF_AUTO], [:])])
+ m4_if(ARG_IF_GIVEN, , [m4_define([ARG_IF_GIVEN], [:])])
+ m4_if(ARG_IF_NOT_GIVEN, , [m4_define([ARG_IF_NOT_GIVEN], [:])])
##########################
# Part 2: Set up autoconf shell code
@@ -813,3 +818,12 @@ AC_DEFUN([UTIL_CHECK_STRING_NON_EMPTY],
FAILURE="Value cannot be empty"
fi
])
+
+AC_DEFUN([UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE],
+[
+ if test "x$RESULT" = x; then
+ FAILURE="Value cannot be empty"
+ elif [ ! [[ $RESULT =~ ^[[:print:]]*$ ]] ]; then
+ FAILURE="Value contains non-printing characters: $RESULT"
+ fi
+])
diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk
index 802b0f130f9..ff7c90e5785 100644
--- a/make/common/JavaCompilation.gmk
+++ b/make/common/JavaCompilation.gmk
@@ -219,31 +219,35 @@ define SetupJavaCompilationBody
# Use java server if it is enabled, and the user does not want a specialized
# class path.
ifeq ($$(ENABLE_JAVAC_SERVER)+$$($1_CLASSPATH), true+)
- $1_JAVAC := $$(INTERIM_LANGTOOLS_ARGS) -cp $(BUILDTOOLS_OUTPUTDIR)/langtools_javacserver_classes javacserver.Main
-
# Create a configuration file with the needed information for the javac
# server to function properly.
- $1_JAVAC_SERVER_CONFIG := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$$($1_SAFE_NAME)-server.conf
+ $1_JAVAC_SERVER_CONFIG := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$$($1_SAFE_NAME)-javacserver.conf
+
+ # Arguments needed to launch the javacserver client, as well as for the
+ # client to launch the server.
+ $1_JAVAC_SERVER_ARGS := $$(INTERIM_LANGTOOLS_ARGS) \
+ -cp $(BUILDTOOLS_OUTPUTDIR)/langtools_javacserver_classes
# The portfile contains the tcp/ip on which the server listens
# and the cookie necessary to talk to the server.
$1_JAVAC_PORT_FILE := $$(call FixPath, $$(JAVAC_SERVER_DIR)/server.port)
- # The servercmd specifies how to launch the server. This will be executed
- # by the client, if needed.
- $1_JAVAC_SERVER_CMD := $$(call FixPath, $$(JAVA) $$($1_JAVA_FLAGS) $$($1_JAVAC))
+ # The javacmd tells the client how to run java to launch the server.
+ $1_JAVAC_SERVER_JAVA_CMD := $$(call FixPath, $$(JAVA) $$($1_JAVA_FLAGS) \
+ $$($1_JAVAC_SERVER_ARGS))
- $1_CONFIG_VARDEPS := $$($1_JAVAC_PORT_FILE) $$($1_JAVAC_SERVER_CMD)
+ $1_CONFIG_VARDEPS := $$($1_JAVAC_PORT_FILE) $$($1_JAVAC_SERVER_JAVA_CMD)
$1_CONFIG_VARDEPS_FILE := $$(call DependOnVariable, $1_CONFIG_VARDEPS, \
$$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1.config_vardeps)
+ # Write these values to a config file
$$($1_JAVAC_SERVER_CONFIG): $$($1_CONFIG_VARDEPS_FILE)
$(ECHO) portfile=$$($1_JAVAC_PORT_FILE) > $$@
- $(ECHO) servercmd=$$($1_JAVAC_SERVER_CMD) >> $$@
+ $(ECHO) javacmd=$$($1_JAVAC_SERVER_JAVA_CMD) >> $$@
# Always use small java to launch client
- $1_JAVAC_CMD := $$(JAVA_SMALL) $$($1_JAVA_FLAGS) $$($1_JAVAC) \
- --server:conf=$$($1_JAVAC_SERVER_CONFIG)
+ $1_JAVAC_CMD := $$(JAVA_SMALL) $$($1_JAVA_FLAGS) $$($1_JAVAC_SERVER_ARGS) \
+ javacserver.Main --conf=$$($1_JAVAC_SERVER_CONFIG)
else
# No javac server
$1_JAVAC := $$(INTERIM_LANGTOOLS_ARGS) -m jdk.compiler.interim/com.sun.tools.javac.Main
diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk
index 8743f8a7619..252d9dd50da 100644
--- a/make/common/MakeBase.gmk
+++ b/make/common/MakeBase.gmk
@@ -306,17 +306,36 @@ endef
# There are two versions, either creating a relative or an absolute link. Be
# careful when using this on Windows since the symlink created is only valid in
# the unix emulation environment.
-define link-file-relative
+# In msys2 we use mklink /J because its ln would perform a deep copy of the target.
+# This inhibits performance and can lead to issues with long paths. With mklink /J
+# relative linking does not work, so we handle the link as absolute path.
+ifeq ($(OPENJDK_BUILD_OS_ENV), windows.msys2)
+ define link-file-relative
+ $(call MakeTargetDir)
+ $(RM) '$(call DecodeSpace, $@)'
+ cmd //c "mklink /J $(call FixPath, $(call DecodeSpace, $@)) $(call FixPath, $(call DecodeSpace, $<))"
+ endef
+else
+ define link-file-relative
$(call MakeTargetDir)
$(RM) '$(call DecodeSpace, $@)'
$(LN) -s '$(call DecodeSpace, $(call RelativePath, $<, $(@D)))' '$(call DecodeSpace, $@)'
-endef
+ endef
+endif
-define link-file-absolute
+ifeq ($(OPENJDK_BUILD_OS_ENV), windows.msys2)
+ define link-file-absolute
+ $(call MakeTargetDir)
+ $(RM) '$(call DecodeSpace, $@)'
+ cmd //c "mklink /J $(call FixPath, $(call DecodeSpace, $@)) $(call FixPath, $(call DecodeSpace, $<))"
+ endef
+else
+ define link-file-absolute
$(call MakeTargetDir)
$(RM) '$(call DecodeSpace, $@)'
$(LN) -s '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)'
-endef
+ endef
+endif
################################################################################
diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk
index 3a9e5a1a57e..cf1cd2683cd 100644
--- a/make/common/NativeCompilation.gmk
+++ b/make/common/NativeCompilation.gmk
@@ -701,6 +701,19 @@ define SetupNativeCompilationBody
$$(error No sources found for $1 when looking inside the dirs $$($1_SRC))
endif
+ ifeq ($$($1_TYPE), EXECUTABLE)
+ ifeq ($(UBSAN_ENABLED), true)
+ # We need to set the default options for UBSan. This needs to be included in every executable.
+ # Rather than copy and paste code to everything with a main function, we add an additional
+ # source file to every executable that exports __ubsan_default_options.
+ ifneq ($$(filter %.cpp %.cc, $$($1_SRCS)), )
+ $1_SRCS += $(TOPDIR)/make/data/ubsan/ubsan_default_options.cpp
+ else
+ $1_SRCS += $(TOPDIR)/make/data/ubsan/ubsan_default_options.c
+ endif
+ endif
+ endif
+
# Calculate the expected output from compiling the sources
$1_EXPECTED_OBJS_FILENAMES := $$(call replace_with_obj_extension, $$(notdir $$($1_SRCS)))
$1_EXPECTED_OBJS := $$(addprefix $$($1_OBJECT_DIR)/, $$($1_EXPECTED_OBJS_FILENAMES))
diff --git a/make/common/modules/LibCommon.gmk b/make/common/modules/LibCommon.gmk
index aa5c9f0a5c6..2450d2d1e03 100644
--- a/make/common/modules/LibCommon.gmk
+++ b/make/common/modules/LibCommon.gmk
@@ -41,15 +41,12 @@ ifeq ($(TOOLCHAIN_TYPE), gcc)
CFLAGS_JDKLIB += -fvisibility=hidden
CXXFLAGS_JDKLIB += -fvisibility=hidden
LDFLAGS_JDKLIB += -Wl,--exclude-libs,ALL
- EXPORT_ALL_SYMBOLS := -fvisibility=default
else ifeq ($(TOOLCHAIN_TYPE), clang)
CFLAGS_JDKLIB += -fvisibility=hidden
CXXFLAGS_JDKLIB += -fvisibility=hidden
- EXPORT_ALL_SYMBOLS := -fvisibility=default
else ifeq ($(TOOLCHAIN_TYPE), xlc)
CFLAGS_JDKLIB += -qvisibility=hidden
CXXFLAGS_JDKLIB += -qvisibility=hidden
- EXPORT_ALL_SYMBOLS := -qvisibility=default
endif
# Put the libraries here.
diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf
index fa7062b6fa9..b7c27797034 100644
--- a/make/conf/github-actions.conf
+++ b/make/conf/github-actions.conf
@@ -26,7 +26,7 @@
# Versions and download locations for dependencies used by GitHub Actions (GHA)
GTEST_VERSION=1.8.1
-JTREG_VERSION=7.1+1
+JTREG_VERSION=7.1.1+1
LINUX_X64_BOOT_JDK_EXT=tar.gz
LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk19/877d6127e982470ba2a7faa31cc93d04/36/GPL/openjdk-19_linux-x64_bin.tar.gz
diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js
index 4ffc7e50259..064dd7bbd32 100644
--- a/make/conf/jib-profiles.js
+++ b/make/conf/jib-profiles.js
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -944,7 +944,7 @@ var getJibProfilesProfiles = function (input, common, data) {
target_cpu: input.build_cpu,
dependencies: [
"jtreg", "gnumake", "boot_jdk", "devkit", "jib", "jcov", testedProfileJdk,
- testedProfileTest, testedProfile + ".jdk_symbols",
+ testedProfileTest,
],
src: "src.conf",
make_args: testOnlyMake,
@@ -958,6 +958,9 @@ var getJibProfilesProfiles = function (input, common, data) {
labels: "test"
}
};
+ if (!testedProfile.endsWith("-jcov")) {
+ testOnlyProfilesPrebuilt["run-test-prebuilt"]["dependencies"].push(testedProfile + ".jdk_symbols");
+ }
// If actually running the run-test-prebuilt profile, verify that the input
// variable is valid and if so, add the appropriate target_* values from
@@ -987,7 +990,7 @@ var getJibProfilesProfiles = function (input, common, data) {
dependencies: [ "lldb" ],
environment_path: [
input.get("gnumake", "install_path") + "/bin",
- input.get("lldb", "install_path") + "/Xcode.app/Contents/Developer/usr/bin",
+ input.get("lldb", "install_path") + "/Xcode/Contents/Developer/usr/bin",
],
};
profiles["run-test"] = concatObjects(profiles["run-test"], macosxRunTestExtra);
@@ -1032,7 +1035,7 @@ var getJibProfilesDependencies = function (input, common) {
var devkit_platform_revisions = {
linux_x64: "gcc11.2.0-OL6.4+1.0",
- macosx: "Xcode12.4+1.0",
+ macosx: "Xcode12.4+1.1",
windows_x64: "VS2022-17.1.0+1.0",
linux_aarch64: "gcc11.2.0-OL7.6+1.0",
linux_arm: "gcc8.2.0-Fedora27+1.0",
@@ -1123,7 +1126,7 @@ var getJibProfilesDependencies = function (input, common) {
organization: common.organization,
ext: "tar.gz",
module: "devkit-macosx" + (input.build_cpu == "x64" ? "_x64" : ""),
- revision: (input.build_cpu == "x64" ? "Xcode11.3.1-MacOSX10.15+1.1" : devkit_platform_revisions[devkit_platform])
+ revision: (input.build_cpu == "x64" ? "Xcode11.3.1-MacOSX10.15+1.2" : devkit_platform_revisions[devkit_platform])
},
cups: {
@@ -1135,9 +1138,9 @@ var getJibProfilesDependencies = function (input, common) {
jtreg: {
server: "jpg",
product: "jtreg",
- version: "7.1",
+ version: "7.1.1",
build_number: "1",
- file: "bundles/jtreg-7.1+1.zip",
+ file: "bundles/jtreg-7.1.1+1.zip",
environment_name: "JT_HOME",
environment_path: input.get("jtreg", "home_path") + "/bin",
configure_args: "--with-jtreg=" + input.get("jtreg", "home_path"),
@@ -1151,7 +1154,7 @@ var getJibProfilesDependencies = function (input, common) {
jcov: {
organization: common.organization,
- revision: "3.0-13-jdk-asm+1.0",
+ revision: "3.0-14-jdk-asm+1.0",
ext: "zip",
environment_name: "JCOV_HOME",
},
diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf
index 5be559266fe..4a3e5133567 100644
--- a/make/conf/version-numbers.conf
+++ b/make/conf/version-numbers.conf
@@ -26,17 +26,17 @@
# Default version, product, and vendor information to use,
# unless overridden by configure
-DEFAULT_VERSION_FEATURE=20
+DEFAULT_VERSION_FEATURE=21
DEFAULT_VERSION_INTERIM=0
DEFAULT_VERSION_UPDATE=0
DEFAULT_VERSION_PATCH=0
DEFAULT_VERSION_EXTRA1=0
DEFAULT_VERSION_EXTRA2=0
DEFAULT_VERSION_EXTRA3=0
-DEFAULT_VERSION_DATE=2023-03-21
-DEFAULT_VERSION_CLASSFILE_MAJOR=64 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
+DEFAULT_VERSION_DATE=2023-09-19
+DEFAULT_VERSION_CLASSFILE_MAJOR=65 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
DEFAULT_VERSION_CLASSFILE_MINOR=0
DEFAULT_VERSION_DOCS_API_SINCE=11
-DEFAULT_ACCEPTABLE_BOOT_VERSIONS="19 20"
-DEFAULT_JDK_SOURCE_TARGET_VERSION=20
+DEFAULT_ACCEPTABLE_BOOT_VERSIONS="19 20 21"
+DEFAULT_JDK_SOURCE_TARGET_VERSION=21
DEFAULT_PROMOTED_VERSION_PRE=ea
diff --git a/make/data/cldr/common/bcp47/timezone.xml b/make/data/cldr/common/bcp47/timezone.xml
index ddbccff077c..57d81ed48ec 100644
--- a/make/data/cldr/common/bcp47/timezone.xml
+++ b/make/data/cldr/common/bcp47/timezone.xml
@@ -280,6 +280,7 @@ For terms of use, see http://www.unicode.org/copyright.html
+
diff --git a/make/data/cldr/common/main/root.xml b/make/data/cldr/common/main/root.xml
index 411a316f8ed..44c80ff1348 100644
--- a/make/data/cldr/common/main/root.xml
+++ b/make/data/cldr/common/main/root.xml
@@ -2994,6 +2994,18 @@ Warnings: All cp values have U+FE0F characters removed. See /annotationsDerived/
Ho Chi Minh
+
+ BahÃa de Banderas
+
+
+ Cancún
+
+
+ Ciudad Juárez
+
+
+ Mérida
+
diff --git a/make/data/cldr/common/supplemental/metaZones.xml b/make/data/cldr/common/supplemental/metaZones.xml
index 1c363cbe7aa..0beb757cacb 100644
--- a/make/data/cldr/common/supplemental/metaZones.xml
+++ b/make/data/cldr/common/supplemental/metaZones.xml
@@ -333,6 +333,12 @@ For terms of use, see http://www.unicode.org/copyright.html
+
+
+
+
+
+
@@ -621,8 +627,7 @@ For terms of use, see http://www.unicode.org/copyright.html
-
-
+
diff --git a/make/data/hotspot-symbols/symbols-unix b/make/data/hotspot-symbols/symbols-unix
index de2babed51a..ae49a992f54 100644
--- a/make/data/hotspot-symbols/symbols-unix
+++ b/make/data/hotspot-symbols/symbols-unix
@@ -194,8 +194,6 @@ JVM_RegisterLambdaProxyClassForArchiving
JVM_RegisterSignal
JVM_ReleaseUTF
JVM_ReportFinalizationComplete
-JVM_ExtentLocalCache
-JVM_SetExtentLocalCache
JVM_SetArrayElement
JVM_SetClassSigners
JVM_SetNativeThreadName
@@ -225,4 +223,10 @@ JVM_VirtualThreadMountEnd
JVM_VirtualThreadUnmountBegin
JVM_VirtualThreadUnmountEnd
JVM_VirtualThreadHideFrames
+
+# Scoped values
+JVM_EnsureMaterializedForStackWalk_func
+JVM_FindScopedValueBindings
+JVM_ScopedValueCache
+JVM_SetScopedValueCache
#
diff --git a/make/data/ubsan/ubsan_default_options.c b/make/data/ubsan/ubsan_default_options.c
new file mode 100644
index 00000000000..ee426ebbc39
--- /dev/null
+++ b/make/data/ubsan/ubsan_default_options.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. 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.
+ */
+
+#ifndef UNDEFINED_BEHAVIOR_SANITIZER
+#error "Build misconfigured, preprocessor macro UNDEFINED_BEHAVIOR_SANITIZER should be defined"
+#endif
+
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
+#if (defined(__GNUC__) && !defined(__clang__)) || __has_attribute(visibility)
+#define ATTRIBUTE_DEFAULT_VISIBILITY __attribute__((visibility("default")))
+#else
+#define ATTRIBUTE_DEFAULT_VISIBILITY
+#endif
+
+#if (defined(__GNUC__) && !defined(__clang__)) || __has_attribute(used)
+#define ATTRIBUTE_USED __attribute__((used))
+#else
+#define ATTRIBUTE_USED
+#endif
+
+// Override weak symbol exposed by UBSan to override default options. This is called by UBSan
+// extremely early during library loading, before main is called. We need to override the default
+// options because by default UBSan only prints a warning for each occurrence. We want jtreg tests
+// to fail when undefined behavior is encountered. We also want a full stack trace for the offending
+// thread so it is easier to track down. You can override these options by setting the environment
+// variable UBSAN_OPTIONS.
+ATTRIBUTE_DEFAULT_VISIBILITY ATTRIBUTE_USED const char* __ubsan_default_options() {
+ return "halt_on_error=1,print_stacktrace=1";
+}
diff --git a/make/data/ubsan/ubsan_default_options.cpp b/make/data/ubsan/ubsan_default_options.cpp
new file mode 100644
index 00000000000..dbebb5b2977
--- /dev/null
+++ b/make/data/ubsan/ubsan_default_options.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+extern "C" {
+
+#include "./ubsan_default_options.c"
+
+} // extern "C"
diff --git a/make/hotspot/lib/JvmFlags.gmk b/make/hotspot/lib/JvmFlags.gmk
index 1588c19fac3..1fadd5331aa 100644
--- a/make/hotspot/lib/JvmFlags.gmk
+++ b/make/hotspot/lib/JvmFlags.gmk
@@ -67,10 +67,12 @@ JVM_CFLAGS_TARGET_DEFINES += \
#
ifeq ($(DEBUG_LEVEL), release)
+ # release builds disable uses of assert macro from .
+ JVM_CFLAGS_DEBUGLEVEL := -DNDEBUG
# For hotspot, release builds differ internally between "optimized" and "product"
# in that "optimize" does not define PRODUCT.
ifneq ($(HOTSPOT_DEBUG_LEVEL), optimized)
- JVM_CFLAGS_DEBUGLEVEL := -DPRODUCT
+ JVM_CFLAGS_DEBUGLEVEL += -DPRODUCT
endif
else ifeq ($(DEBUG_LEVEL), fastdebug)
JVM_CFLAGS_DEBUGLEVEL := -DASSERT
diff --git a/make/hotspot/test/GtestImage.gmk b/make/hotspot/test/GtestImage.gmk
index 322a90b3d10..d216328e567 100644
--- a/make/hotspot/test/GtestImage.gmk
+++ b/make/hotspot/test/GtestImage.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -41,10 +41,22 @@ ifeq ($(call isTargetOs, windows), true)
$(foreach v, $(JVM_VARIANTS), \
$(eval $(call SetupCopyFiles, COPY_GTEST_MSVCR_$v, \
DEST := $(TEST_IMAGE_DIR)/hotspot/gtest/$v, \
- FILES := $(MSVCR_DLL) $(VCRUNTIME_1_DLL) $(MSVCP_DLL), \
+ FILES := $(MSVCR_DLL), \
FLATTEN := true, \
)) \
$(eval TARGETS += $$(COPY_GTEST_MSVCR_$v)) \
+ $(eval $(call SetupCopyFiles, COPY_GTEST_VCRUNTIME_1_$v, \
+ DEST := $(TEST_IMAGE_DIR)/hotspot/gtest/$v, \
+ FILES := $(VCRUNTIME_1_DLL), \
+ FLATTEN := true, \
+ )) \
+ $(eval TARGETS += $$(COPY_GTEST_VCRUNTIME_1_$v)) \
+ $(eval $(call SetupCopyFiles, COPY_GTEST_MSVCP_$v, \
+ DEST := $(TEST_IMAGE_DIR)/hotspot/gtest/$v, \
+ FILES := $(MSVCP_DLL), \
+ FLATTEN := true, \
+ )) \
+ $(eval TARGETS += $$(COPY_GTEST_MSVCP_$v)) \
$(if $(call equals, $(COPY_DEBUG_SYMBOLS), true), \
$(eval $(call SetupCopyFiles, COPY_GTEST_PDB_$v, \
SRC := $(HOTSPOT_OUTPUTDIR)/variant-$v/libjvm/gtest, \
diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java
index e0e95c9e6a2..d6c502252e0 100644
--- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java
+++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,8 +34,6 @@
import java.time.*;
import java.util.*;
import java.util.ResourceBundle.Control;
-import java.util.logging.Level;
-import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
@@ -609,16 +607,19 @@ private static void convertBundles(List bundles) throws Exception {
* Translate the aliases into the real entries in the bundle map.
*/
static void handleAliases(Map bundleMap) {
- Set bundleKeys = bundleMap.keySet();
- try {
- for (String key : aliases.keySet()) {
- String targetKey = aliases.get(key);
- if (bundleKeys.contains(targetKey)) {
- bundleMap.putIfAbsent(key, bundleMap.get(targetKey));
+ for (String key : aliases.keySet()) {
+ var source = bundleMap.get(aliases.get(key));
+ if (source != null) {
+ if (bundleMap.get(key) instanceof String[] sa) {
+ // fill missing elements in case of String array
+ for (int i = 0; i < sa.length; i++) {
+ if (sa[i] == null && ((String[])source)[i] != null) {
+ sa[i] = ((String[])source)[i];
+ }
+ }
}
+ bundleMap.putIfAbsent(key, source);
}
- } catch (Exception ex) {
- Logger.getLogger(CLDRConverter.class.getName()).log(Level.SEVERE, null, ex);
}
}
@@ -633,7 +634,7 @@ static String getLanguageCode(String id) {
/**
* Examine if the id includes the country (territory) code. If it does, it returns
* the country code.
- * Otherwise, it returns null. eg. when the id is "zh_Hans_SG", it return "SG".
+ * Otherwise, it returns null. eg. when the id is "zh_Hans_SG", it returns "SG".
* It does NOT return UN M.49 code, e.g., '001', as those three digit numbers cannot
* be translated into package names.
*/
@@ -645,13 +646,21 @@ static String getCountryCode(String id) {
/**
* Examine if the id includes the region code. If it does, it returns
* the region code.
- * Otherwise, it returns null. eg. when the id is "zh_Hans_SG", it return "SG".
+ * Otherwise, it returns null. eg. when the id is "zh_Hans_SG", it returns "SG".
* It DOES return UN M.49 code, e.g., '001', as well as ISO 3166 two letter country codes.
*/
static String getRegionCode(String id) {
return Locale.forLanguageTag(id.replaceAll("_", "-")).getCountry();
}
+ /**
+ * Examine if the id includes the script code. If it does, it returns
+ * the script code.
+ */
+ static String getScriptCode(String id) {
+ return Locale.forLanguageTag(id.replaceAll("_", "-")).getScript();
+ }
+
private static class KeyComparator implements Comparator {
static KeyComparator INSTANCE = new KeyComparator();
@@ -1020,6 +1029,7 @@ private static String toLocaleName(String tag) {
private static void setupBaseLocales(String localeList) {
Arrays.stream(localeList.split(","))
.map(Locale::forLanguageTag)
+ .map(l -> new Locale.Builder().setLocale(l).setScript("Latn").build())
.map(l -> Control.getControl(Control.FORMAT_DEFAULT)
.getCandidateLocales("", l))
.forEach(BASE_LOCALES::addAll);
diff --git a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java
index 344bb0ea21f..6b2b5b4c0c0 100644
--- a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java
+++ b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java
@@ -417,11 +417,11 @@ public Map parentLocales() {
private static final Locale.Builder LOCALE_BUILDER = new Locale.Builder();
private static boolean isBaseLocale(String localeID) {
localeID = localeID.replaceAll("-", "_");
- // ignore script here
Locale locale = LOCALE_BUILDER
.clear()
.setLanguage(CLDRConverter.getLanguageCode(localeID))
.setRegion(CLDRConverter.getRegionCode(localeID))
+ .setScript(CLDRConverter.getScriptCode(localeID))
.build();
return CLDRConverter.BASE_LOCALES.contains(locale);
}
diff --git a/make/jdk/src/classes/build/tools/taglet/SealedGraph.java b/make/jdk/src/classes/build/tools/taglet/SealedGraph.java
index da79c17b387..df719d6fce6 100644
--- a/make/jdk/src/classes/build/tools/taglet/SealedGraph.java
+++ b/make/jdk/src/classes/build/tools/taglet/SealedGraph.java
@@ -40,6 +40,7 @@
import static java.lang.System.lineSeparator;
import static java.nio.file.StandardOpenOption.*;
+import static java.util.stream.Collectors.joining;
import static jdk.javadoc.doclet.Taglet.Location.TYPE;
/**
@@ -98,7 +99,7 @@ public String toString(List extends DocTree> tags, Element element) {
.map(Objects::toString)
.collect(Collectors.toUnmodifiableSet());
- String dotContent = Renderer.graph(typeElement, exports);
+ String dotContent = new Renderer().graph(typeElement, exports);
try {
Files.writeString(dotFile, dotContent, WRITE, CREATE, TRUNCATE_EXISTING);
@@ -133,13 +134,10 @@ private String getImage(String typeName, String file, int height, boolean useBor
(height <= 0 ? "" : " height=\"" + height + "\""));
}
- private static final class Renderer {
-
- private Renderer() {
- }
+ private final class Renderer {
// Generates a graph in DOT format
- static String graph(TypeElement rootClass, Set exports) {
+ String graph(TypeElement rootClass, Set exports) {
final State state = new State(rootClass);
traverse(state, rootClass, exports);
return state.render();
@@ -155,17 +153,21 @@ static void traverse(State state, TypeElement node, Set exports) {
}
}
- private static final class State {
+ private final class State {
private static final String LABEL = "label";
private static final String TOOLTIP = "tooltip";
+ private static final String LINK = "href";
private static final String STYLE = "style";
+ private final TypeElement rootNode;
+
private final StringBuilder builder;
private final Map> nodeStyleMap;
public State(TypeElement rootNode) {
+ this.rootNode = rootNode;
nodeStyleMap = new LinkedHashMap<>();
builder = new StringBuilder()
.append("digraph G {")
@@ -188,12 +190,30 @@ public void addNode(TypeElement node) {
var styles = nodeStyleMap.computeIfAbsent(id(node), n -> new LinkedHashMap<>());
styles.put(LABEL, node.getSimpleName().toString());
styles.put(TOOLTIP, node.getQualifiedName().toString());
+ styles.put(LINK, relativeLink(node));
if (!(node.getModifiers().contains(Modifier.SEALED) || node.getModifiers().contains(Modifier.FINAL))) {
// This indicates that the hierarchy is not closed
styles.put(STYLE, "dashed");
}
}
+ // A permitted class must be in the same package or in the same module.
+ // This implies the module is always the same.
+ private String relativeLink(TypeElement node) {
+ var util = SealedGraph.this.docletEnvironment.getElementUtils();
+ var rootPackage = util.getPackageOf(rootNode);
+ var nodePackage = util.getPackageOf(node);
+ var backNavigator = rootPackage.getQualifiedName().toString().chars()
+ .filter(c -> c == '.')
+ .mapToObj(c -> "../")
+ .collect(joining()) +
+ "../";
+ var forwardNavigator = nodePackage.getQualifiedName().toString()
+ .replace(".", "/");
+
+ return backNavigator + forwardNavigator + "/" + node.getSimpleName() + ".html";
+ }
+
public void addEdge(TypeElement node, TypeElement subNode) {
builder.append(" ")
.append(quotedId(subNode))
@@ -209,8 +229,8 @@ public String render() {
.append('"').append(nodeName).append("\" ")
.append(styles.entrySet().stream()
.map(e -> e.getKey() + "=\"" + e.getValue() + "\"")
- .collect(Collectors.joining(" ", "[", "]")))
- .append(System.lineSeparator());
+ .collect(joining(" ", "[", "]")))
+ .append(lineSeparator());
});
builder.append("}");
return builder.toString();
diff --git a/make/langtools/tools/javacserver/Main.java b/make/langtools/tools/javacserver/Main.java
index 2eecfb2b4a8..b2582518948 100644
--- a/make/langtools/tools/javacserver/Main.java
+++ b/make/langtools/tools/javacserver/Main.java
@@ -25,34 +25,13 @@
package javacserver;
-import java.util.Arrays;
-
-import javacserver.client.ClientMain;
-import javacserver.server.ServerMain;
-
-import static javacserver.options.Option.STARTSERVER;
+import javacserver.client.Client;
/**
- * The application entry point of the smart javac wrapper tool.
- *
- * This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
+ * The application entry point of the javacserver build tool.
*/
public class Main {
-
- public static void main(String... args) {
- System.exit(go(args));
- }
-
- public static int go(String[] args) {
-
- // Server or client mode?
- boolean serverMode = Arrays.asList(args)
- .stream()
- .anyMatch(arg -> arg.startsWith(STARTSERVER.arg));
-
- return serverMode ? ServerMain.run(args) : ClientMain.run(args);
+ public static void main(String... args) {
+ Client.main(args);
}
}
diff --git a/make/langtools/tools/javacserver/Util.java b/make/langtools/tools/javacserver/Util.java
deleted file mode 100644
index 96558d503c8..00000000000
--- a/make/langtools/tools/javacserver/Util.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package javacserver;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.regex.Pattern;
-import java.util.stream.Stream;
-
-/**
- * Utilities.
- *
- *
This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
- */
-public class Util {
-
-
-
- public static String extractStringOption(String opName, String s) {
- return extractStringOption(opName, s, null);
- }
-
- private static String extractStringOptionWithDelimiter(String opName, String s, String deflt, char delimiter) {
- int p = s.indexOf(opName+"=");
- if (p == -1) return deflt;
- p+=opName.length()+1;
- int pe = s.indexOf(delimiter, p);
- if (pe == -1) pe = s.length();
- return s.substring(p, pe);
- }
-
- public static String extractStringOption(String opName, String s, String deflt) {
- return extractStringOptionWithDelimiter(opName, s, deflt, ',');
- }
-
- public static String extractStringOptionLine(String opName, String s, String deflt) {
- return extractStringOptionWithDelimiter(opName, s, deflt, '\n').strip();
- }
-
- public static int extractIntOption(String opName, String s, int deflt) {
- int p = s.indexOf(opName+"=");
- if (p == -1) return deflt;
- p+=opName.length()+1;
- int pe = s.indexOf(',', p);
- if (pe == -1) pe = s.length();
- int v = 0;
- try {
- v = Integer.parseInt(s.substring(p, pe));
- } catch (Exception e) {}
- return v;
- }
-
-
- /**
- * Convenience method to create a set with strings.
- */
- public static Set set(String... ss) {
- Set set = new HashSet<>();
- set.addAll(Arrays.asList(ss));
- return set;
- }
-
- /**
- * Normalize windows drive letter paths to upper case to enable string
- * comparison.
- *
- * @param file File name to normalize
- * @return The normalized string if file has a drive letter at the beginning,
- * otherwise the original string.
- */
- public static String normalizeDriveLetter(String file) {
- if (file.length() > 2 && file.charAt(1) == ':') {
- return Character.toUpperCase(file.charAt(0)) + file.substring(1);
- } else if (file.length() > 3 && file.charAt(0) == '*'
- && file.charAt(2) == ':') {
- // Handle a wildcard * at the beginning of the string.
- return file.substring(0, 1) + Character.toUpperCase(file.charAt(1))
- + file.substring(2);
- }
- return file;
- }
-
-
- public static Set union(Set extends E> s1,
- Set extends E> s2) {
- Set union = new HashSet<>();
- union.addAll(s1);
- union.addAll(s2);
- return union;
- }
-
- public static Set subtract(Set extends E> orig,
- Set extends E> toSubtract) {
- Set difference = new HashSet<>(orig);
- difference.removeAll(toSubtract);
- return difference;
- }
-
- public static String getStackTrace(Throwable t) {
- StringWriter sw = new StringWriter();
- t.printStackTrace(new PrintWriter(sw));
- return sw.toString();
- }
-
- public static Set intersection(Collection extends E> c1,
- Collection extends E> c2) {
- Set intersection = new HashSet(c1);
- intersection.retainAll(c2);
- return intersection;
- }
-
-
- public static Stream getLines(String str) {
- return str.isEmpty()
- ? Stream.empty()
- : Stream.of(str.split(Pattern.quote(System.lineSeparator())));
- }
-}
diff --git a/make/langtools/tools/javacserver/client/Client.java b/make/langtools/tools/javacserver/client/Client.java
new file mode 100644
index 00000000000..b3b4a8543a0
--- /dev/null
+++ b/make/langtools/tools/javacserver/client/Client.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javacserver.client;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import javacserver.server.Server;
+import javacserver.shared.PortFileInaccessibleException;
+import javacserver.shared.Protocol;
+import javacserver.shared.Result;
+import javacserver.util.AutoFlushWriter;
+import javacserver.util.Log;
+
+/**
+ * The javacserver client. This is called from the makefiles, and is responsible for passing the command
+ * line on to a server instance running javac, starting a new server if needed.
+ */
+public class Client {
+ private static final Log.Level LOG_LEVEL = Log.Level.INFO;
+
+ // Wait 2 seconds for response, before giving up on javac server.
+ private static final int CONNECTION_TIMEOUT = 2000;
+ private static final int MAX_CONNECT_ATTEMPTS = 3;
+ private static final int WAIT_BETWEEN_CONNECT_ATTEMPTS = 2000;
+
+ private final ClientConfiguration conf;
+
+ public Client(ClientConfiguration conf) {
+ this.conf = conf;
+ }
+
+ public static void main(String... args) {
+ Log.setLogForCurrentThread(new Log(
+ new AutoFlushWriter(new OutputStreamWriter(System.out)),
+ new AutoFlushWriter(new OutputStreamWriter(System.err))));
+ Log.setLogLevel(LOG_LEVEL);
+
+ ClientConfiguration conf = ClientConfiguration.fromCommandLineArguments(args);
+ if (conf == null) {
+ System.exit(Result.CMDERR.exitCode);
+ }
+
+ Client client = new Client(conf);
+ int exitCode = client.dispatchToServer();
+
+ System.exit(exitCode);
+ }
+
+ private int dispatchToServer() {
+ try {
+ // Check if server seems to be already running
+ if (!conf.portFile().hasValidValues()) {
+ // Fork a new server and wait for it to start
+ startNewServer();
+ }
+
+ try (Socket socket = tryConnect()) {
+ BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
+
+ Protocol.sendCommand(out, conf.javacArgs());
+ int exitCode = Protocol.readResponse(in);
+
+ return exitCode;
+ }
+ } catch (PortFileInaccessibleException e) {
+ Log.error("Port file inaccessible.");
+ return Result.ERROR.exitCode;
+ } catch (IOException ioe) {
+ Log.error("IOException caught during compilation: " + ioe.getMessage());
+ Log.debug(ioe);
+ return Result.ERROR.exitCode;
+ } catch (InterruptedException ie) {
+ Thread.currentThread().interrupt(); // Restore interrupt
+ Log.error("Compilation interrupted.");
+ Log.debug(ie);
+ return Result.ERROR.exitCode;
+ }
+ }
+
+ /*
+ * Makes MAX_CONNECT_ATTEMPTS attempts to connect to server.
+ */
+ private Socket tryConnect() throws IOException, InterruptedException {
+ int attempt = 0;
+
+ while (true) {
+ Log.debug("Trying to connect. Attempt " + (++attempt) + " of " + MAX_CONNECT_ATTEMPTS);
+ try {
+ Socket socket = new Socket();
+ InetAddress localhost = InetAddress.getByName(null);
+ InetSocketAddress address = new InetSocketAddress(localhost, conf.portFile().getPort());
+ socket.connect(address, CONNECTION_TIMEOUT);
+ Log.debug("Connected");
+ return socket;
+ } catch (IOException ex) {
+ Log.error("Connection attempt failed: " + ex.getMessage());
+ if (attempt >= MAX_CONNECT_ATTEMPTS) {
+ Log.error("Giving up");
+ throw new IOException("Could not connect to server", ex);
+ }
+ }
+ Thread.sleep(WAIT_BETWEEN_CONNECT_ATTEMPTS);
+ }
+ }
+
+ /*
+ * Fork a server process and wait for server to come around
+ */
+ private void startNewServer() throws IOException, InterruptedException {
+ List cmd = new ArrayList<>();
+ // conf.javaCommand() is how to start java in the way we want to run
+ // the server
+ cmd.addAll(Arrays.asList(conf.javaCommand().split(" ")));
+ // javacserver.server.Server is the server main class
+ cmd.add(Server.class.getName());
+ // and it expects a port file path
+ cmd.add(conf.portFile().getFilename());
+
+ Process serverProcess;
+ Log.debug("Starting server. Command: " + String.join(" ", cmd));
+ try {
+ // If the cmd for some reason can't be executed (file is not found,
+ // or is not executable for instance) this will throw an
+ // IOException
+ serverProcess = new ProcessBuilder(cmd).redirectErrorStream(true).start();
+ } catch (IOException ex) {
+ // Message is typically something like:
+ // Cannot run program "xyz": error=2, No such file or directory
+ Log.error("Failed to create server process: " + ex.getMessage());
+ Log.debug(ex);
+ throw new IOException(ex);
+ }
+
+ // serverProcess != null at this point.
+ try {
+ // Throws an IOException if no valid values materialize
+ conf.portFile().waitForValidValues();
+ } catch (IOException ex) {
+ // Process was started, but server failed to initialize. This could
+ // for instance be due to the JVM not finding the server class,
+ // or the server running in to some exception early on.
+ Log.error("javacserver server process failed to initialize: " + ex.getMessage());
+ Log.error("Process output:");
+ Reader serverStdoutStderr = new InputStreamReader(serverProcess.getInputStream());
+ try (BufferedReader br = new BufferedReader(serverStdoutStderr)) {
+ br.lines().forEach(Log::error);
+ }
+ Log.error("");
+ try {
+ Log.error("Process exit code: " + serverProcess.exitValue());
+ } catch (IllegalThreadStateException e) {
+ // Server is presumably still running.
+ }
+ throw new IOException("Server failed to initialize: " + ex.getMessage(), ex);
+ }
+ }
+}
diff --git a/make/langtools/tools/javacserver/client/ClientConfiguration.java b/make/langtools/tools/javacserver/client/ClientConfiguration.java
new file mode 100644
index 00000000000..1c901d615f3
--- /dev/null
+++ b/make/langtools/tools/javacserver/client/ClientConfiguration.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javacserver.client;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.List;
+import javacserver.shared.PortFile;
+import javacserver.util.Log;
+
+/**
+ * Description of the arguments needed to start a javacserver client, as extracted from
+ * the command line and configuration file.
+ */
+public record ClientConfiguration(PortFile portFile, String javaCommand, String[] javacArgs) {
+ static ClientConfiguration fromCommandLineArguments(String... args) {
+ String confFileName = getConfFileName(args);
+ if (confFileName == null) {
+ return null;
+ }
+
+ String confFileContent = getConfFileContent(confFileName);
+ if (confFileContent == null) {
+ return null;
+ }
+
+ String portFileName = getPortFileName(confFileContent);
+ if (portFileName == null) {
+ return null;
+ }
+ String javaCommand = getJavaCommandString(confFileContent);
+ if (javaCommand == null) {
+ return null;
+ }
+
+ PortFile portFile = new PortFile(portFileName);
+ String[] javacArgs = Arrays.copyOfRange(args, 1, args.length);
+
+ ClientConfiguration conf = new ClientConfiguration(portFile, javaCommand, javacArgs);
+ return conf;
+ }
+
+ private static String getConfFileName(String[] args) {
+ if (args.length < 1) {
+ Log.error("Error: javacserver client: missing --conf= argument");
+ return null;
+ }
+ String[] conf = args[0].split("=", 2);
+ if (conf.length != 2 || !conf[0].equalsIgnoreCase("--conf")) {
+ Log.error("Error: javacserver client: first argument must be --conf=");
+ return null;
+ }
+ String confFileName = conf[1];
+ if (!Files.exists(Path.of(confFileName))) {
+ Log.error("Error: javacserver client: specified conf file does not exist");
+ return null;
+ }
+ return confFileName;
+ }
+
+ private static String getConfFileContent(String confFile) {
+ try {
+ List confFileLines = Files.readAllLines(Path.of(confFile));
+ String confFileContent = String.join("\n", confFileLines);
+ return confFileContent;
+ } catch (IOException e) {
+ Log.error("Cannot read configuration file " + confFile);
+ Log.debug(e);
+ return null;
+ }
+ }
+
+ private static String getJavaCommandString(String confFileContent) {
+ String serverCommandString = getConfValue("javacmd", confFileContent);
+ if (serverCommandString.isEmpty()) {
+ Log.error("Configuration file missing value for 'javacmd'");
+ return null;
+ } else {
+ return serverCommandString;
+ }
+ }
+
+ private static String getPortFileName(String confFileContent) {
+ String portfileName = getConfValue("portfile", confFileContent);
+ if (portfileName.isEmpty()) {
+ Log.error("Configuration file missing value for 'portfile'");
+ return null;
+ } else {
+ return portfileName;
+ }
+ }
+
+ private static String getConfValue(String optionName, String content) {
+ String result;
+ int p = content.indexOf(optionName + "=");
+ if (p == -1) {
+ result = "";
+ } else {
+ p += optionName.length() + 1;
+ int pe = content.indexOf('\n', p);
+ if (pe == -1) pe = content.length();
+ result = content.substring(p, pe);
+ }
+ return result.strip();
+ }
+}
\ No newline at end of file
diff --git a/make/langtools/tools/javacserver/client/ClientMain.java b/make/langtools/tools/javacserver/client/ClientMain.java
deleted file mode 100644
index c26ead5e633..00000000000
--- a/make/langtools/tools/javacserver/client/ClientMain.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package javacserver.client;
-
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-
-import javacserver.AutoFlushWriter;
-import javacserver.Log;
-import javacserver.Result;
-import javacserver.comp.SjavacImpl;
-import javacserver.options.Options;
-import javacserver.server.Sjavac;
-
-/**
- * This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
- */
-public class ClientMain {
-
- public static int run(String[] args) {
- return run(args,
- new AutoFlushWriter(new OutputStreamWriter(System.out)),
- new AutoFlushWriter(new OutputStreamWriter(System.err)));
- }
-
- public static int run(String[] args, Writer out, Writer err) {
-
- Log.setLogForCurrentThread(new Log(out, err));
-
- Options options;
- try {
- options = Options.parseArgs(args);
- } catch (IllegalArgumentException e) {
- Log.error(e.getMessage());
- return Result.CMDERR.exitCode;
- }
-
- Log.setLogLevel(options.getLogLevel());
-
- // Prepare sjavac object
- boolean useServer = options.getServerConf() != null;
- Sjavac sjavac = useServer ? new SjavacClient(options) : new SjavacImpl();
-
- // Perform compilation
- Result result = sjavac.compile(args);
-
- // If sjavac is running in the foreground we should shut it down at this point
- if (!useServer) {
- sjavac.shutdown();
- }
-
- return result.exitCode;
- }
-}
diff --git a/make/langtools/tools/javacserver/client/SjavacClient.java b/make/langtools/tools/javacserver/client/SjavacClient.java
deleted file mode 100644
index 3d12eb31782..00000000000
--- a/make/langtools/tools/javacserver/client/SjavacClient.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package javacserver.client;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.Reader;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import javacserver.Log;
-import javacserver.Result;
-import javacserver.Util;
-import javacserver.options.Options;
-import javacserver.server.PortFile;
-import javacserver.server.Sjavac;
-import javacserver.server.SjavacServer;
-
-/**
- * Sjavac implementation that delegates requests to a SjavacServer.
- *
- *
This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
- */
-public class SjavacClient implements Sjavac {
-
- private PortFile portFile;
-
- // The servercmd option specifies how the server part of sjavac is spawned.
- // It should point to a javacserver.Main that supports --startserver
- private String serverCommand;
-
- // Accept 120 seconds of inactivity before quitting.
- private static final int KEEPALIVE = 120;
- private static final int POOLSIZE = Runtime.getRuntime().availableProcessors();
- // Wait 2 seconds for response, before giving up on javac server.
- private static final int CONNECTION_TIMEOUT = 2000;
- private static final int MAX_CONNECT_ATTEMPTS = 3;
- private static final int WAIT_BETWEEN_CONNECT_ATTEMPTS = 2000;
-
- public SjavacClient(Options options) {
- String serverConf = options.getServerConf();
- String configFile = Util.extractStringOption("conf", serverConf, "");
-
- try {
- List configFileLines = Files.readAllLines(Path.of(configFile));
- String configFileContent = String.join("\n", configFileLines);
-
- String portfileName = Util.extractStringOptionLine("portfile", configFileContent, "");
- if (portfileName.isEmpty()) {
- Log.error("Configuration file missing value for 'portfile'");
- portFile = null;
- } else {
- portFile = SjavacServer.getPortFile(portfileName);
- }
-
- String serverCommandString = Util.extractStringOptionLine("servercmd", configFileContent, "");
- if (serverCommandString.isEmpty()) {
- Log.error("Configuration file missing value for 'servercmd'");
- serverCommand = null;
- } else {
- serverCommand = serverCommandString;
- }
- } catch (IOException e) {
- Log.error("Cannot read configuration file " + configFile);
- Log.debug(e);
- portFile = null;
- serverCommand = null;
- }
- }
-
- @Override
- public Result compile(String[] args) {
- if (portFile == null || serverCommand == null) {
- Log.error("Incorrect configuration, portfile and/or servercmd missing");
- return Result.ERROR;
- }
-
- Result result = null;
- try (Socket socket = tryConnect()) {
- PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
- BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
-
- // Send args array to server
- out.println(args.length);
- for (String arg : args)
- out.println(arg);
- out.flush();
-
- // Read server response line by line
- String line;
- while (null != (line = in.readLine())) {
- if (!line.contains(":")) {
- throw new AssertionError("Could not parse protocol line: >>\"" + line + "\"<<");
- }
- String[] typeAndContent = line.split(":", 2);
- String type = typeAndContent[0];
- String content = typeAndContent[1];
-
- try {
- if (Log.isDebugging()) {
- // Distinguish server generated output if debugging.
- content = "[sjavac-server] " + content;
- }
- Log.log(Log.Level.valueOf(type), content);
- continue;
- } catch (IllegalArgumentException e) {
- // Parsing of 'type' as log level failed.
- }
-
- if (type.equals(SjavacServer.LINE_TYPE_RC)) {
- result = Result.valueOf(content);
- }
- }
- } catch (PortFileInaccessibleException e) {
- Log.error("Port file inaccessible.");
- result = Result.ERROR;
- } catch (IOException ioe) {
- Log.error("IOException caught during compilation: " + ioe.getMessage());
- Log.debug(ioe);
- result = Result.ERROR;
- } catch (InterruptedException ie) {
- Thread.currentThread().interrupt(); // Restore interrupt
- Log.error("Compilation interrupted.");
- Log.debug(ie);
- result = Result.ERROR;
- }
-
- if (result == null) {
- // No LINE_TYPE_RC was found.
- result = Result.ERROR;
- }
-
- return result;
- }
-
- /*
- * Makes MAX_CONNECT_ATTEMPTS attempts to connect to server.
- */
- private Socket tryConnect() throws IOException, InterruptedException {
- makeSureServerIsRunning();
- int attempt = 0;
- while (true) {
- Log.debug("Trying to connect. Attempt " + (++attempt) + " of " + MAX_CONNECT_ATTEMPTS);
- try {
- return makeConnectionAttempt();
- } catch (IOException ex) {
- Log.error("Connection attempt failed: " + ex.getMessage());
- if (attempt >= MAX_CONNECT_ATTEMPTS) {
- Log.error("Giving up");
- throw new IOException("Could not connect to server", ex);
- }
- }
- Thread.sleep(WAIT_BETWEEN_CONNECT_ATTEMPTS);
- }
- }
-
- private Socket makeConnectionAttempt() throws IOException {
- Socket socket = new Socket();
- InetAddress localhost = InetAddress.getByName(null);
- InetSocketAddress address = new InetSocketAddress(localhost, portFile.getPort());
- socket.connect(address, CONNECTION_TIMEOUT);
- Log.debug("Connected");
- return socket;
- }
-
- /*
- * Will return immediately if a server already seems to be running,
- * otherwise fork a new server and block until it seems to be running.
- */
- private void makeSureServerIsRunning()
- throws IOException, InterruptedException {
-
- if (portFile.exists()) {
- portFile.lock();
- portFile.getValues();
- portFile.unlock();
-
- if (portFile.containsPortInfo()) {
- // Server seems to already be running
- return;
- }
- }
-
- // Fork a new server and wait for it to start
- startNewServer();
- }
-
- @Override
- public void shutdown() {
- // Nothing to clean up
- }
-
- /*
- * Fork a server process process and wait for server to come around
- */
- public void startNewServer()
- throws IOException, InterruptedException {
- List cmd = new ArrayList<>();
- cmd.addAll(Arrays.asList(serverCommand.split(" ")));
- cmd.add("--startserver:"
- + "portfile=" + portFile.getFilename()
- + ",poolsize=" + POOLSIZE
- + ",keepalive="+ KEEPALIVE);
-
- Process serverProcess;
- Log.debug("Starting server. Command: " + String.join(" ", cmd));
- try {
- // If the cmd for some reason can't be executed (file is not found,
- // or is not executable for instance) this will throw an
- // IOException and p == null.
- serverProcess = new ProcessBuilder(cmd)
- .redirectErrorStream(true)
- .start();
- } catch (IOException ex) {
- // Message is typically something like:
- // Cannot run program "xyz": error=2, No such file or directory
- Log.error("Failed to create server process: " + ex.getMessage());
- Log.debug(ex);
- throw new IOException(ex);
- }
-
- // serverProcess != null at this point.
- try {
- // Throws an IOException if no valid values materialize
- portFile.waitForValidValues();
- } catch (IOException ex) {
- // Process was started, but server failed to initialize. This could
- // for instance be due to the JVM not finding the server class,
- // or the server running in to some exception early on.
- Log.error("Sjavac server failed to initialize: " + ex.getMessage());
- Log.error("Process output:");
- Reader serverStdoutStderr = new InputStreamReader(serverProcess.getInputStream());
- try (BufferedReader br = new BufferedReader(serverStdoutStderr)) {
- br.lines().forEach(Log::error);
- }
- Log.error("");
- try {
- Log.error("Process exit code: " + serverProcess.exitValue());
- } catch (IllegalThreadStateException e) {
- // Server is presumably still running.
- }
- throw new IOException("Server failed to initialize: " + ex.getMessage(), ex);
- }
- }
-}
diff --git a/make/langtools/tools/javacserver/comp/SjavacImpl.java b/make/langtools/tools/javacserver/comp/SjavacImpl.java
deleted file mode 100644
index eb7ba30f73d..00000000000
--- a/make/langtools/tools/javacserver/comp/SjavacImpl.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package javacserver.comp;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.stream.Stream;
-
-import com.sun.tools.javac.Main;
-
-import javacserver.Log;
-import javacserver.Result;
-import javacserver.Util;
-import javacserver.options.Option;
-import javacserver.server.Sjavac;
-
-/**
- * The sjavac implementation that interacts with javac and performs the actual
- * compilation.
- *
- * This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
- */
-public class SjavacImpl implements Sjavac {
-
- @Override
- @SuppressWarnings("deprecated")
- public Result compile(String[] args) {
- // Direct logging to our byte array stream.
- StringWriter strWriter = new StringWriter();
- PrintWriter printWriter = new PrintWriter(strWriter);
-
- // Prepare arguments
- String[] passThroughArgs = Stream.of(args)
- .filter(arg -> !arg.startsWith(Option.SERVER.arg))
- .toArray(String[]::new);
- // Compile
- int exitcode = Main.compile(passThroughArgs, printWriter);
- Result result = Result.of(exitcode);
-
- // Process compiler output (which is always errors)
- printWriter.flush();
- Util.getLines(strWriter.toString()).forEach(Log::error);
-
- return result;
-
- }
-
- @Override
- public void shutdown() {
- // Nothing to clean up
- }
-}
diff --git a/make/langtools/tools/javacserver/options/ArgumentIterator.java b/make/langtools/tools/javacserver/options/ArgumentIterator.java
deleted file mode 100644
index 54c6105227a..00000000000
--- a/make/langtools/tools/javacserver/options/ArgumentIterator.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package javacserver.options;
-
-import java.util.Iterator;
-
-/**
- *
This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
- */
-public class ArgumentIterator implements Iterator {
-
- /** The underlying argument iterator */
- private Iterator iter;
-
- /** Extra state used to implement peek and current */
- private String current;
- private String buffered;
-
- public ArgumentIterator(Iterable iter) {
- this.iter = iter.iterator();
- }
-
- @Override
- public boolean hasNext() {
- return buffered != null || iter.hasNext();
- }
-
- @Override
- public String next() {
- fillBuffer();
- current = buffered;
- buffered = null;
- return current;
- }
-
- /**
- * @return the last element returned by next() (or {@code null} if next has
- * never been invoked on this iterator).
- */
- public String current() {
- return current;
- }
-
- /** Can't remove current element, since we may have buffered it. */
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * @return Returns the next element without advancing the iterator
- */
- public String peek() {
- fillBuffer();
- return buffered;
- }
-
- private void fillBuffer() {
- if (buffered == null && iter.hasNext())
- buffered = iter.next();
- }
-
-}
diff --git a/make/langtools/tools/javacserver/options/CommandLine.java b/make/langtools/tools/javacserver/options/CommandLine.java
deleted file mode 100644
index 017d32a0d7c..00000000000
--- a/make/langtools/tools/javacserver/options/CommandLine.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package javacserver.options;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Various utility methods for processing Java tool command line arguments.
- *
- * This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
- */
-public class CommandLine {
- /**
- * Process Win32-style command files for the specified command line
- * arguments and return the resulting arguments. A command file argument
- * is of the form '@file' where 'file' is the name of the file whose
- * contents are to be parsed for additional arguments. The contents of
- * the command file are parsed using StreamTokenizer and the original
- * '@file' argument replaced with the resulting tokens. Recursive command
- * files are not supported. The '@' character itself can be quoted with
- * the sequence '@@'.
- * @param args the arguments that may contain @files
- * @return the arguments, with @files expanded
- * @throws IOException if there is a problem reading any of the @files
- */
- public static List parse(List args) throws IOException {
- List newArgs = new ArrayList<>();
- appendParsedCommandArgs(newArgs, args);
- return newArgs;
- }
-
- private static void appendParsedCommandArgs(List newArgs, List args) throws IOException {
- for (String arg : args) {
- if (arg.length() > 1 && arg.charAt(0) == '@') {
- arg = arg.substring(1);
- if (arg.charAt(0) == '@') {
- newArgs.add(arg);
- } else {
- loadCmdFile(arg, newArgs);
- }
- } else {
- newArgs.add(arg);
- }
- }
- }
-
- /**
- * Process the given environment variable and appends any Win32-style
- * command files for the specified command line arguments and return
- * the resulting arguments. A command file argument
- * is of the form '@file' where 'file' is the name of the file whose
- * contents are to be parsed for additional arguments. The contents of
- * the command file are parsed using StreamTokenizer and the original
- * '@file' argument replaced with the resulting tokens. Recursive command
- * files are not supported. The '@' character itself can be quoted with
- * the sequence '@@'.
- * @param envVariable the env variable to process
- * @param args the arguments that may contain @files
- * @return the arguments, with environment variable's content and expansion of @files
- * @throws IOException if there is a problem reading any of the @files
- * @throws UnmatchedQuote
- */
- public static List parse(String envVariable, List args)
- throws IOException, UnmatchedQuote {
-
- List inArgs = new ArrayList<>();
- appendParsedEnvVariables(inArgs, envVariable);
- inArgs.addAll(args);
- List newArgs = new ArrayList<>();
- appendParsedCommandArgs(newArgs, inArgs);
- return newArgs;
- }
-
- private static void loadCmdFile(String name, List args) throws IOException {
- try (Reader r = Files.newBufferedReader(Paths.get(name), Charset.defaultCharset())) {
- Tokenizer t = new Tokenizer(r);
- String s;
- while ((s = t.nextToken()) != null) {
- args.add(s);
- }
- }
- }
-
- public static class Tokenizer {
- private final Reader in;
- private int ch;
-
- public Tokenizer(Reader in) throws IOException {
- this.in = in;
- ch = in.read();
- }
-
- public String nextToken() throws IOException {
- skipWhite();
- if (ch == -1) {
- return null;
- }
-
- StringBuilder sb = new StringBuilder();
- char quoteChar = 0;
-
- while (ch != -1) {
- switch (ch) {
- case ' ':
- case '\t':
- case '\f':
- if (quoteChar == 0) {
- return sb.toString();
- }
- sb.append((char) ch);
- break;
-
- case '\n':
- case '\r':
- return sb.toString();
-
- case '\'':
- case '"':
- if (quoteChar == 0) {
- quoteChar = (char) ch;
- } else if (quoteChar == ch) {
- quoteChar = 0;
- } else {
- sb.append((char) ch);
- }
- break;
-
- case '\\':
- if (quoteChar != 0) {
- ch = in.read();
- switch (ch) {
- case '\n':
- case '\r':
- while (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f') {
- ch = in.read();
- }
- continue;
-
- case 'n':
- ch = '\n';
- break;
- case 'r':
- ch = '\r';
- break;
- case 't':
- ch = '\t';
- break;
- case 'f':
- ch = '\f';
- break;
- }
- }
- sb.append((char) ch);
- break;
-
- default:
- sb.append((char) ch);
- }
-
- ch = in.read();
- }
-
- return sb.toString();
- }
-
- void skipWhite() throws IOException {
- while (ch != -1) {
- switch (ch) {
- case ' ':
- case '\t':
- case '\n':
- case '\r':
- case '\f':
- break;
-
- case '#':
- ch = in.read();
- while (ch != '\n' && ch != '\r' && ch != -1) {
- ch = in.read();
- }
- break;
-
- default:
- return;
- }
-
- ch = in.read();
- }
- }
- }
-
- @SuppressWarnings("fallthrough")
- private static void appendParsedEnvVariables(List newArgs, String envVariable)
- throws UnmatchedQuote {
-
- if (envVariable == null) {
- return;
- }
- String in = System.getenv(envVariable);
- if (in == null || in.trim().isEmpty()) {
- return;
- }
-
- final char NUL = (char)0;
- final int len = in.length();
-
- int pos = 0;
- StringBuilder sb = new StringBuilder();
- char quote = NUL;
- char ch;
-
- loop:
- while (pos < len) {
- ch = in.charAt(pos);
- switch (ch) {
- case '\"': case '\'':
- if (quote == NUL) {
- quote = ch;
- } else if (quote == ch) {
- quote = NUL;
- } else {
- sb.append(ch);
- }
- pos++;
- break;
- case '\f': case '\n': case '\r': case '\t': case ' ':
- if (quote == NUL) {
- newArgs.add(sb.toString());
- sb.setLength(0);
- while (ch == '\f' || ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ') {
- pos++;
- if (pos >= len) {
- break loop;
- }
- ch = in.charAt(pos);
- }
- break;
- }
- // fall through
- default:
- sb.append(ch);
- pos++;
- }
- }
- if (sb.length() != 0) {
- newArgs.add(sb.toString());
- }
- if (quote != NUL) {
- throw new UnmatchedQuote(envVariable);
- }
- }
-
- public static class UnmatchedQuote extends Exception {
- private static final long serialVersionUID = 0;
-
- public final String variableName;
-
- UnmatchedQuote(String variable) {
- this.variableName = variable;
- }
- }
-}
diff --git a/make/langtools/tools/javacserver/options/Option.java b/make/langtools/tools/javacserver/options/Option.java
deleted file mode 100644
index 2856c65627b..00000000000
--- a/make/langtools/tools/javacserver/options/Option.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package javacserver.options;
-
-/**
- * Sjavac options can be classified as:
- *
- * (1) relevant only for sjavac, such as --server
- * (2) relevant for sjavac and javac, such as -d, or
- * (3) relevant only for javac, such as -g.
- *
- * This enum represents all options from (1) and (2). Note that instances of
- * this enum only entail static information about the option. For storage of
- * option values, refer to Options.
- *
- * This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
- */
-public enum Option {
- SERVER("--server:", "Specify server configuration file of running server") {
- @Override
- protected void processMatching(ArgumentIterator iter, Options.ArgDecoderOptionHelper helper) {
- helper.serverConf(iter.current().substring(arg.length()));
- }
- },
- STARTSERVER("--startserver:", "Start server and use the given configuration file") {
- @Override
- protected void processMatching(ArgumentIterator iter, Options.ArgDecoderOptionHelper helper) {
- helper.startServerConf(iter.current().substring(arg.length()));
- }
- };
-
-
- public final String arg;
-
- final String description;
-
- private Option(String arg, String description) {
- this.arg = arg;
- this.description = description;
- }
-
- // Future cleanup: Change the "=" syntax to ":" syntax to be consistent and
- // to follow the javac-option style.
-
- public boolean hasOption() {
- return arg.endsWith(":") || arg.endsWith("=");
- }
-
-
- /**
- * Process current argument of argIter.
- *
- * It's final, since the option customization is typically done in
- * processMatching.
- *
- * @param argIter Iterator to read current and succeeding arguments from.
- * @param helper The helper to report back to.
- * @return true iff the argument was processed by this option.
- */
- public final boolean processCurrent(ArgumentIterator argIter,
- Options.ArgDecoderOptionHelper helper) {
- String fullArg = argIter.current(); // "-tr" or "-log=level"
- if (hasOption() ? fullArg.startsWith(arg) : fullArg.equals(arg)) {
- processMatching(argIter, helper);
- return true;
- }
- // Did not match
- return false;
- }
-
- /** Called by process if the current argument matches this option. */
- protected abstract void processMatching(ArgumentIterator argIter,
- Options.ArgDecoderOptionHelper helper);
-}
diff --git a/make/langtools/tools/javacserver/options/Options.java b/make/langtools/tools/javacserver/options/Options.java
deleted file mode 100644
index 507e7134fdd..00000000000
--- a/make/langtools/tools/javacserver/options/Options.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package javacserver.options;
-
-import java.util.List;
-
-/**
- * Instances of this class represent values for sjavac command line options.
- *
- *
This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
- */
-public class Options {
- private String logLevel = "info";
-
- private boolean startServer = false;
-
- // Server configuration string
- private String serverConf;
-
- /** Get the log level. */
- public String getLogLevel() {
- return logLevel;
- }
-
- /** Return true iff a new server should be started */
- public boolean startServerFlag() {
- return startServer;
- }
-
- /** Return the server configuration string. */
- public String getServerConf() {
- return serverConf;
- }
-
- /**
- * Parses the given argument array and returns a corresponding Options
- * instance.
- */
- public static Options parseArgs(String... args) {
- Options options = new Options();
- options.new ArgDecoderOptionHelper().traverse(args);
- return options;
- }
-
- // OptionHelper that records the traversed options in this Options instance.
- public class ArgDecoderOptionHelper {
- public void reportError(String msg) {
- throw new IllegalArgumentException(msg);
- }
-
- public void serverConf(String conf) {
- if (serverConf != null)
- reportError("Can not specify more than one server configuration.");
- else
- serverConf = conf;
- }
-
- public void startServerConf(String conf) {
- if (serverConf != null)
- reportError("Can not specify more than one server configuration.");
- else {
- startServer = true;
- serverConf = conf;
- }
- }
-
- /**
- * Traverses an array of arguments and performs the appropriate callbacks.
- *
- * @param args the arguments to traverse.
- */
- void traverse(String[] args) {
- Iterable allArgs;
- try {
- allArgs = CommandLine.parse(List.of(args)); // Detect @file and load it as a command line.
- } catch (java.io.IOException e) {
- throw new IllegalArgumentException("Problem reading @"+e.getMessage());
- }
- ArgumentIterator argIter = new ArgumentIterator(allArgs);
-
- nextArg:
- while (argIter.hasNext()) {
-
- String arg = argIter.next();
-
- if (arg.startsWith("-")) {
- for (Option opt : Option.values()) {
- if (opt.processCurrent(argIter, this))
- continue nextArg;
- }
- }
- }
- }
- }
-}
diff --git a/make/langtools/tools/javacserver/comp/PooledSjavac.java b/make/langtools/tools/javacserver/server/CompilerThreadPool.java
similarity index 60%
rename from make/langtools/tools/javacserver/comp/PooledSjavac.java
rename to make/langtools/tools/javacserver/server/CompilerThreadPool.java
index 3647f17cc10..3f3dea52c84 100644
--- a/make/langtools/tools/javacserver/comp/PooledSjavac.java
+++ b/make/langtools/tools/javacserver/server/CompilerThreadPool.java
@@ -23,54 +23,38 @@
* questions.
*/
-package javacserver.comp;
+package javacserver.server;
-import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
-
-import javacserver.Log;
-import javacserver.Result;
-import javacserver.server.Sjavac;
+import javacserver.util.Log;
/**
- * An sjavac implementation that limits the number of concurrent calls by
- * wrapping invocations in Callables and delegating them to a FixedThreadPool.
- *
- * This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
+ * Use a fixed thread pool to limit the amount of concurrent javac compilation
+ * that can happen.
*/
-public class PooledSjavac implements Sjavac {
+public class CompilerThreadPool {
+ private static final int POOLSIZE = Runtime.getRuntime().availableProcessors();
- final Sjavac delegate;
- final ExecutorService pool;
+ private final ExecutorService pool;
- public PooledSjavac(Sjavac delegate, int poolsize) {
- Objects.requireNonNull(delegate);
- this.delegate = delegate;
- pool = Executors.newFixedThreadPool(poolsize);
+ public CompilerThreadPool() {
+ this.pool = Executors.newFixedThreadPool(POOLSIZE);
}
- @Override
- public Result compile(String[] args) {
+ public int dispatchCompilation(String[] args) {
Log log = Log.get();
try {
- return pool.submit(() -> {
- Log.setLogForCurrentThread(log);
- return delegate.compile(args);
- }).get();
+ return pool.submit(() -> Server.runCompiler(log, args)).get();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Error during compile", e);
}
}
- @Override
public void shutdown() {
- Log.debug("Shutting down PooledSjavac");
+ Log.debug("Shutting down javacserver thread pool");
pool.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
@@ -78,16 +62,17 @@ public void shutdown() {
pool.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
- Log.error("ThreadPool did not terminate");
+ Log.error("Thread pool did not terminate");
}
} catch (InterruptedException ie) {
- // (Re-)Cancel if current thread also interrupted
- pool.shutdownNow();
- // Preserve interrupt status
- Thread.currentThread().interrupt();
+ // (Re-)Cancel if current thread also interrupted
+ pool.shutdownNow();
+ // Preserve interrupt status
+ Thread.currentThread().interrupt();
}
-
- delegate.shutdown();
}
+ public int poolSize() {
+ return POOLSIZE;
+ }
}
diff --git a/make/langtools/tools/javacserver/server/IdleResetSjavac.java b/make/langtools/tools/javacserver/server/IdleMonitor.java
similarity index 59%
rename from make/langtools/tools/javacserver/server/IdleResetSjavac.java
rename to make/langtools/tools/javacserver/server/IdleMonitor.java
index be4be86c622..939a97beebb 100644
--- a/make/langtools/tools/javacserver/server/IdleResetSjavac.java
+++ b/make/langtools/tools/javacserver/server/IdleMonitor.java
@@ -27,53 +27,30 @@
import java.util.Timer;
import java.util.TimerTask;
-
-import javacserver.Log;
-import javacserver.Result;
+import java.util.function.Consumer;
+import javacserver.util.RunnableTimerTask;
/**
- * An sjavac implementation that keeps track of idleness and shuts down the
- * given Terminable upon idleness timeout.
- *
- * An idleness timeout kicks in {@code idleTimeout} milliseconds after the last
- * request is completed.
- *
- *
This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
+ * Monitors the javacserver daemon, shutting it down if it recieves no new requests
+ * after a certain amount of time.
*/
-public class IdleResetSjavac implements Sjavac {
+public class IdleMonitor {
+ // Accept 120 seconds of inactivity before quitting.
+ private static final int KEEPALIVE = 120;
- private final Sjavac delegate;
- private final Terminable toShutdown;
+ private final Consumer onShutdown;
private final Timer idlenessTimer = new Timer();
- private final long idleTimeout;
private int outstandingCalls = 0;
// Class invariant: idlenessTimerTask != null <-> idlenessTimerTask is scheduled
private TimerTask idlenessTimerTask;
- public IdleResetSjavac(Sjavac delegate,
- Terminable toShutdown,
- long idleTimeout) {
- this.delegate = delegate;
- this.toShutdown = toShutdown;
- this.idleTimeout = idleTimeout;
+ public IdleMonitor(Consumer onShutdown) {
+ this.onShutdown = onShutdown;
scheduleTimeout();
}
- @Override
- public Result compile(String[] args) {
- startCall();
- try {
- return delegate.compile(args);
- } finally {
- endCall();
- }
- }
-
- private synchronized void startCall() {
+ public synchronized void startCall() {
// Was there no outstanding calls before this call?
if (++outstandingCalls == 1) {
// Then the timer task must have been scheduled
@@ -85,7 +62,7 @@ private synchronized void startCall() {
}
}
- private synchronized void endCall() {
+ public synchronized void endCall() {
if (--outstandingCalls == 0) {
// No more outstanding calls. Schedule timeout.
scheduleTimeout();
@@ -95,19 +72,14 @@ private synchronized void endCall() {
private void scheduleTimeout() {
if (idlenessTimerTask != null)
throw new IllegalStateException("Idle timeout already scheduled");
- idlenessTimerTask = new TimerTask() {
- public void run() {
- Log.setLogForCurrentThread(ServerMain.getErrorLog());
- toShutdown.shutdown("Server has been idle for " + (idleTimeout / 1000) + " seconds.");
- }
- };
- idlenessTimer.schedule(idlenessTimerTask, idleTimeout);
+ idlenessTimerTask = new RunnableTimerTask(() -> {
+ Server.restoreServerErrorLog();
+ onShutdown.accept("Server has been idle for " + KEEPALIVE + " seconds.");
+ });
+ idlenessTimer.schedule(idlenessTimerTask, KEEPALIVE * 1000);
}
- @Override
public void shutdown() {
idlenessTimer.cancel();
- delegate.shutdown();
}
-
}
diff --git a/make/langtools/tools/javacserver/server/PortFileMonitor.java b/make/langtools/tools/javacserver/server/PortFileMonitor.java
index 1b8828c694b..41a357b6db5 100644
--- a/make/langtools/tools/javacserver/server/PortFileMonitor.java
+++ b/make/langtools/tools/javacserver/server/PortFileMonitor.java
@@ -27,68 +27,61 @@
import java.io.IOException;
import java.util.Timer;
-import java.util.TimerTask;
-
-import javacserver.Log;
+import java.util.function.Consumer;
+import javacserver.shared.PortFile;
+import javacserver.util.Log;
+import javacserver.util.RunnableTimerTask;
/**
- * Monitors the presence of a port file and shuts down the given SjavacServer
+ * Monitors the presence of a port file and shuts down the server
* whenever the port file is deleted or invalidated.
*
* TODO: JDK-8046882
- *
- * This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
*/
public class PortFileMonitor {
-
// Check if the portfile is gone, every 5 seconds.
private static final int CHECK_PORTFILE_INTERVAL = 5000;
private final Timer timer = new Timer();
private final PortFile portFile;
- private final SjavacServer server;
+ private final Consumer onShutdown;
public PortFileMonitor(PortFile portFile,
- SjavacServer server) {
+ Consumer onShutdown) {
this.portFile = portFile;
- this.server = server;
+ this.onShutdown = onShutdown;
}
public void start() {
Log log = Log.get();
- TimerTask shutdownCheck = new TimerTask() {
- public void run() {
- Log.setLogForCurrentThread(log);
- Log.debug("Checking port file status...");
- try {
- if (!portFile.exists()) {
- // Time to quit because the portfile was deleted by another
- // process, probably by the makefile that is done building.
- server.shutdown("Quitting because portfile was deleted!");
- } else if (portFile.markedForStop()) {
- // Time to quit because another process touched the file
- // server.port.stop to signal that the server should stop.
- // This is necessary on some operating systems that lock
- // the port file hard!
- server.shutdown("Quitting because a portfile.stop file was found!");
- } else if (!portFile.stillMyValues()) {
- // Time to quit because another build has started.
- server.shutdown("Quitting because portfile is now owned by another javac server!");
- }
- } catch (IOException e) {
- Log.error("IOException caught in PortFileMonitor.");
- Log.debug(e);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- Log.error(e);
- }
- }
- };
+ timer.schedule(new RunnableTimerTask(() -> checkPortFile(log)), 0, CHECK_PORTFILE_INTERVAL);
+ }
- timer.schedule(shutdownCheck, 0, CHECK_PORTFILE_INTERVAL);
+ private void checkPortFile(Log log) {
+ Log.setLogForCurrentThread(log);
+ Log.debug("Checking port file status...");
+ try {
+ if (!portFile.exists()) {
+ // Time to quit because the portfile was deleted by another
+ // process, probably by the makefile that is done building.
+ onShutdown.accept("Quitting because portfile was deleted!");
+ } else if (portFile.markedForStop()) {
+ // Time to quit because another process touched the file
+ // server.port.stop to signal that the server should stop.
+ // This is necessary on some operating systems that lock
+ // the port file hard!
+ onShutdown.accept("Quitting because a portfile.stop file was found!");
+ } else if (!portFile.stillMyValues()) {
+ // Time to quit because another build has started.
+ onShutdown.accept("Quitting because portfile is now owned by another javac server!");
+ }
+ } catch (IOException e) {
+ Log.error("IOException caught in PortFileMonitor.");
+ Log.debug(e);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ Log.error(e);
+ }
}
public void shutdown() {
diff --git a/make/langtools/tools/javacserver/server/RequestHandler.java b/make/langtools/tools/javacserver/server/RequestHandler.java
deleted file mode 100644
index b2d04e4606b..00000000000
--- a/make/langtools/tools/javacserver/server/RequestHandler.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package javacserver.server;
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.net.Socket;
-import java.nio.file.Path;
-
-import javacserver.Log;
-import javacserver.Result;
-import javacserver.Util;
-
-import static javacserver.server.SjavacServer.LINE_TYPE_RC;
-
-
-/**
- * A RequestHandler handles requests performed over a socket. Specifically it
- * - Reads the command string specifying which method is to be invoked
- * - Reads the appropriate arguments
- * - Delegates the actual invocation to the given sjavac implementation
- * - Writes the result back to the socket output stream
- *
- * None of the work performed by this class is really bound by the CPU. It
- * should be completely fine to have a large number of RequestHandlers active.
- * To limit the number of concurrent compilations, use PooledSjavac.
- *
- * This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
- */
-public class RequestHandler extends Thread {
-
- private final Socket socket;
- private final Sjavac sjavac;
-
- public RequestHandler(Socket socket, Sjavac sjavac) {
- this.socket = socket;
- this.sjavac = sjavac;
- }
-
- @Override
- public void run() {
-
- try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
-
- // Set up logging for this thread. Stream back logging messages to
- // client on the format format "level:msg".
- Log.setLogForCurrentThread(new Log(out, out) {
- @Override
- protected boolean isLevelLogged(Level l) {
- // Make sure it is up to the client to decide whether or
- // not this message should be displayed.
- return true;
- }
-
- @Override
- protected void printLogMsg(Level msgLevel, String msg) {
- // Follow sjavac server/client protocol: Send one line
- // at a time and prefix with message with "level:".
- Util.getLines(msg)
- .map(line -> msgLevel + ":" + line)
- .forEach(line -> super.printLogMsg(msgLevel, line));
- }
- });
-
- // Read argument array
- int n = Integer.parseInt(in.readLine());
- String[] args = new String[n];
- for (int i = 0; i < n; i++) {
- args[i] = in.readLine();
- }
-
- // If there has been any internal errors, notify client
- checkInternalErrorLog();
-
- // Perform compilation
- Result rc = sjavac.compile(args);
-
- // Send return code back to client
- out.println(LINE_TYPE_RC + ":" + rc.name());
-
- // Check for internal errors again.
- checkInternalErrorLog();
- } catch (Exception ex) {
- // Not much to be done at this point. The client side request
- // code will most likely throw an IOException and the
- // compilation will fail.
- Log.error(ex);
- } finally {
- Log.setLogForCurrentThread(null);
- }
- }
-
- private void checkInternalErrorLog() {
- Path errorLog = ServerMain.getErrorLog().getLogDestination();
- if (errorLog != null) {
- Log.error("Server has encountered an internal error. See " + errorLog.toAbsolutePath()
- + " for details.");
- }
- }
-}
diff --git a/make/langtools/tools/javacserver/server/Server.java b/make/langtools/tools/javacserver/server/Server.java
new file mode 100644
index 00000000000..b213c992667
--- /dev/null
+++ b/make/langtools/tools/javacserver/server/Server.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javacserver.server;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.spi.ToolProvider;
+import javacserver.shared.PortFile;
+import javacserver.shared.Protocol;
+import javacserver.shared.Result;
+import javacserver.util.LazyInitFileLog;
+import javacserver.util.Log;
+import javacserver.util.LoggingOutputStream;
+import javacserver.util.Util;
+
+/**
+ * Start a new server main thread, that will listen to incoming connection requests from the client,
+ * and dispatch these on to worker threads in a thread pool, running javac.
+ */
+public class Server {
+ private ServerSocket serverSocket;
+ private PortFile portFile;
+ private PortFileMonitor portFileMonitor;
+ private IdleMonitor idleMonitor;
+ private CompilerThreadPool compilerThreadPool;
+
+ // Set to false break accept loop
+ final AtomicBoolean keepAcceptingRequests = new AtomicBoolean();
+
+ // For logging server internal (non request specific) errors.
+ private static LazyInitFileLog errorLog;
+
+ public static void main(String... args) {
+ initLogging();
+
+ try {
+ PortFile portFile = getPortFileFromArguments(args);
+ if (portFile == null) {
+ System.exit(Result.CMDERR.exitCode);
+ return;
+ }
+
+ Server server = new Server(portFile);
+ if (!server.start()) {
+ System.exit(Result.ERROR.exitCode);
+ } else {
+ System.exit(Result.OK.exitCode);
+ }
+ } catch (IOException | InterruptedException ex) {
+ ex.printStackTrace();
+ System.exit(Result.ERROR.exitCode);
+ }
+ }
+
+ private static void initLogging() {
+ // Under normal operation, all logging messages generated server-side
+ // are due to compilation requests. These logging messages should
+ // be relayed back to the requesting client rather than written to the
+ // server log. The only messages that should be written to the server
+ // log (in production mode) should be errors,
+ errorLog = new LazyInitFileLog("server.log");
+ Log.setLogForCurrentThread(errorLog);
+ Log.setLogLevel(Log.Level.ERROR); // should be set to ERROR.
+
+ // Make sure no exceptions go under the radar
+ Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
+ restoreServerErrorLog();
+ Log.error(e);
+ });
+
+ // Inevitably someone will try to print messages using System.{out,err}.
+ // Make sure this output also ends up in the log.
+ System.setOut(new PrintStream(new LoggingOutputStream(System.out, Log.Level.INFO, "[stdout] ")));
+ System.setErr(new PrintStream(new LoggingOutputStream(System.err, Log.Level.ERROR, "[stderr] ")));
+ }
+
+ private static PortFile getPortFileFromArguments(String[] args) {
+ if (args.length != 1) {
+ Log.error("javacserver daemon incorrectly called");
+ return null;
+ }
+ String portfilename = args[0];
+ PortFile portFile = new PortFile(portfilename);
+ return portFile;
+ }
+
+ public Server(PortFile portFile) throws FileNotFoundException {
+ this.portFile = portFile;
+ }
+
+ /**
+ * Start the daemon, unless another one is already running, in which it returns
+ * false and exits immediately.
+ */
+ private boolean start() throws IOException, InterruptedException {
+ // The port file is locked and the server port and cookie is written into it.
+ portFile.lock();
+ portFile.getValues();
+ if (portFile.containsPortInfo()) {
+ Log.debug("javacserver daemon not started because portfile exists!");
+ portFile.unlock();
+ return false;
+ }
+
+ serverSocket = new ServerSocket();
+ InetAddress localhost = InetAddress.getByName(null);
+ serverSocket.bind(new InetSocketAddress(localhost, 0));
+
+ // At this point the server accepts connections, so it is now safe
+ // to publish the port / cookie information
+
+ // The secret cookie shared between server and client through the port file.
+ // Used to prevent clients from believing that they are communicating with
+ // an old server when a new server has started and reused the same port as
+ // an old server.
+ long myCookie = new Random().nextLong();
+ portFile.setValues(serverSocket.getLocalPort(), myCookie);
+ portFile.unlock();
+
+ portFileMonitor = new PortFileMonitor(portFile, this::shutdownServer);
+ portFileMonitor.start();
+ compilerThreadPool = new CompilerThreadPool();
+ idleMonitor = new IdleMonitor(this::shutdownServer);
+
+ Log.debug("javacserver daemon started. Accepting connections...");
+ Log.debug(" port: " + serverSocket.getLocalPort());
+ Log.debug(" time: " + new java.util.Date());
+ Log.debug(" poolsize: " + compilerThreadPool.poolSize());
+
+ keepAcceptingRequests.set(true);
+ do {
+ try {
+ Socket socket = serverSocket.accept();
+ // Handle each incoming request in a separate thread. This is just for socket communication,
+ // the actual compilation will be done by the threadpool.
+ Thread requestHandler = new Thread(() -> handleRequest(socket));
+ requestHandler.start();
+ } catch (SocketException se) {
+ // Caused by serverSocket.close() and indicates shutdown
+ }
+ } while (keepAcceptingRequests.get());
+
+ Log.debug("Shutting down.");
+
+ // No more connections accepted. If any client managed to connect after
+ // the accept() was interrupted but before the server socket is closed
+ // here, any attempt to read or write to the socket will result in an
+ // IOException on the client side.
+
+ // Shut down
+ idleMonitor.shutdown();
+ compilerThreadPool.shutdown();
+
+ return true;
+ }
+
+ private void handleRequest(Socket socket) {
+ try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
+ try {
+ idleMonitor.startCall();
+
+ // Set up logging for this thread. Stream back logging messages to
+ // client on the format "level:msg".
+ Log.setLogForCurrentThread(new Protocol.ProtocolLog(out));
+
+ String[] args = Protocol.readCommand(in);
+
+ // If there has been any internal errors, notify client
+ checkInternalErrorLog();
+
+ // Perform compilation. This will call runCompiler() on a
+ // thread in the thread pool
+ int exitCode = compilerThreadPool.dispatchCompilation(args);
+ Protocol.sendExitCode(out, exitCode);
+
+ // Check for internal errors again.
+ checkInternalErrorLog();
+ } finally {
+ idleMonitor.endCall();
+ }
+ } catch (Exception ex) {
+ // Not much to be done at this point. The client side request
+ // code will most likely throw an IOException and the
+ // compilation will fail.
+ Log.error(ex);
+ } finally {
+ Log.setLogForCurrentThread(null);
+ }
+ }
+
+ public static int runCompiler(Log log, String[] args) {
+ Log.setLogForCurrentThread(log);
+
+ // Direct logging to our byte array stream.
+ StringWriter strWriter = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(strWriter);
+
+ // Compile
+ Optional tool = ToolProvider.findFirst("javac");
+ if (tool.isEmpty()) {
+ Log.error("Can't find tool javac");
+ return Result.ERROR.exitCode;
+ }
+ int exitcode = tool.get().run(printWriter, printWriter, args);
+
+ // Process compiler output (which is always errors)
+ printWriter.flush();
+ Util.getLines(strWriter.toString()).forEach(Log::error);
+
+ return exitcode;
+ }
+
+ private void checkInternalErrorLog() {
+ Path errorLogPath = errorLog.getLogDestination();
+ if (errorLogPath != null) {
+ Log.error("Server has encountered an internal error. See " + errorLogPath.toAbsolutePath()
+ + " for details.");
+ }
+ }
+
+ public static void restoreServerErrorLog() {
+ Log.setLogForCurrentThread(errorLog);
+ }
+
+ public void shutdownServer(String quitMsg) {
+ if (!keepAcceptingRequests.compareAndSet(true, false)) {
+ // Already stopped, no need to shut down again
+ return;
+ }
+
+ Log.debug("Quitting: " + quitMsg);
+
+ portFileMonitor.shutdown(); // No longer any need to monitor port file
+
+ // Unpublish port before shutting down socket to minimize the number of
+ // failed connection attempts
+ try {
+ portFile.delete();
+ } catch (IOException | InterruptedException e) {
+ Log.error(e);
+ }
+ try {
+ serverSocket.close();
+ } catch (IOException e) {
+ Log.error(e);
+ }
+ }
+}
diff --git a/make/langtools/tools/javacserver/server/ServerMain.java b/make/langtools/tools/javacserver/server/ServerMain.java
deleted file mode 100644
index 1f5b51755bb..00000000000
--- a/make/langtools/tools/javacserver/server/ServerMain.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package javacserver.server;
-
-import java.io.IOException;
-import java.io.PrintStream;
-
-import javacserver.Log;
-import javacserver.Result;
-import javacserver.server.log.LazyInitFileLog;
-import javacserver.server.log.LoggingOutputStream;
-
-import static javacserver.Log.Level.ERROR;
-import static javacserver.Log.Level.INFO;
-
-/**
- * This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
- */
-public class ServerMain {
-
- // For logging server internal (non request specific) errors.
- private static LazyInitFileLog errorLog;
-
- public static int run(String[] args) {
-
- // Under normal operation, all logging messages generated server-side
- // are due to compilation requests. These logging messages should
- // be relayed back to the requesting client rather than written to the
- // server log. The only messages that should be written to the server
- // log (in production mode) should be errors,
- Log.setLogForCurrentThread(errorLog = new LazyInitFileLog("server.log"));
- Log.setLogLevel(ERROR); // should be set to ERROR.
-
- // Make sure no exceptions go under the radar
- Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
- Log.setLogForCurrentThread(errorLog);
- Log.error(e);
- });
-
- // Inevitably someone will try to print messages using System.{out,err}.
- // Make sure this output also ends up in the log.
- System.setOut(new PrintStream(new LoggingOutputStream(System.out, INFO, "[stdout] ")));
- System.setErr(new PrintStream(new LoggingOutputStream(System.err, ERROR, "[stderr] ")));
-
- // Any options other than --startserver?
- if (args.length > 1) {
- Log.error("When spawning a background server, only a single --startserver argument is allowed.");
- return Result.CMDERR.exitCode;
- }
-
- int exitCode;
- try {
- SjavacServer server = new SjavacServer(args[0]);
- exitCode = server.startServer();
- } catch (IOException | InterruptedException ex) {
- ex.printStackTrace();
- exitCode = Result.ERROR.exitCode;
- }
-
- return exitCode;
- }
-
- public static LazyInitFileLog getErrorLog() {
- return errorLog;
- }
-}
diff --git a/make/langtools/tools/javacserver/server/SjavacServer.java b/make/langtools/tools/javacserver/server/SjavacServer.java
deleted file mode 100644
index d52e274c4ac..00000000000
--- a/make/langtools/tools/javacserver/server/SjavacServer.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package javacserver.server;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import javacserver.Log;
-import javacserver.Result;
-import javacserver.Util;
-import javacserver.comp.PooledSjavac;
-import javacserver.comp.SjavacImpl;
-
-/**
- * The JavacServer class contains methods both to setup a server that responds to requests and methods to connect to this server.
- *
- *
This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
- */
-public class SjavacServer implements Terminable {
-
- // Prefix of line containing return code.
- public static final String LINE_TYPE_RC = "RC";
-
- private final String portfilename;
- private final int poolsize;
- private final int keepalive;
-
- // The secret cookie shared between server and client through the port file.
- // Used to prevent clients from believing that they are communicating with
- // an old server when a new server has started and reused the same port as
- // an old server.
- private final long myCookie;
-
- // Accumulated build time, not counting idle time, used for logging purposes
- private long totalBuildTime;
-
- // The sjavac implementation to delegate requests to
- Sjavac sjavac;
-
- private ServerSocket serverSocket;
-
- private PortFile portFile;
- private PortFileMonitor portFileMonitor;
-
- // Set to false break accept loop
- final AtomicBoolean keepAcceptingRequests = new AtomicBoolean();
-
- // For the client, all port files fetched, one per started javac server.
- // Though usually only one javac server is started by a client.
- private static Map allPortFiles;
-
- public SjavacServer(String settings) throws FileNotFoundException {
- this(Util.extractStringOption("portfile", settings),
- Util.extractIntOption("poolsize", settings, Runtime.getRuntime().availableProcessors()),
- Util.extractIntOption("keepalive", settings, 120));
- }
-
- public SjavacServer(String portfilename,
- int poolsize,
- int keepalive)
- throws FileNotFoundException {
- this.portfilename = portfilename;
- this.poolsize = poolsize;
- this.keepalive = keepalive;
- this.myCookie = new Random().nextLong();
- }
-
-
- /**
- * Acquire the port file. Synchronized since several threads inside an smart javac wrapper client acquires the same port file at the same time.
- */
- public static synchronized PortFile getPortFile(String filename) {
- if (allPortFiles == null) {
- allPortFiles = new HashMap<>();
- }
- PortFile pf = allPortFiles.get(filename);
-
- // Port file known. Does it still exist?
- if (pf != null) {
- try {
- if (!pf.exists())
- pf = null;
- } catch (IOException ioex) {
- ioex.printStackTrace();
- }
- }
-
- if (pf == null) {
- pf = new PortFile(filename);
- allPortFiles.put(filename, pf);
- }
- return pf;
- }
-
- /**
- * Get the cookie used for this server.
- */
- long getCookie() {
- return myCookie;
- }
-
- /**
- * Get the port used for this server.
- */
- int getPort() {
- return serverSocket.getLocalPort();
- }
-
- /**
- * Sum up the total build time for this javac server.
- */
- public void addBuildTime(long inc) {
- totalBuildTime += inc;
- }
-
- /**
- * Start a server using a settings string. Typically: "--startserver:portfile=/tmp/myserver,poolsize=3" and the string "portfile=/tmp/myserver,poolsize=3"
- * is sent as the settings parameter. Returns 0 on success, -1 on failure.
- */
- public int startServer() throws IOException, InterruptedException {
- long serverStart = System.currentTimeMillis();
-
- // The port file is locked and the server port and cookie is written into it.
- portFile = getPortFile(portfilename);
-
- synchronized (portFile) {
- portFile.lock();
- portFile.getValues();
- if (portFile.containsPortInfo()) {
- Log.debug("Javac server not started because portfile exists!");
- portFile.unlock();
- return Result.ERROR.exitCode;
- }
-
- // .-----------. .--------. .------.
- // socket -->| IdleReset |-->| Pooled |-->| Impl |--> javac
- // '-----------' '--------' '------'
- sjavac = new SjavacImpl();
- sjavac = new PooledSjavac(sjavac, poolsize);
- sjavac = new IdleResetSjavac(sjavac,
- this,
- keepalive * 1000);
-
- serverSocket = new ServerSocket();
- InetAddress localhost = InetAddress.getByName(null);
- serverSocket.bind(new InetSocketAddress(localhost, 0));
-
- // At this point the server accepts connections, so it is now safe
- // to publish the port / cookie information
- portFile.setValues(getPort(), getCookie());
- portFile.unlock();
- }
-
- portFileMonitor = new PortFileMonitor(portFile, this);
- portFileMonitor.start();
-
- Log.debug("Sjavac server started. Accepting connections...");
- Log.debug(" port: " + getPort());
- Log.debug(" time: " + new java.util.Date());
- Log.debug(" poolsize: " + poolsize);
-
-
- keepAcceptingRequests.set(true);
- do {
- try {
- Socket socket = serverSocket.accept();
- new RequestHandler(socket, sjavac).start();
- } catch (SocketException se) {
- // Caused by serverSocket.close() and indicates shutdown
- }
- } while (keepAcceptingRequests.get());
-
- Log.debug("Shutting down.");
-
- // No more connections accepted. If any client managed to connect after
- // the accept() was interrupted but before the server socket is closed
- // here, any attempt to read or write to the socket will result in an
- // IOException on the client side.
-
- long realTime = System.currentTimeMillis() - serverStart;
- Log.debug("Total wall clock time " + realTime + "ms build time " + totalBuildTime + "ms");
-
- // Shut down
- sjavac.shutdown();
-
- return Result.OK.exitCode;
- }
-
- @Override
- public void shutdown(String quitMsg) {
- if (!keepAcceptingRequests.compareAndSet(true, false)) {
- // Already stopped, no need to shut down again
- return;
- }
-
- Log.debug("Quitting: " + quitMsg);
-
- portFileMonitor.shutdown(); // No longer any need to monitor port file
-
- // Unpublish port before shutting down socket to minimize the number of
- // failed connection attempts
- try {
- portFile.delete();
- } catch (IOException | InterruptedException e) {
- Log.error(e);
- }
- try {
- serverSocket.close();
- } catch (IOException e) {
- Log.error(e);
- }
- }
-}
diff --git a/make/langtools/tools/javacserver/server/PortFile.java b/make/langtools/tools/javacserver/shared/PortFile.java
similarity index 94%
rename from make/langtools/tools/javacserver/server/PortFile.java
rename to make/langtools/tools/javacserver/shared/PortFile.java
index 3874a4c1ee2..2e4283a22b3 100644
--- a/make/langtools/tools/javacserver/server/PortFile.java
+++ b/make/langtools/tools/javacserver/shared/PortFile.java
@@ -23,7 +23,7 @@
* questions.
*/
-package javacserver.server;
+package javacserver.shared;
import java.io.File;
import java.io.FileNotFoundException;
@@ -34,23 +34,15 @@
import java.nio.channels.FileLock;
import java.nio.channels.FileLockInterruptionException;
import java.util.concurrent.Semaphore;
-
-import javacserver.Log;
-import javacserver.client.PortFileInaccessibleException;
+import javacserver.util.Log;
/**
* The PortFile class mediates access to a short binary file containing the tcp/ip port (for the localhost)
* and a cookie necessary for the server answering on that port. The file can be locked using file system
* primitives to avoid race conditions when several javac clients are started at the same. Note that file
- * system locking is not always supported on a all operating systems and/or file systems.
- *
- * This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
+ * system locking is not always supported on all operating systems and/or file systems.
*/
public class PortFile {
-
// Port file format:
// byte ordering: high byte first = big endian
// Magic nr, 4 byte int, first in file.
@@ -225,6 +217,19 @@ public void unlock() throws IOException {
lockSem.release();
}
+ public boolean hasValidValues() throws IOException, InterruptedException {
+ if (exists()) {
+ lock();
+ getValues();
+ unlock();
+
+ if (containsPortInfo()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Wait for the port file to contain values that look valid.
*/
@@ -277,7 +282,7 @@ public boolean stillMyValues() throws IOException, FileNotFoundException, Interr
continue;
}
catch (ClosedChannelException e) {
- // The channel has been closed since sjavac is exiting.
+ // The channel has been closed since the server is exiting.
return false;
}
}
diff --git a/make/langtools/tools/javacserver/client/PortFileInaccessibleException.java b/make/langtools/tools/javacserver/shared/PortFileInaccessibleException.java
similarity index 98%
rename from make/langtools/tools/javacserver/client/PortFileInaccessibleException.java
rename to make/langtools/tools/javacserver/shared/PortFileInaccessibleException.java
index c9db8dfc44a..b306893c20d 100644
--- a/make/langtools/tools/javacserver/client/PortFileInaccessibleException.java
+++ b/make/langtools/tools/javacserver/shared/PortFileInaccessibleException.java
@@ -23,7 +23,7 @@
* questions.
*/
-package javacserver.client;
+package javacserver.shared;
import java.io.IOException;
diff --git a/make/langtools/tools/javacserver/shared/Protocol.java b/make/langtools/tools/javacserver/shared/Protocol.java
new file mode 100644
index 00000000000..f4f0f23cdc6
--- /dev/null
+++ b/make/langtools/tools/javacserver/shared/Protocol.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javacserver.shared;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import javacserver.util.Log;
+import javacserver.util.Util;
+
+/**
+ * Implementation of the wire protocol used by the javacserver client and daemon to communicate.
+ * Basically, the client sends the argument to javac, one line per string. The server responds
+ * with log lines (if there is any output), and the exit code from javac.
+ */
+public class Protocol {
+ // Prefix of line containing return code.
+ private static final String LINE_TYPE_RC = "RC";
+
+ public static void sendCommand(PrintWriter out, String[] args) throws IOException {
+ // Send args array to server
+ out.println(args.length);
+ for (String arg : args)
+ out.println(arg);
+ out.flush();
+ }
+
+ public static String[] readCommand(BufferedReader in) throws IOException {
+ // Read argument array
+ int n = Integer.parseInt(in.readLine());
+ String[] args = new String[n];
+ for (int i = 0; i < n; i++) {
+ args[i] = in.readLine();
+ }
+ return args;
+ }
+
+ public static void sendExitCode(PrintWriter out, int exitCode) {
+ // Send return code back to client
+ out.println(LINE_TYPE_RC + ":" + exitCode);
+ }
+
+ public static int readResponse(BufferedReader in) throws IOException {
+ // Read server response line by line
+ String line;
+ while (null != (line = in.readLine())) {
+ Line parsedLine = new Line(line);
+
+ try {
+ String content = parsedLine.getContent();
+ if (Log.isDebugging()) {
+ // Distinguish server generated output if debugging.
+ content = "[javacserver] " + content;
+ }
+ Log.log(Log.Level.valueOf(parsedLine.getType()), content);
+ continue;
+ } catch (IllegalArgumentException e) {
+ // Parsing of 'type' as log level failed.
+ }
+
+ if (parsedLine.isExitCode()) {
+ return parsedLine.getExitCode();
+ }
+ }
+ // No exit code was found.
+ return Result.ERROR.exitCode;
+ }
+
+ public static class Line {
+ private final String type;
+
+ public String getType() {
+ return type;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public boolean isExitCode() {
+ return type.equals(LINE_TYPE_RC);
+ }
+
+ public int getExitCode() {
+ return Integer.parseInt(content);
+ }
+
+ private final String content;
+
+ public Line(String line) {
+ if (!line.contains(":")) {
+ throw new AssertionError("Could not parse protocol line: >>\"" + line + "\"<<");
+ }
+ String[] typeAndContent = line.split(":", 2);
+ type = typeAndContent[0];
+ content = typeAndContent[1];
+ }
+ }
+
+ public static class ProtocolLog extends Log {
+ public ProtocolLog(PrintWriter out) {
+ super(out, out);
+ }
+
+ @Override
+ protected boolean isLevelLogged(Level l) {
+ // Make sure it is up to the client to decide whether or
+ // not this message should be displayed.
+ return true;
+ }
+
+ @Override
+ protected void printLogMsg(Level msgLevel, String msg) {
+ // Follow the server/client protocol: Send one line
+ // at a time and prefix with message with "level:".
+ Util.getLines(msg)
+ .map(line -> msgLevel + ":" + line)
+ .forEach(line -> super.printLogMsg(msgLevel, line));
+ }
+ }
+}
diff --git a/make/langtools/tools/javacserver/server/Terminable.java b/make/langtools/tools/javacserver/shared/Result.java
similarity index 74%
rename from make/langtools/tools/javacserver/server/Terminable.java
rename to make/langtools/tools/javacserver/shared/Result.java
index 5c598ddc420..f15c3dd3765 100644
--- a/make/langtools/tools/javacserver/server/Terminable.java
+++ b/make/langtools/tools/javacserver/shared/Result.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,14 +23,19 @@
* questions.
*/
-package javacserver.server;
+package javacserver.shared;
/**
- *
This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
+ * Result codes.
*/
-public interface Terminable {
- void shutdown(String quitMsg);
+public enum Result {
+ OK(0), // Compilation completed with no errors.
+ ERROR(1), // Completed but reported errors.
+ CMDERR(2); // Bad command-line arguments
+
+ public final int exitCode;
+
+ Result(int exitCode) {
+ this.exitCode = exitCode;
+ }
}
diff --git a/make/langtools/tools/javacserver/AutoFlushWriter.java b/make/langtools/tools/javacserver/util/AutoFlushWriter.java
similarity index 98%
rename from make/langtools/tools/javacserver/AutoFlushWriter.java
rename to make/langtools/tools/javacserver/util/AutoFlushWriter.java
index 92d64399690..1c06d558a8c 100644
--- a/make/langtools/tools/javacserver/AutoFlushWriter.java
+++ b/make/langtools/tools/javacserver/util/AutoFlushWriter.java
@@ -23,14 +23,13 @@
* questions.
*/
-package javacserver;
+package javacserver.util;
import java.io.FilterWriter;
import java.io.IOException;
import java.io.Writer;
public class AutoFlushWriter extends FilterWriter {
-
public AutoFlushWriter(Writer out) {
super(out);
}
diff --git a/make/langtools/tools/javacserver/server/log/LazyInitFileLog.java b/make/langtools/tools/javacserver/util/LazyInitFileLog.java
similarity index 97%
rename from make/langtools/tools/javacserver/server/log/LazyInitFileLog.java
rename to make/langtools/tools/javacserver/util/LazyInitFileLog.java
index 5471b8f0196..4de83b63176 100644
--- a/make/langtools/tools/javacserver/server/log/LazyInitFileLog.java
+++ b/make/langtools/tools/javacserver/util/LazyInitFileLog.java
@@ -23,7 +23,7 @@
* questions.
*/
-package javacserver.server.log;
+package javacserver.util;
import java.io.FileWriter;
import java.io.IOException;
@@ -32,10 +32,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
-import javacserver.Log;
-
public class LazyInitFileLog extends Log {
-
String baseFilename;
Path destination = null;
diff --git a/make/langtools/tools/javacserver/Log.java b/make/langtools/tools/javacserver/util/Log.java
similarity index 78%
rename from make/langtools/tools/javacserver/Log.java
rename to make/langtools/tools/javacserver/util/Log.java
index 49b62876083..0c9d51e3c86 100644
--- a/make/langtools/tools/javacserver/Log.java
+++ b/make/langtools/tools/javacserver/util/Log.java
@@ -23,17 +23,16 @@
* questions.
*/
-package javacserver;
+package javacserver.util;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
-import java.util.Locale;
/**
- * Utility class only for sjavac logging.
+ * Utility class only for javacserver logging.
*
- * Logging in sjavac has special requirements when running in server/client
+ * Logging in javacserver has special requirements when running in server/client
* mode. Most of the log messages is generated server-side, but the server
* is typically spawned by the client in the background, so the user usually
* does not see the server stdout/stderr. For this reason log messages needs
@@ -42,16 +41,9 @@
* instance so that each connected client can have its own instance that
* relays messages back to the requesting client.
*
- * On the client-side (or when running sjavac without server-mode) there will
- * typically just be one Log instance.
- *
- *
This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
+ * On the client-side there will typically just be one Log instance.
*/
public class Log {
-
public enum Level {
ERROR,
WARN,
@@ -61,7 +53,7 @@ public enum Level {
}
private static Log stdOutErr = new Log(new PrintWriter(System.out), new PrintWriter(System.err));
- private static ThreadLocal loggers = new ThreadLocal<>();
+ private static ThreadLocal logger = new ThreadLocal<>();
protected PrintWriter err; // Used for error and warning messages
protected PrintWriter out; // Used for other messages
@@ -73,31 +65,19 @@ public Log(Writer out, Writer err) {
}
public static void setLogForCurrentThread(Log log) {
- loggers.set(log);
- }
-
- public static void setLogLevel(String l) {
- setLogLevel(Level.valueOf(l.toUpperCase(Locale.US)));
+ logger.set(log);
}
public static void setLogLevel(Level l) {
get().level = l;
}
- public static void trace(String msg) {
- log(Level.TRACE, msg);
- }
-
public static void debug(String msg) {
log(Level.DEBUG, msg);
}
- public static void info(String msg) {
- log(Level.INFO, msg);
- }
-
- public static void warn(String msg) {
- log(Level.WARN, msg);
+ public static void debug(Throwable t) {
+ log(Level.DEBUG, t);
}
public static void error(String msg) {
@@ -112,10 +92,6 @@ public static void log(Level l, String msg) {
get().printLogMsg(l, msg);
}
- public static void debug(Throwable t) {
- log(Level.DEBUG, t);
- }
-
public static void log(Level l, Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw, true));
@@ -131,7 +107,7 @@ protected boolean isLevelLogged(Level l) {
}
public static Log get() {
- Log log = loggers.get();
+ Log log = logger.get();
return log != null ? log : stdOutErr;
}
diff --git a/make/langtools/tools/javacserver/server/log/LoggingOutputStream.java b/make/langtools/tools/javacserver/util/LoggingOutputStream.java
similarity index 97%
rename from make/langtools/tools/javacserver/server/log/LoggingOutputStream.java
rename to make/langtools/tools/javacserver/util/LoggingOutputStream.java
index 6df616bd5e2..3b3f88d7647 100644
--- a/make/langtools/tools/javacserver/server/log/LoggingOutputStream.java
+++ b/make/langtools/tools/javacserver/util/LoggingOutputStream.java
@@ -23,17 +23,14 @@
* questions.
*/
-package javacserver.server.log;
+package javacserver.util;
import java.io.ByteArrayOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
-import javacserver.Log;
-
public class LoggingOutputStream extends FilterOutputStream {
-
private static final byte[] LINE_SEP = System.lineSeparator().getBytes();
private final Log.Level level;
diff --git a/src/java.base/share/classes/sun/net/ProgressMeteringPolicy.java b/make/langtools/tools/javacserver/util/RunnableTimerTask.java
similarity index 68%
rename from src/java.base/share/classes/sun/net/ProgressMeteringPolicy.java
rename to make/langtools/tools/javacserver/util/RunnableTimerTask.java
index f6e3ea9465e..7d8f5aa3a43 100644
--- a/src/java.base/share/classes/sun/net/ProgressMeteringPolicy.java
+++ b/make/langtools/tools/javacserver/util/RunnableTimerTask.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,24 +22,23 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-package sun.net;
-import java.net.URL;
+package javacserver.util;
+
+import java.util.TimerTask;
/**
- * ProgressMeteringPolicy is an interface for determining progress metering policy.
- *
- * @author Stanley Man-Kit Ho
+ * Wrapper class since TimerTask is not up to modern standards
*/
-public interface ProgressMeteringPolicy
-{
- /**
- * Return true if metering should be turned on for a particular network input stream.
- */
- public boolean shouldMeterInput(URL url, String method);
+public class RunnableTimerTask extends TimerTask {
+ private final Runnable task;
+
+ public RunnableTimerTask(Runnable task) {
+ this.task = task;
+ }
- /**
- * Return update notification threshold.
- */
- public int getProgressUpdateThreshold();
+ @Override
+ public void run() {
+ task.run();
+ }
}
diff --git a/make/langtools/tools/javacserver/server/Sjavac.java b/make/langtools/tools/javacserver/util/Util.java
similarity index 72%
rename from make/langtools/tools/javacserver/server/Sjavac.java
rename to make/langtools/tools/javacserver/util/Util.java
index 9c7c980c2f2..8381b1c3c6d 100644
--- a/make/langtools/tools/javacserver/server/Sjavac.java
+++ b/make/langtools/tools/javacserver/util/Util.java
@@ -23,20 +23,18 @@
* questions.
*/
-package javacserver.server;
+package javacserver.util;
-import javacserver.Result;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
-/**
- * Interface of the SjavacImpl, the sjavac client and all wrappers such as
- * PooledSjavac etc.
- *
- * This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
- */
-public interface Sjavac {
- Result compile(String[] args);
- void shutdown();
+public class Util {
+ /**
+ * Return a stream of strings, where the input string is split at line separators.
+ */
+ public static Stream getLines(String str) {
+ return str.isEmpty()
+ ? Stream.empty()
+ : Stream.of(str.split(Pattern.quote(System.lineSeparator())));
+ }
}
diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk
index e32277d4a42..fecd7a957bc 100644
--- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk
+++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk
@@ -120,11 +120,6 @@ ifeq ($(call isTargetOs, windows), true)
LIBAWT_VERSIONINFO_RESOURCE := $(TOPDIR)/src/$(MODULE)/windows/native/libawt/windows/awt.rc
endif
-ifeq ($(call isTargetOs, linux), true)
- # FIXME: This is probably not what we want to do, but keep it now for compatibility.
- LIBAWT_CFLAGS += $(EXPORT_ALL_SYMBOLS)
-endif
-
# Turn off all warnings for debug_mem.c This is needed because the specific warning
# about initializing a declared 'extern' cannot be turned off individually. Only
# applies to debug builds. This limitation in gcc is tracked in
@@ -414,7 +409,7 @@ ifeq ($(FREETYPE_TO_USE), system)
LIBFREETYPE_LIBS := $(FREETYPE_LIBS)
else
BUILD_LIBFREETYPE_HEADER_DIRS := $(TOPDIR)/src/$(MODULE)/share/native/libfreetype/include
- BUILD_LIBFREETYPE_CFLAGS := -DFT2_BUILD_LIBRARY $(EXPORT_ALL_SYMBOLS)
+ BUILD_LIBFREETYPE_CFLAGS := -DFT2_BUILD_LIBRARY
# For use by libfontmanager:
LIBFREETYPE_CFLAGS := -I$(BUILD_LIBFREETYPE_HEADER_DIRS)
diff --git a/make/modules/jdk.sctp/Java.gmk b/make/modules/jdk.sctp/Java.gmk
index 05e27e1eaf8..10793d45c84 100644
--- a/make/modules/jdk.sctp/Java.gmk
+++ b/make/modules/jdk.sctp/Java.gmk
@@ -44,3 +44,10 @@ endif
ifeq ($(call isTargetOs, aix), true)
EXCLUDE_FILES += $(SCTP_IMPL_CLASSES)
endif
+
+ifeq ($(call isTargetOsType, unix), true)
+ ifeq ($(call isTargetOs, macosx aix), false)
+ # This class is not needed on "unix" because SCTP in Java is supported for that platform
+ EXCLUDE_FILES += $(TOPDIR)/src/jdk.sctp/share/classes/sun/nio/ch/sctp/UnsupportedUtil.java
+ endif
+endif
diff --git a/make/src/classes/build/tools/jfr/GenerateJfrFiles.java b/make/src/classes/build/tools/jfr/GenerateJfrFiles.java
index 712487ce32b..6b89d02ad2f 100644
--- a/make/src/classes/build/tools/jfr/GenerateJfrFiles.java
+++ b/make/src/classes/build/tools/jfr/GenerateJfrFiles.java
@@ -1,3 +1,28 @@
+/*
+ * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
package build.tools.jfr;
import java.io.BufferedOutputStream;
@@ -573,9 +598,13 @@ private static void printJfrPeriodicHpp(Metadata metadata, File outputFile) thro
out.write("#include \"jfrfiles/jfrEventIds.hpp\"");
out.write("#include \"memory/allocation.hpp\"");
out.write("");
+ out.write("enum PeriodicType {BEGIN_CHUNK, INTERVAL, END_CHUNK};");
+ out.write("");
out.write("class JfrPeriodicEventSet : public AllStatic {");
out.write(" public:");
- out.write(" static void requestEvent(JfrEventId id) {");
+ out.write(" static void requestEvent(JfrEventId id, jlong timestamp, PeriodicType periodicType) {");
+ out.write(" _timestamp = Ticks(timestamp);");
+ out.write(" _type = periodicType;");
out.write(" switch(id) {");
out.write(" ");
for (TypeElement e : metadata.getPeriodicEvents()) {
@@ -595,6 +624,10 @@ private static void printJfrPeriodicHpp(Metadata metadata, File outputFile) thro
out.write(" static void request" + e.name + "(void);");
out.write("");
}
+ out.write(" static Ticks timestamp(void);");
+ out.write(" static Ticks _timestamp;");
+ out.write(" static PeriodicType type(void);");
+ out.write(" static PeriodicType _type;");
out.write("};");
out.write("");
out.write("#endif // INCLUDE_JFR");
diff --git a/make/test/JtregNativeHotspot.gmk b/make/test/JtregNativeHotspot.gmk
index ba21e1f60e6..83c9a2377ca 100644
--- a/make/test/JtregNativeHotspot.gmk
+++ b/make/test/JtregNativeHotspot.gmk
@@ -874,7 +874,7 @@ BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exesigtest := -ljvm
ifeq ($(call isTargetOs, windows), true)
BUILD_HOTSPOT_JTREG_EXECUTABLES_CFLAGS_exeFPRegs := -MT
- BUILD_HOTSPOT_JTREG_EXCLUDE += exesigtest.c libterminatedThread.c libTestJNI.c libCompleteExit.c libTestPsig.c
+ BUILD_HOTSPOT_JTREG_EXCLUDE += exesigtest.c libterminatedThread.c libTestJNI.c libCompleteExit.c libTestPsig.c libnativeStack.c
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libatExit := jvm.lib
BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exedaemonDestroy := jvm.lib
else
@@ -1515,6 +1515,7 @@ else
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libterminatedThread += -lpthread
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libatExit += -ljvm
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libCompleteExit += -lpthread
+ BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libnativeStack += -lpthread
endif
# This evaluation is expensive and should only be done if this target was
diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad
index e6d39248ac4..e6c2cc79ff1 100644
--- a/src/hotspot/cpu/aarch64/aarch64.ad
+++ b/src/hotspot/cpu/aarch64/aarch64.ad
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2014, 2021, Red Hat, Inc. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
@@ -1739,7 +1739,7 @@ void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
st->print("\n\t");
st->print("ldr rscratch1, [guard]\n\t");
st->print("dmb ishld\n\t");
- st->print("ldr rscratch2, [rthread, #thread_disarmed_offset]\n\t");
+ st->print("ldr rscratch2, [rthread, #thread_disarmed_guard_value_offset]\n\t");
st->print("cmp rscratch1, rscratch2\n\t");
st->print("b.eq skip");
st->print("\n\t");
@@ -1796,8 +1796,9 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
Label* guard = &dummy_guard;
if (!Compile::current()->output()->in_scratch_emit_size()) {
// Use real labels from actual stub when not emitting code for the purpose of measuring its size
- C2EntryBarrierStub* stub = Compile::current()->output()->entry_barrier_table()->add_entry_barrier();
- slow_path = &stub->slow_path();
+ C2EntryBarrierStub* stub = new (Compile::current()->comp_arena()) C2EntryBarrierStub();
+ Compile::current()->output()->add_stub(stub);
+ slow_path = &stub->entry();
continuation = &stub->continuation();
guard = &stub->guard();
}
@@ -1879,7 +1880,9 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
Label dummy_label;
Label* code_stub = &dummy_label;
if (!C->output()->in_scratch_emit_size()) {
- code_stub = &C->output()->safepoint_poll_table()->add_safepoint(__ offset());
+ C2SafepointPollStub* stub = new (C->comp_arena()) C2SafepointPollStub(__ offset());
+ C->output()->add_stub(stub);
+ code_stub = &stub->entry();
}
__ relocate(relocInfo::poll_return_type);
__ safepoint_poll(*code_stub, true /* at_return */, false /* acquire */, true /* in_nmethod */);
@@ -3632,6 +3635,11 @@ encode %{
ciEnv::current()->record_failure("CodeCache is full");
return;
}
+ } else if (_method->intrinsic_id() == vmIntrinsicID::_ensureMaterializedForStackWalk) {
+ // The NOP here is purely to ensure that eliding a call to
+ // JVM_EnsureMaterializedForStackWalk doesn't change the code size.
+ __ nop();
+ __ block_comment("call JVM_EnsureMaterializedForStackWalk (elided)");
} else {
int method_index = resolved_method_index(cbuf);
RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index)
@@ -7550,7 +7558,7 @@ instruct storeimmL0(immL0 zero, memory8 mem)
instruct storeP(iRegP src, memory8 mem)
%{
match(Set mem (StoreP mem src));
- predicate(!needs_releasing_store(n));
+ predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0);
ins_cost(INSN_COST);
format %{ "str $src, $mem\t# ptr" %}
@@ -7564,7 +7572,7 @@ instruct storeP(iRegP src, memory8 mem)
instruct storeimmP0(immP0 zero, memory8 mem)
%{
match(Set mem (StoreP mem zero));
- predicate(!needs_releasing_store(n));
+ predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0);
ins_cost(INSN_COST);
format %{ "str zr, $mem\t# ptr" %}
@@ -7965,6 +7973,7 @@ instruct storeimmL0_volatile(immL0 zero, /* sync_memory*/indirect mem)
instruct storeP_volatile(iRegP src, /* sync_memory*/indirect mem)
%{
match(Set mem (StoreP mem src));
+ predicate(n->as_Store()->barrier_data() == 0);
ins_cost(VOLATILE_REF_COST);
format %{ "stlr $src, $mem\t# ptr" %}
@@ -7977,6 +7986,7 @@ instruct storeP_volatile(iRegP src, /* sync_memory*/indirect mem)
instruct storeimmP0_volatile(immP0 zero, /* sync_memory*/indirect mem)
%{
match(Set mem (StoreP mem zero));
+ predicate(n->as_Store()->barrier_data() == 0);
ins_cost(VOLATILE_REF_COST);
format %{ "stlr zr, $mem\t# ptr" %}
@@ -9646,6 +9656,90 @@ instruct get_and_addIi_no_resAcq(indirect mem, Universe dummy, immIAddSub incr)
ins_pipe(pipe_serial);
%}
+// Manifest a CmpU result in an integer register.
+// (src1 < src2) ? -1 : ((src1 > src2) ? 1 : 0)
+instruct cmpU3_reg_reg(iRegINoSp dst, iRegI src1, iRegI src2, rFlagsReg flags)
+%{
+ match(Set dst (CmpU3 src1 src2));
+ effect(KILL flags);
+
+ ins_cost(INSN_COST * 3);
+ format %{
+ "cmpw $src1, $src2\n\t"
+ "csetw $dst, ne\n\t"
+ "cnegw $dst, lo\t# CmpU3(reg)"
+ %}
+ ins_encode %{
+ __ cmpw($src1$$Register, $src2$$Register);
+ __ csetw($dst$$Register, Assembler::NE);
+ __ cnegw($dst$$Register, $dst$$Register, Assembler::LO);
+ %}
+
+ ins_pipe(pipe_class_default);
+%}
+
+instruct cmpU3_reg_imm(iRegINoSp dst, iRegI src1, immIAddSub src2, rFlagsReg flags)
+%{
+ match(Set dst (CmpU3 src1 src2));
+ effect(KILL flags);
+
+ ins_cost(INSN_COST * 3);
+ format %{
+ "subsw zr, $src1, $src2\n\t"
+ "csetw $dst, ne\n\t"
+ "cnegw $dst, lo\t# CmpU3(imm)"
+ %}
+ ins_encode %{
+ __ subsw(zr, $src1$$Register, (int32_t)$src2$$constant);
+ __ csetw($dst$$Register, Assembler::NE);
+ __ cnegw($dst$$Register, $dst$$Register, Assembler::LO);
+ %}
+
+ ins_pipe(pipe_class_default);
+%}
+
+// Manifest a CmpUL result in an integer register.
+// (src1 < src2) ? -1 : ((src1 > src2) ? 1 : 0)
+instruct cmpUL3_reg_reg(iRegINoSp dst, iRegL src1, iRegL src2, rFlagsReg flags)
+%{
+ match(Set dst (CmpUL3 src1 src2));
+ effect(KILL flags);
+
+ ins_cost(INSN_COST * 3);
+ format %{
+ "cmp $src1, $src2\n\t"
+ "csetw $dst, ne\n\t"
+ "cnegw $dst, lo\t# CmpUL3(reg)"
+ %}
+ ins_encode %{
+ __ cmp($src1$$Register, $src2$$Register);
+ __ csetw($dst$$Register, Assembler::NE);
+ __ cnegw($dst$$Register, $dst$$Register, Assembler::LO);
+ %}
+
+ ins_pipe(pipe_class_default);
+%}
+
+instruct cmpUL3_reg_imm(iRegINoSp dst, iRegL src1, immLAddSub src2, rFlagsReg flags)
+%{
+ match(Set dst (CmpUL3 src1 src2));
+ effect(KILL flags);
+
+ ins_cost(INSN_COST * 3);
+ format %{
+ "subs zr, $src1, $src2\n\t"
+ "csetw $dst, ne\n\t"
+ "cnegw $dst, lo\t# CmpUL3(imm)"
+ %}
+ ins_encode %{
+ __ subs(zr, $src1$$Register, (int32_t)$src2$$constant);
+ __ csetw($dst$$Register, Assembler::NE);
+ __ cnegw($dst$$Register, $dst$$Register, Assembler::LO);
+ %}
+
+ ins_pipe(pipe_class_default);
+%}
+
// Manifest a CmpL result in an integer register.
// (src1 < src2) ? -1 : ((src1 > src2) ? 1 : 0)
instruct cmpL3_reg_reg(iRegINoSp dst, iRegL src1, iRegL src2, rFlagsReg flags)
@@ -9653,13 +9747,12 @@ instruct cmpL3_reg_reg(iRegINoSp dst, iRegL src1, iRegL src2, rFlagsReg flags)
match(Set dst (CmpL3 src1 src2));
effect(KILL flags);
- ins_cost(INSN_COST * 6);
+ ins_cost(INSN_COST * 3);
format %{
- "cmp $src1, $src2"
- "csetw $dst, ne"
- "cnegw $dst, lt"
+ "cmp $src1, $src2\n\t"
+ "csetw $dst, ne\n\t"
+ "cnegw $dst, lt\t# CmpL3(reg)"
%}
- // format %{ "CmpL3 $dst, $src1, $src2" %}
ins_encode %{
__ cmp($src1$$Register, $src2$$Register);
__ csetw($dst$$Register, Assembler::NE);
@@ -9674,19 +9767,14 @@ instruct cmpL3_reg_imm(iRegINoSp dst, iRegL src1, immLAddSub src2, rFlagsReg fla
match(Set dst (CmpL3 src1 src2));
effect(KILL flags);
- ins_cost(INSN_COST * 6);
+ ins_cost(INSN_COST * 3);
format %{
- "cmp $src1, $src2"
- "csetw $dst, ne"
- "cnegw $dst, lt"
+ "subs zr, $src1, $src2\n\t"
+ "csetw $dst, ne\n\t"
+ "cnegw $dst, lt\t# CmpL3(imm)"
%}
ins_encode %{
- int32_t con = (int32_t)$src2$$constant;
- if (con < 0) {
- __ adds(zr, $src1$$Register, -con);
- } else {
- __ subs(zr, $src1$$Register, con);
- }
+ __ subs(zr, $src1$$Register, (int32_t)$src2$$constant);
__ csetw($dst$$Register, Assembler::NE);
__ cnegw($dst$$Register, $dst$$Register, Assembler::LT);
%}
diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad
index 7868d7cf46b..c67d43a2c34 100644
--- a/src/hotspot/cpu/aarch64/aarch64_vector.ad
+++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad
@@ -132,6 +132,11 @@ source %{
// Vector API intrinsics.
if ((opcode == Op_VectorCastD2X && bt == T_INT) ||
(opcode == Op_VectorCastL2X && bt == T_FLOAT) ||
+ (opcode == Op_CountLeadingZerosV && bt == T_LONG) ||
+ (opcode == Op_CountTrailingZerosV && bt == T_LONG) ||
+ // The vector implementation of Op_AddReductionVD/F is for the Vector API only.
+ // It is not suitable for auto-vectorization because it does not add the elements
+ // in the same order as sequential code, and FP addition is non-associative.
opcode == Op_AddReductionVD || opcode == Op_AddReductionVF ||
opcode == Op_MulReductionVD || opcode == Op_MulReductionVF ||
opcode == Op_MulVL) {
@@ -2874,23 +2879,30 @@ instruct reduce_addL_sve(iRegLNoSp dst, iRegL isrc, vReg vsrc, vRegD tmp) %{
%}
// reduction addF
+// Floating-point addition is not associative, so the rules for AddReductionVF
+// on NEON can't be used to auto-vectorize floating-point reduce-add.
+// Currently, on NEON, AddReductionVF is only generated by Vector API.
+instruct reduce_add2F_neon(vRegF dst, vRegF fsrc, vReg vsrc) %{
+ predicate(UseSVE == 0 && Matcher::vector_length(n->in(2)) == 2);
+ match(Set dst (AddReductionVF fsrc vsrc));
+ effect(TEMP_DEF dst);
+ format %{ "reduce_add2F_neon $dst, $fsrc, $vsrc" %}
+ ins_encode %{
+ __ faddp($dst$$FloatRegister, $vsrc$$FloatRegister, __ S);
+ __ fadds($dst$$FloatRegister, $dst$$FloatRegister, $fsrc$$FloatRegister);
+ %}
+ ins_pipe(pipe_slow);
+%}
-instruct reduce_addF_neon(vRegF dst, vRegF fsrc, vReg vsrc, vReg tmp) %{
- predicate(UseSVE == 0);
+instruct reduce_add4F_neon(vRegF dst, vRegF fsrc, vReg vsrc, vReg tmp) %{
+ predicate(UseSVE == 0 && Matcher::vector_length(n->in(2)) == 4);
match(Set dst (AddReductionVF fsrc vsrc));
effect(TEMP_DEF dst, TEMP tmp);
- format %{ "reduce_addF_neon $dst, $fsrc, $vsrc\t# KILL $tmp" %}
+ format %{ "reduce_add4F_neon $dst, $fsrc, $vsrc\t# KILL $tmp" %}
ins_encode %{
- uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
- __ fadds($dst$$FloatRegister, $fsrc$$FloatRegister, $vsrc$$FloatRegister);
- __ ins($tmp$$FloatRegister, __ S, $vsrc$$FloatRegister, 0, 1);
- __ fadds($dst$$FloatRegister, $dst$$FloatRegister, $tmp$$FloatRegister);
- if (length_in_bytes == 16) {
- __ ins($tmp$$FloatRegister, __ S, $vsrc$$FloatRegister, 0, 2);
- __ fadds($dst$$FloatRegister, $dst$$FloatRegister, $tmp$$FloatRegister);
- __ ins($tmp$$FloatRegister, __ S, $vsrc$$FloatRegister, 0, 3);
- __ fadds($dst$$FloatRegister, $dst$$FloatRegister, $tmp$$FloatRegister);
- }
+ __ faddp($tmp$$FloatRegister, __ T4S, $vsrc$$FloatRegister, $vsrc$$FloatRegister);
+ __ faddp($dst$$FloatRegister, $tmp$$FloatRegister, __ S);
+ __ fadds($dst$$FloatRegister, $dst$$FloatRegister, $fsrc$$FloatRegister);
%}
ins_pipe(pipe_slow);
%}
@@ -2908,16 +2920,17 @@ instruct reduce_addF_sve(vRegF dst_src1, vReg src2) %{
%}
// reduction addD
-
-instruct reduce_addD_neon(vRegD dst, vRegD dsrc, vReg vsrc, vReg tmp) %{
+// Floating-point addition is not associative, so the rule for AddReductionVD
+// on NEON can't be used to auto-vectorize floating-point reduce-add.
+// Currently, on NEON, AddReductionVD is only generated by Vector API.
+instruct reduce_addD_neon(vRegD dst, vRegD dsrc, vReg vsrc) %{
predicate(UseSVE == 0);
match(Set dst (AddReductionVD dsrc vsrc));
- effect(TEMP_DEF dst, TEMP tmp);
- format %{ "reduce_addD_neon $dst, $dsrc, $vsrc\t# 2D. KILL $tmp" %}
+ effect(TEMP_DEF dst);
+ format %{ "reduce_addD_neon $dst, $dsrc, $vsrc\t# 2D" %}
ins_encode %{
- __ faddd($dst$$FloatRegister, $dsrc$$FloatRegister, $vsrc$$FloatRegister);
- __ ins($tmp$$FloatRegister, __ D, $vsrc$$FloatRegister, 0, 1);
- __ faddd($dst$$FloatRegister, $dst$$FloatRegister, $tmp$$FloatRegister);
+ __ faddp($dst$$FloatRegister, $vsrc$$FloatRegister, __ D);
+ __ faddd($dst$$FloatRegister, $dst$$FloatRegister, $dsrc$$FloatRegister);
%}
ins_pipe(pipe_slow);
%}
@@ -5672,7 +5685,6 @@ instruct vpopcountI(vReg dst, vReg src) %{
// vector popcount - LONG
instruct vpopcountL(vReg dst, vReg src) %{
- predicate(Matcher::vector_element_basic_type(n) == T_LONG);
match(Set dst (PopCountVL src));
format %{ "vpopcountL $dst, $src" %}
ins_encode %{
@@ -5688,32 +5700,6 @@ instruct vpopcountL(vReg dst, vReg src) %{
ins_pipe(pipe_slow);
%}
-// If the PopCountVL is generated by auto-vectorization, the dst basic
-// type is T_INT. And once we have unified the type definition for
-// Vector API and auto-vectorization, this rule can be merged with
-// "vpopcountL" rule.
-
-instruct vpopcountL_I(vReg dst, vReg src, vReg tmp) %{
- predicate(Matcher::vector_element_basic_type(n) == T_INT);
- match(Set dst (PopCountVL src));
- effect(TEMP_DEF dst, TEMP tmp);
- format %{ "vpopcountL_I $dst, $src\t# KILL $tmp" %}
- ins_encode %{
- if (UseSVE == 0) {
- __ cnt($dst$$FloatRegister, __ T16B, $src$$FloatRegister);
- __ uaddlp($dst$$FloatRegister, __ T16B, $dst$$FloatRegister);
- __ uaddlp($dst$$FloatRegister, __ T8H, $dst$$FloatRegister);
- __ uaddlp($dst$$FloatRegister, __ T4S, $dst$$FloatRegister);
- __ xtn($dst$$FloatRegister, __ T2S, $dst$$FloatRegister, __ T2D);
- } else {
- __ sve_cnt($dst$$FloatRegister, __ D, ptrue, $src$$FloatRegister);
- __ sve_vector_narrow($dst$$FloatRegister, __ S,
- $dst$$FloatRegister, __ D, $tmp$$FloatRegister);
- }
- %}
- ins_pipe(pipe_slow);
-%}
-
// vector popcount - predicated
instruct vpopcountI_masked(vReg dst_src, pRegGov pg) %{
@@ -5729,7 +5715,7 @@ instruct vpopcountI_masked(vReg dst_src, pRegGov pg) %{
%}
instruct vpopcountL_masked(vReg dst_src, pRegGov pg) %{
- predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n) == T_LONG);
+ predicate(UseSVE > 0);
match(Set dst_src (PopCountVL dst_src pg));
format %{ "vpopcountL_masked $dst_src, $pg, $dst_src" %}
ins_encode %{
@@ -5894,67 +5880,62 @@ instruct vroundD(vReg dst, vReg src, immI rmode) %{
// anytrue
-instruct vtest_anytrue_neon(iRegINoSp dst, vReg src1, vReg src2, vReg tmp, rFlagsReg cr) %{
+instruct vtest_anytrue_neon(rFlagsReg cr, vReg src1, vReg src2, vReg tmp) %{
predicate(UseSVE == 0 &&
static_cast(n)->get_predicate() == BoolTest::ne);
- match(Set dst (VectorTest src1 src2 ));
- effect(TEMP tmp, KILL cr);
- format %{ "vtest_anytrue_neon $dst, $src1\t# KILL $tmp, cr" %}
+ match(Set cr (VectorTest src1 src2));
+ effect(TEMP tmp);
+ format %{ "vtest_anytrue_neon $src1\t# KILL $tmp" %}
ins_encode %{
// No need to use src2.
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src1);
assert(length_in_bytes == 8 || length_in_bytes == 16, "must be");
__ addv($tmp$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B, $src1$$FloatRegister);
- __ umov($dst$$Register, $tmp$$FloatRegister, __ B, 0);
- __ cmpw($dst$$Register, zr);
- __ csetw($dst$$Register, Assembler::NE);
+ __ umov(rscratch1, $tmp$$FloatRegister, __ B, 0);
+ __ cmpw(rscratch1, zr);
%}
ins_pipe(pipe_slow);
%}
-instruct vtest_anytrue_sve(iRegINoSp dst, pReg src1, pReg src2, rFlagsReg cr) %{
+instruct vtest_anytrue_sve(rFlagsReg cr, pReg src1, pReg src2) %{
predicate(UseSVE > 0 &&
static_cast(n)->get_predicate() == BoolTest::ne);
- match(Set dst (VectorTest src1 src2));
- effect(KILL cr);
- format %{ "vtest_anytrue_sve $dst, $src1\t# KILL cr" %}
+ match(Set cr (VectorTest src1 src2));
+ format %{ "vtest_anytrue_sve $src1" %}
ins_encode %{
// "src2" is not used for sve.
__ sve_ptest(ptrue, $src1$$PRegister);
- __ csetw($dst$$Register, Assembler::NE);
%}
ins_pipe(pipe_slow);
%}
// alltrue
-instruct vtest_alltrue_neon(iRegINoSp dst, vReg src1, vReg src2, vReg tmp, rFlagsReg cr) %{
+instruct vtest_alltrue_neon(rFlagsReg cr, vReg src1, vReg src2, vReg tmp) %{
predicate(UseSVE == 0 &&
static_cast(n)->get_predicate() == BoolTest::overflow);
- match(Set dst (VectorTest src1 src2));
- effect(TEMP tmp, KILL cr);
- format %{ "vtest_alltrue_neon $dst, $src1\t# KILL $tmp, cr" %}
+ match(Set cr (VectorTest src1 src2));
+ effect(TEMP tmp);
+ format %{ "vtest_alltrue_neon $src1\t# KILL $tmp" %}
ins_encode %{
// No need to use src2.
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src1);
assert(length_in_bytes == 8 || length_in_bytes == 16, "must be");
__ uminv($tmp$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B, $src1$$FloatRegister);
- __ umov($dst$$Register, $tmp$$FloatRegister, __ B, 0);
- __ cmpw($dst$$Register, 0xff);
- __ csetw($dst$$Register, Assembler::EQ);
+ __ umov(rscratch1, $tmp$$FloatRegister, __ B, 0);
+ __ cmpw(rscratch1, 0xff);
%}
ins_pipe(pipe_slow);
%}
-instruct vtest_alltrue_sve(iRegINoSp dst, pReg src1, pReg src2, pReg ptmp, rFlagsReg cr) %{
+instruct vtest_alltrue_sve(rFlagsReg cr, pReg src1, pReg src2, pReg ptmp) %{
predicate(UseSVE > 0 &&
static_cast(n)->get_predicate() == BoolTest::overflow);
- match(Set dst (VectorTest src1 src2));
- effect(TEMP ptmp, KILL cr);
- format %{ "vtest_alltrue_sve $dst, $src1, $src2\t# KILL $ptmp, cr" %}
+ match(Set cr (VectorTest src1 src2));
+ effect(TEMP ptmp);
+ format %{ "vtest_alltrue_sve $src1, $src2\t# KILL $ptmp" %}
ins_encode %{
__ sve_eors($ptmp$$PRegister, ptrue, $src1$$PRegister, $src2$$PRegister);
- __ csetw($dst$$Register, Assembler::EQ);
%}
ins_pipe(pipe_slow);
%}
diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4
index 118611b1675..b59e1ae43fa 100644
--- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4
+++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4
@@ -122,6 +122,11 @@ source %{
// Vector API intrinsics.
if ((opcode == Op_VectorCastD2X && bt == T_INT) ||
(opcode == Op_VectorCastL2X && bt == T_FLOAT) ||
+ (opcode == Op_CountLeadingZerosV && bt == T_LONG) ||
+ (opcode == Op_CountTrailingZerosV && bt == T_LONG) ||
+ // The vector implementation of Op_AddReductionVD/F is for the Vector API only.
+ // It is not suitable for auto-vectorization because it does not add the elements
+ // in the same order as sequential code, and FP addition is non-associative.
opcode == Op_AddReductionVD || opcode == Op_AddReductionVF ||
opcode == Op_MulReductionVD || opcode == Op_MulReductionVF ||
opcode == Op_MulVL) {
@@ -1806,23 +1811,30 @@ REDUCE_ADD_INT_NEON_SVE_PAIRWISE(I, iRegIorL2I)
REDUCE_ADD_INT_NEON_SVE_PAIRWISE(L, iRegL)
// reduction addF
+// Floating-point addition is not associative, so the rules for AddReductionVF
+// on NEON can't be used to auto-vectorize floating-point reduce-add.
+// Currently, on NEON, AddReductionVF is only generated by Vector API.
+instruct reduce_add2F_neon(vRegF dst, vRegF fsrc, vReg vsrc) %{
+ predicate(UseSVE == 0 && Matcher::vector_length(n->in(2)) == 2);
+ match(Set dst (AddReductionVF fsrc vsrc));
+ effect(TEMP_DEF dst);
+ format %{ "reduce_add2F_neon $dst, $fsrc, $vsrc" %}
+ ins_encode %{
+ __ faddp($dst$$FloatRegister, $vsrc$$FloatRegister, __ S);
+ __ fadds($dst$$FloatRegister, $dst$$FloatRegister, $fsrc$$FloatRegister);
+ %}
+ ins_pipe(pipe_slow);
+%}
-instruct reduce_addF_neon(vRegF dst, vRegF fsrc, vReg vsrc, vReg tmp) %{
- predicate(UseSVE == 0);
+instruct reduce_add4F_neon(vRegF dst, vRegF fsrc, vReg vsrc, vReg tmp) %{
+ predicate(UseSVE == 0 && Matcher::vector_length(n->in(2)) == 4);
match(Set dst (AddReductionVF fsrc vsrc));
effect(TEMP_DEF dst, TEMP tmp);
- format %{ "reduce_addF_neon $dst, $fsrc, $vsrc\t# KILL $tmp" %}
+ format %{ "reduce_add4F_neon $dst, $fsrc, $vsrc\t# KILL $tmp" %}
ins_encode %{
- uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc);
- __ fadds($dst$$FloatRegister, $fsrc$$FloatRegister, $vsrc$$FloatRegister);
- __ ins($tmp$$FloatRegister, __ S, $vsrc$$FloatRegister, 0, 1);
- __ fadds($dst$$FloatRegister, $dst$$FloatRegister, $tmp$$FloatRegister);
- if (length_in_bytes == 16) {
- __ ins($tmp$$FloatRegister, __ S, $vsrc$$FloatRegister, 0, 2);
- __ fadds($dst$$FloatRegister, $dst$$FloatRegister, $tmp$$FloatRegister);
- __ ins($tmp$$FloatRegister, __ S, $vsrc$$FloatRegister, 0, 3);
- __ fadds($dst$$FloatRegister, $dst$$FloatRegister, $tmp$$FloatRegister);
- }
+ __ faddp($tmp$$FloatRegister, __ T4S, $vsrc$$FloatRegister, $vsrc$$FloatRegister);
+ __ faddp($dst$$FloatRegister, $tmp$$FloatRegister, __ S);
+ __ fadds($dst$$FloatRegister, $dst$$FloatRegister, $fsrc$$FloatRegister);
%}
ins_pipe(pipe_slow);
%}
@@ -1845,16 +1857,17 @@ dnl
REDUCE_ADD_FP_SVE(F, S)
// reduction addD
-
-instruct reduce_addD_neon(vRegD dst, vRegD dsrc, vReg vsrc, vReg tmp) %{
+// Floating-point addition is not associative, so the rule for AddReductionVD
+// on NEON can't be used to auto-vectorize floating-point reduce-add.
+// Currently, on NEON, AddReductionVD is only generated by Vector API.
+instruct reduce_addD_neon(vRegD dst, vRegD dsrc, vReg vsrc) %{
predicate(UseSVE == 0);
match(Set dst (AddReductionVD dsrc vsrc));
- effect(TEMP_DEF dst, TEMP tmp);
- format %{ "reduce_addD_neon $dst, $dsrc, $vsrc\t# 2D. KILL $tmp" %}
+ effect(TEMP_DEF dst);
+ format %{ "reduce_addD_neon $dst, $dsrc, $vsrc\t# 2D" %}
ins_encode %{
- __ faddd($dst$$FloatRegister, $dsrc$$FloatRegister, $vsrc$$FloatRegister);
- __ ins($tmp$$FloatRegister, __ D, $vsrc$$FloatRegister, 0, 1);
- __ faddd($dst$$FloatRegister, $dst$$FloatRegister, $tmp$$FloatRegister);
+ __ faddp($dst$$FloatRegister, $vsrc$$FloatRegister, __ D);
+ __ faddd($dst$$FloatRegister, $dst$$FloatRegister, $dsrc$$FloatRegister);
%}
ins_pipe(pipe_slow);
%}
@@ -4055,7 +4068,6 @@ instruct vpopcountI(vReg dst, vReg src) %{
// vector popcount - LONG
instruct vpopcountL(vReg dst, vReg src) %{
- predicate(Matcher::vector_element_basic_type(n) == T_LONG);
match(Set dst (PopCountVL src));
format %{ "vpopcountL $dst, $src" %}
ins_encode %{
@@ -4071,37 +4083,11 @@ instruct vpopcountL(vReg dst, vReg src) %{
ins_pipe(pipe_slow);
%}
-// If the PopCountVL is generated by auto-vectorization, the dst basic
-// type is T_INT. And once we have unified the type definition for
-// Vector API and auto-vectorization, this rule can be merged with
-// "vpopcountL" rule.
-
-instruct vpopcountL_I(vReg dst, vReg src, vReg tmp) %{
- predicate(Matcher::vector_element_basic_type(n) == T_INT);
- match(Set dst (PopCountVL src));
- effect(TEMP_DEF dst, TEMP tmp);
- format %{ "vpopcountL_I $dst, $src\t# KILL $tmp" %}
- ins_encode %{
- if (UseSVE == 0) {
- __ cnt($dst$$FloatRegister, __ T16B, $src$$FloatRegister);
- __ uaddlp($dst$$FloatRegister, __ T16B, $dst$$FloatRegister);
- __ uaddlp($dst$$FloatRegister, __ T8H, $dst$$FloatRegister);
- __ uaddlp($dst$$FloatRegister, __ T4S, $dst$$FloatRegister);
- __ xtn($dst$$FloatRegister, __ T2S, $dst$$FloatRegister, __ T2D);
- } else {
- __ sve_cnt($dst$$FloatRegister, __ D, ptrue, $src$$FloatRegister);
- __ sve_vector_narrow($dst$$FloatRegister, __ S,
- $dst$$FloatRegister, __ D, $tmp$$FloatRegister);
- }
- %}
- ins_pipe(pipe_slow);
-%}
-
// vector popcount - predicated
UNARY_OP_PREDICATE(vpopcountI, PopCountVI, sve_cnt)
instruct vpopcountL_masked(vReg dst_src, pRegGov pg) %{
- predicate(UseSVE > 0 && Matcher::vector_element_basic_type(n) == T_LONG);
+ predicate(UseSVE > 0);
match(Set dst_src (PopCountVL dst_src pg));
format %{ "vpopcountL_masked $dst_src, $pg, $dst_src" %}
ins_encode %{
@@ -4266,67 +4252,62 @@ instruct vroundD(vReg dst, vReg src, immI rmode) %{
// anytrue
-instruct vtest_anytrue_neon(iRegINoSp dst, vReg src1, vReg src2, vReg tmp, rFlagsReg cr) %{
+instruct vtest_anytrue_neon(rFlagsReg cr, vReg src1, vReg src2, vReg tmp) %{
predicate(UseSVE == 0 &&
static_cast(n)->get_predicate() == BoolTest::ne);
- match(Set dst (VectorTest src1 src2 ));
- effect(TEMP tmp, KILL cr);
- format %{ "vtest_anytrue_neon $dst, $src1\t# KILL $tmp, cr" %}
+ match(Set cr (VectorTest src1 src2));
+ effect(TEMP tmp);
+ format %{ "vtest_anytrue_neon $src1\t# KILL $tmp" %}
ins_encode %{
// No need to use src2.
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src1);
assert(length_in_bytes == 8 || length_in_bytes == 16, "must be");
__ addv($tmp$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B, $src1$$FloatRegister);
- __ umov($dst$$Register, $tmp$$FloatRegister, __ B, 0);
- __ cmpw($dst$$Register, zr);
- __ csetw($dst$$Register, Assembler::NE);
+ __ umov(rscratch1, $tmp$$FloatRegister, __ B, 0);
+ __ cmpw(rscratch1, zr);
%}
ins_pipe(pipe_slow);
%}
-instruct vtest_anytrue_sve(iRegINoSp dst, pReg src1, pReg src2, rFlagsReg cr) %{
+instruct vtest_anytrue_sve(rFlagsReg cr, pReg src1, pReg src2) %{
predicate(UseSVE > 0 &&
static_cast(n)->get_predicate() == BoolTest::ne);
- match(Set dst (VectorTest src1 src2));
- effect(KILL cr);
- format %{ "vtest_anytrue_sve $dst, $src1\t# KILL cr" %}
+ match(Set cr (VectorTest src1 src2));
+ format %{ "vtest_anytrue_sve $src1" %}
ins_encode %{
// "src2" is not used for sve.
__ sve_ptest(ptrue, $src1$$PRegister);
- __ csetw($dst$$Register, Assembler::NE);
%}
ins_pipe(pipe_slow);
%}
// alltrue
-instruct vtest_alltrue_neon(iRegINoSp dst, vReg src1, vReg src2, vReg tmp, rFlagsReg cr) %{
+instruct vtest_alltrue_neon(rFlagsReg cr, vReg src1, vReg src2, vReg tmp) %{
predicate(UseSVE == 0 &&
static_cast(n)->get_predicate() == BoolTest::overflow);
- match(Set dst (VectorTest src1 src2));
- effect(TEMP tmp, KILL cr);
- format %{ "vtest_alltrue_neon $dst, $src1\t# KILL $tmp, cr" %}
+ match(Set cr (VectorTest src1 src2));
+ effect(TEMP tmp);
+ format %{ "vtest_alltrue_neon $src1\t# KILL $tmp" %}
ins_encode %{
// No need to use src2.
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src1);
assert(length_in_bytes == 8 || length_in_bytes == 16, "must be");
__ uminv($tmp$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B, $src1$$FloatRegister);
- __ umov($dst$$Register, $tmp$$FloatRegister, __ B, 0);
- __ cmpw($dst$$Register, 0xff);
- __ csetw($dst$$Register, Assembler::EQ);
+ __ umov(rscratch1, $tmp$$FloatRegister, __ B, 0);
+ __ cmpw(rscratch1, 0xff);
%}
ins_pipe(pipe_slow);
%}
-instruct vtest_alltrue_sve(iRegINoSp dst, pReg src1, pReg src2, pReg ptmp, rFlagsReg cr) %{
+instruct vtest_alltrue_sve(rFlagsReg cr, pReg src1, pReg src2, pReg ptmp) %{
predicate(UseSVE > 0 &&
static_cast(n)->get_predicate() == BoolTest::overflow);
- match(Set dst (VectorTest src1 src2));
- effect(TEMP ptmp, KILL cr);
- format %{ "vtest_alltrue_sve $dst, $src1, $src2\t# KILL $ptmp, cr" %}
+ match(Set cr (VectorTest src1 src2));
+ effect(TEMP ptmp);
+ format %{ "vtest_alltrue_sve $src1, $src2\t# KILL $ptmp" %}
ins_encode %{
__ sve_eors($ptmp$$PRegister, ptrue, $src1$$PRegister, $src2$$PRegister);
- __ csetw($dst$$Register, Assembler::EQ);
%}
ins_pipe(pipe_slow);
%}
diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp
index b05c0e800e8..3cd87e254b3 100644
--- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -505,7 +505,20 @@ class Address {
}
bool uses(Register reg) const {
- return base() == reg || index() == reg;
+ switch (_mode) {
+ case literal:
+ case no_mode:
+ return false;
+ case base_plus_offset:
+ case base_plus_offset_reg:
+ case pre:
+ case post:
+ case post_reg:
+ return base() == reg || index() == reg;
+ default:
+ ShouldNotReachHere();
+ return false;
+ }
}
address target() const {
@@ -2435,6 +2448,7 @@ void mvnw(Register Rd, Register Rm,
break;
default:
ShouldNotReachHere();
+ Rm = 0; // unreachable
}
starti;
@@ -2715,6 +2729,7 @@ template
INSN(fabd, 1, 1, 0b110101);
INSN(fadd, 0, 0, 0b110101);
INSN(fdiv, 1, 0, 0b111111);
+ INSN(faddp, 1, 0, 0b110101);
INSN(fmul, 1, 0, 0b110111);
INSN(fsub, 0, 1, 0b110101);
INSN(fmla, 0, 0, 0b110011);
diff --git a/src/hotspot/cpu/aarch64/c1_Defs_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_Defs_aarch64.hpp
index 9072d09f18c..e92c538637f 100644
--- a/src/hotspot/cpu/aarch64/c1_Defs_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/c1_Defs_aarch64.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -78,4 +78,8 @@ enum {
pd_float_saved_as_double = false
};
+enum {
+ pd_two_operand_lir_form = false
+};
+
#endif // CPU_AARCH64_C1_DEFS_AARCH64_HPP
diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp
index aa51335c4c2..3aa7acf71b3 100644
--- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -199,9 +199,12 @@ void C1_MacroAssembler::initialize_body(Register obj, Register len_in_bytes, int
mov(rscratch1, len_in_bytes);
lea(t1, Address(obj, hdr_size_in_bytes));
lsr(t2, rscratch1, LogBytesPerWord);
- zero_words(t1, t2);
+ address tpc = zero_words(t1, t2);
bind(done);
+ if (tpc == nullptr) {
+ Compilation::current()->bailout("no space for trampoline stub");
+ }
}
@@ -228,10 +231,17 @@ void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register
if (var_size_in_bytes != noreg) {
mov(index, var_size_in_bytes);
initialize_body(obj, index, hdr_size_in_bytes, t1, t2);
+ if (Compilation::current()->bailed_out()) {
+ return;
+ }
} else if (con_size_in_bytes > hdr_size_in_bytes) {
con_size_in_bytes -= hdr_size_in_bytes;
lea(t1, Address(obj, hdr_size_in_bytes));
- zero_words(t1, con_size_in_bytes / BytesPerWord);
+ address tpc = zero_words(t1, con_size_in_bytes / BytesPerWord);
+ if (tpc == nullptr) {
+ Compilation::current()->bailout("no space for trampoline stub");
+ return;
+ }
}
}
@@ -267,6 +277,9 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1,
// clear rest of allocated space
initialize_body(obj, arr_size, header_size * BytesPerWord, t1, t2);
+ if (Compilation::current()->bailed_out()) {
+ return;
+ }
membar(StoreStore);
diff --git a/src/hotspot/cpu/aarch64/c1_globals_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_globals_aarch64.hpp
index 50bbbd786d9..c2d1405b005 100644
--- a/src/hotspot/cpu/aarch64/c1_globals_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/c1_globals_aarch64.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -60,6 +60,5 @@ define_pd_global(bool, UseTypeProfile, false);
define_pd_global(bool, OptimizeSinglePrecision, true );
define_pd_global(bool, CSEArrayLength, false);
-define_pd_global(bool, TwoOperandLIRForm, false );
#endif // CPU_AARCH64_C1_GLOBALS_AARCH64_HPP
diff --git a/src/hotspot/cpu/aarch64/c2_safepointPollStubTable_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp
similarity index 65%
rename from src/hotspot/cpu/aarch64/c2_safepointPollStubTable_aarch64.cpp
rename to src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp
index fb36406fbde..009883d6082 100644
--- a/src/hotspot/cpu/aarch64/c2_safepointPollStubTable_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,24 +23,44 @@
*/
#include "precompiled.hpp"
-#include "asm/macroAssembler.hpp"
-#include "opto/compile.hpp"
-#include "opto/node.hpp"
-#include "opto/output.hpp"
+#include "opto/c2_MacroAssembler.hpp"
+#include "opto/c2_CodeStubs.hpp"
#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
#define __ masm.
-void C2SafepointPollStubTable::emit_stub_impl(MacroAssembler& masm, C2SafepointPollStub* entry) const {
+
+int C2SafepointPollStub::max_size() const {
+ return 20;
+}
+
+void C2SafepointPollStub::emit(C2_MacroAssembler& masm) {
assert(SharedRuntime::polling_page_return_handler_blob() != NULL,
"polling page return stub not created yet");
address stub = SharedRuntime::polling_page_return_handler_blob()->entry_point();
RuntimeAddress callback_addr(stub);
- __ bind(entry->_stub_label);
- InternalAddress safepoint_pc(masm.pc() - masm.offset() + entry->_safepoint_offset);
+ __ bind(entry());
+ InternalAddress safepoint_pc(masm.pc() - masm.offset() + _safepoint_offset);
__ adr(rscratch1, safepoint_pc);
__ str(rscratch1, Address(rthread, JavaThread::saved_exception_pc_offset()));
__ far_jump(callback_addr);
}
+
+int C2EntryBarrierStub::max_size() const {
+ return 24;
+}
+
+void C2EntryBarrierStub::emit(C2_MacroAssembler& masm) {
+ __ bind(entry());
+ __ movptr(rscratch1, (uintptr_t) StubRoutines::aarch64::method_entry_barrier());
+ __ blr(rscratch1);
+ __ b(continuation());
+
+ __ bind(guard());
+ __ relocate(entry_guard_Relocation::spec());
+ __ emit_int32(0); // nmethod guard value
+}
+
#undef __
diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
index 93495e0fc58..121b2b96209 100644
--- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -45,21 +45,6 @@
typedef void (MacroAssembler::* chr_insn)(Register Rt, const Address &adr);
-void C2_MacroAssembler::emit_entry_barrier_stub(C2EntryBarrierStub* stub) {
- bind(stub->slow_path());
- movptr(rscratch1, (uintptr_t) StubRoutines::aarch64::method_entry_barrier());
- blr(rscratch1);
- b(stub->continuation());
-
- bind(stub->guard());
- relocate(entry_guard_Relocation::spec());
- emit_int32(0); // nmethod guard value
-}
-
-int C2_MacroAssembler::entry_barrier_stub_size() {
- return 4 * 6;
-}
-
// Search for str1 in str2 and return index or -1
void C2_MacroAssembler::string_indexof(Register str2, Register str1,
Register cnt2, Register cnt1,
@@ -313,7 +298,12 @@ void C2_MacroAssembler::string_indexof(Register str2, Register str1,
stub = RuntimeAddress(StubRoutines::aarch64::string_indexof_linear_uu());
assert(stub.target() != NULL, "string_indexof_linear_uu stub has not been generated");
}
- trampoline_call(stub);
+ address call = trampoline_call(stub);
+ if (call == nullptr) {
+ DEBUG_ONLY(reset_labels(LINEARSEARCH, LINEAR_MEDIUM, DONE, NOMATCH, MATCH));
+ ciEnv::current()->record_failure("CodeCache is full");
+ return;
+ }
b(DONE);
}
@@ -872,7 +862,12 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2,
ShouldNotReachHere();
}
assert(stub.target() != NULL, "compare_long_string stub has not been generated");
- trampoline_call(stub);
+ address call = trampoline_call(stub);
+ if (call == nullptr) {
+ DEBUG_ONLY(reset_labels(DONE, SHORT_LOOP, SHORT_STRING, SHORT_LAST, SHORT_LOOP_TAIL, SHORT_LAST2, SHORT_LAST_INIT, SHORT_LOOP_START));
+ ciEnv::current()->record_failure("CodeCache is full");
+ return;
+ }
b(DONE);
bind(SHORT_STRING);
diff --git a/src/hotspot/cpu/aarch64/codeBuffer_aarch64.cpp b/src/hotspot/cpu/aarch64/codeBuffer_aarch64.cpp
index a4213707afb..3bc12a1f651 100644
--- a/src/hotspot/cpu/aarch64/codeBuffer_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/codeBuffer_aarch64.cpp
@@ -52,7 +52,14 @@ static bool emit_shared_trampolines(CodeBuffer* cb, CodeBuffer::SharedTrampoline
bool p_succeeded = true;
auto emit = [&](address dest, const CodeBuffer::Offsets &offsets) {
masm.set_code_section(cb->stubs());
- masm.align(wordSize);
+ if (!is_aligned(masm.offset(), wordSize)) {
+ if (cb->stubs()->maybe_expand_to_ensure_remaining(NativeInstruction::instruction_size) && cb->blob() == NULL) {
+ ciEnv::current()->record_failure("CodeCache is full");
+ p_succeeded = false;
+ return p_succeeded;
+ }
+ masm.align(wordSize);
+ }
LinkedListIterator it(offsets.head());
int offset = *it.next();
diff --git a/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp
index 79976b84d0a..6075c09f8d2 100644
--- a/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp
+++ b/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp
@@ -196,11 +196,6 @@ inline void ThawBase::prefetch_chunk_pd(void* start, int size) {
Prefetch::read(start, size - 64);
}
-void ThawBase::patch_chunk_pd(intptr_t* sp) {
- intptr_t* fp = _cont.entryFP();
- *(intptr_t**)(sp - frame::sender_sp_offset) = fp;
-}
-
template
inline void Thaw::patch_caller_links(intptr_t* sp, intptr_t* bottom) {
// Fast path depends on !PreserveFramePointer. See can_thaw_fast().
diff --git a/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp b/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp
index a46a8be39d1..9f740098e19 100644
--- a/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/downcallLinker_aarch64.cpp
@@ -42,13 +42,14 @@ class DowncallStubGenerator : public StubCodeGenerator {
BasicType _ret_bt;
const ABIDescriptor& _abi;
- const GrowableArray& _input_registers;
- const GrowableArray& _output_registers;
+ const GrowableArray& _input_registers;
+ const GrowableArray& _output_registers;
bool _needs_return_buffer;
+ int _captured_state_mask;
int _frame_complete;
- int _framesize;
+ int _frame_size_slots;
OopMapSet* _oop_maps;
public:
DowncallStubGenerator(CodeBuffer* buffer,
@@ -56,9 +57,10 @@ class DowncallStubGenerator : public StubCodeGenerator {
int num_args,
BasicType ret_bt,
const ABIDescriptor& abi,
- const GrowableArray& input_registers,
- const GrowableArray& output_registers,
- bool needs_return_buffer)
+ const GrowableArray& input_registers,
+ const GrowableArray& output_registers,
+ bool needs_return_buffer,
+ int captured_state_mask)
: StubCodeGenerator(buffer, PrintMethodHandleStubs),
_signature(signature),
_num_args(num_args),
@@ -67,8 +69,9 @@ class DowncallStubGenerator : public StubCodeGenerator {
_input_registers(input_registers),
_output_registers(output_registers),
_needs_return_buffer(needs_return_buffer),
+ _captured_state_mask(captured_state_mask),
_frame_complete(0),
- _framesize(0),
+ _frame_size_slots(0),
_oop_maps(NULL) {
}
@@ -79,7 +82,7 @@ class DowncallStubGenerator : public StubCodeGenerator {
}
int framesize() const {
- return (_framesize >> (LogBytesPerWord - LogBytesPerInt));
+ return (_frame_size_slots >> (LogBytesPerWord - LogBytesPerInt));
}
OopMapSet* oop_maps() const {
@@ -93,12 +96,15 @@ RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature,
int num_args,
BasicType ret_bt,
const ABIDescriptor& abi,
- const GrowableArray& input_registers,
- const GrowableArray& output_registers,
- bool needs_return_buffer) {
- int locs_size = 64;
+ const GrowableArray& input_registers,
+ const GrowableArray& output_registers,
+ bool needs_return_buffer,
+ int captured_state_mask) {
+ int locs_size = 64;
CodeBuffer code("nep_invoker_blob", native_invoker_code_size, locs_size);
- DowncallStubGenerator g(&code, signature, num_args, ret_bt, abi, input_registers, output_registers, needs_return_buffer);
+ DowncallStubGenerator g(&code, signature, num_args, ret_bt, abi,
+ input_registers, output_registers,
+ needs_return_buffer, captured_state_mask);
g.generate();
code.log_section_sizes("nep_invoker_blob");
@@ -137,10 +143,10 @@ void DowncallStubGenerator::generate() {
Register tmp1 = r9;
Register tmp2 = r10;
- Register shuffle_reg = r19;
+ VMStorage shuffle_reg = as_VMStorage(r19);
JavaCallingConvention in_conv;
NativeCallingConvention out_conv(_input_registers);
- ArgumentShuffle arg_shuffle(_signature, _num_args, _signature, _num_args, &in_conv, &out_conv, shuffle_reg->as_VMReg());
+ ArgumentShuffle arg_shuffle(_signature, _num_args, _signature, _num_args, &in_conv, &out_conv, shuffle_reg);
#ifndef PRODUCT
LogTarget(Trace, foreign, downcall) lt;
@@ -152,32 +158,36 @@ void DowncallStubGenerator::generate() {
#endif
int allocated_frame_size = 0;
- if (_needs_return_buffer) {
- allocated_frame_size += 8; // for address spill
- }
- allocated_frame_size += arg_shuffle.out_arg_stack_slots() < allocated_frame_size
? out_reg_spiller.spill_size_bytes()
: allocated_frame_size;
}
- _framesize = align_up(framesize
- + (allocated_frame_size >> LogBytesPerInt), 4);
- assert(is_even(_framesize/2), "sp not 16-byte aligned");
+ StubLocations locs;
+ locs.set(StubLocations::TARGET_ADDRESS, _abi._scratch1);
+ if (_needs_return_buffer) {
+ locs.set_frame_data(StubLocations::RETURN_BUFFER, allocated_frame_size);
+ allocated_frame_size += BytesPerWord; // for address spill
+ }
+ if (_captured_state_mask != 0) {
+ locs.set_frame_data(StubLocations::CAPTURED_STATE_BUFFER, allocated_frame_size);
+ allocated_frame_size += BytesPerWord;
+ }
+
+ _frame_size_slots = align_up(framesize + (allocated_frame_size >> LogBytesPerInt), 4);
+ assert(is_even(_frame_size_slots/2), "sp not 16-byte aligned");
_oop_maps = new OopMapSet();
address start = __ pc();
@@ -185,13 +195,13 @@ void DowncallStubGenerator::generate() {
__ enter();
// lr and fp are already in place
- __ sub(sp, rfp, ((unsigned)_framesize-4) << LogBytesPerInt); // prolog
+ __ sub(sp, rfp, ((unsigned)_frame_size_slots-4) << LogBytesPerInt); // prolog
_frame_complete = __ pc() - start;
address the_pc = __ pc();
__ set_last_Java_frame(sp, rfp, the_pc, tmp1);
- OopMap* map = new OopMap(_framesize, 0);
+ OopMap* map = new OopMap(_frame_size_slots, 0);
_oop_maps->add_gc_map(the_pc - start, map);
// State transition
@@ -200,43 +210,22 @@ void DowncallStubGenerator::generate() {
__ stlrw(tmp1, tmp2);
__ block_comment("{ argument shuffle");
- arg_shuffle.generate(_masm, shuffle_reg->as_VMReg(), 0, _abi._shadow_space_bytes);
- if (_needs_return_buffer) {
- assert(ret_buf_addr_sp_offset != -1, "no return buffer addr spill");
- __ str(_abi._ret_buf_addr_reg, Address(sp, ret_buf_addr_sp_offset));
- }
+ arg_shuffle.generate(_masm, shuffle_reg, 0, _abi._shadow_space_bytes, locs);
__ block_comment("} argument shuffle");
- __ blr(_abi._target_addr_reg);
+ __ blr(as_Register(locs.get(StubLocations::TARGET_ADDRESS)));
// this call is assumed not to have killed rthread
- if (!_needs_return_buffer) {
- // Unpack native results.
- switch (_ret_bt) {
- case T_BOOLEAN: __ c2bool(r0); break;
- case T_CHAR : __ ubfx(r0, r0, 0, 16); break;
- case T_BYTE : __ sbfx(r0, r0, 0, 8); break;
- case T_SHORT : __ sbfx(r0, r0, 0, 16); break;
- case T_INT : __ sbfx(r0, r0, 0, 32); break;
- case T_DOUBLE :
- case T_FLOAT :
- // Result is in v0 we'll save as needed
- break;
- case T_VOID: break;
- case T_LONG: break;
- default : ShouldNotReachHere();
- }
- } else {
- assert(ret_buf_addr_sp_offset != -1, "no return buffer addr spill");
- __ ldr(tmp1, Address(sp, ret_buf_addr_sp_offset));
+ if (_needs_return_buffer) {
+ __ ldr(tmp1, Address(sp, locs.data_offset(StubLocations::RETURN_BUFFER)));
int offset = 0;
for (int i = 0; i < _output_registers.length(); i++) {
- VMReg reg = _output_registers.at(i);
- if (reg->is_Register()) {
- __ str(reg->as_Register(), Address(tmp1, offset));
+ VMStorage reg = _output_registers.at(i);
+ if (reg.type() == StorageType::INTEGER) {
+ __ str(as_Register(reg), Address(tmp1, offset));
offset += 8;
- } else if(reg->is_FloatRegister()) {
- __ strd(reg->as_FloatRegister(), Address(tmp1, offset));
+ } else if (reg.type() == StorageType::VECTOR) {
+ __ strd(as_FloatRegister(reg), Address(tmp1, offset));
offset += 16;
} else {
ShouldNotReachHere();
@@ -244,6 +233,28 @@ void DowncallStubGenerator::generate() {
}
}
+ //////////////////////////////////////////////////////////////////////////////
+
+ if (_captured_state_mask != 0) {
+ __ block_comment("{ save thread local");
+
+ if (should_save_return_value) {
+ out_reg_spiller.generate_spill(_masm, spill_offset);
+ }
+
+ __ ldr(c_rarg0, Address(sp, locs.data_offset(StubLocations::CAPTURED_STATE_BUFFER)));
+ __ movw(c_rarg1, _captured_state_mask);
+ __ rt_call(CAST_FROM_FN_PTR(address, DowncallLinker::capture_state), tmp1);
+
+ if (should_save_return_value) {
+ out_reg_spiller.generate_fill(_masm, spill_offset);
+ }
+
+ __ block_comment("} save thread local");
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
__ mov(tmp1, _thread_in_native_trans);
__ strw(tmp1, Address(rthread, JavaThread::thread_state_offset()));
@@ -288,7 +299,7 @@ void DowncallStubGenerator::generate() {
__ block_comment("{ L_safepoint_poll_slow_path");
__ bind(L_safepoint_poll_slow_path);
- if (!_needs_return_buffer) {
+ if (should_save_return_value) {
// Need to save the native result registers around any runtime calls.
out_reg_spiller.generate_spill(_masm, spill_offset);
}
@@ -298,7 +309,7 @@ void DowncallStubGenerator::generate() {
__ lea(tmp1, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)));
__ blr(tmp1);
- if (!_needs_return_buffer) {
+ if (should_save_return_value) {
out_reg_spiller.generate_fill(_masm, spill_offset);
}
@@ -310,13 +321,13 @@ void DowncallStubGenerator::generate() {
__ block_comment("{ L_reguard");
__ bind(L_reguard);
- if (!_needs_return_buffer) {
+ if (should_save_return_value) {
out_reg_spiller.generate_spill(_masm, spill_offset);
}
__ rt_call(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages), tmp1);
- if (!_needs_return_buffer) {
+ if (should_save_return_value) {
out_reg_spiller.generate_fill(_masm, spill_offset);
}
diff --git a/src/hotspot/cpu/aarch64/foreignGlobals_aarch64.cpp b/src/hotspot/cpu/aarch64/foreignGlobals_aarch64.cpp
index 6416703502e..e20c7e40601 100644
--- a/src/hotspot/cpu/aarch64/foreignGlobals_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/foreignGlobals_aarch64.cpp
@@ -30,6 +30,7 @@
#include "oops/oopCast.inline.hpp"
#include "prims/foreignGlobals.hpp"
#include "prims/foreignGlobals.inline.hpp"
+#include "prims/vmstorage.hpp"
#include "utilities/formatBuffer.hpp"
bool ABIDescriptor::is_volatile_reg(Register reg) const {
@@ -42,112 +43,183 @@ bool ABIDescriptor::is_volatile_reg(FloatRegister reg) const {
|| _vector_additional_volatile_registers.contains(reg);
}
-static constexpr int INTEGER_TYPE = 0;
-static constexpr int VECTOR_TYPE = 1;
-
const ABIDescriptor ForeignGlobals::parse_abi_descriptor(jobject jabi) {
oop abi_oop = JNIHandles::resolve_non_null(jabi);
ABIDescriptor abi;
- constexpr Register (*to_Register)(int) = as_Register;
objArrayOop inputStorage = jdk_internal_foreign_abi_ABIDescriptor::inputStorage(abi_oop);
- parse_register_array(inputStorage, INTEGER_TYPE, abi._integer_argument_registers, to_Register);
- parse_register_array(inputStorage, VECTOR_TYPE, abi._vector_argument_registers, as_FloatRegister);
+ parse_register_array(inputStorage, StorageType::INTEGER, abi._integer_argument_registers, as_Register);
+ parse_register_array(inputStorage, StorageType::VECTOR, abi._vector_argument_registers, as_FloatRegister);
objArrayOop outputStorage = jdk_internal_foreign_abi_ABIDescriptor::outputStorage(abi_oop);
- parse_register_array(outputStorage, INTEGER_TYPE, abi._integer_return_registers, to_Register);
- parse_register_array(outputStorage, VECTOR_TYPE, abi._vector_return_registers, as_FloatRegister);
+ parse_register_array(outputStorage, StorageType::INTEGER, abi._integer_return_registers, as_Register);
+ parse_register_array(outputStorage, StorageType::VECTOR, abi._vector_return_registers, as_FloatRegister);
objArrayOop volatileStorage = jdk_internal_foreign_abi_ABIDescriptor::volatileStorage(abi_oop);
- parse_register_array(volatileStorage, INTEGER_TYPE, abi._integer_additional_volatile_registers, to_Register);
- parse_register_array(volatileStorage, VECTOR_TYPE, abi._vector_additional_volatile_registers, as_FloatRegister);
+ parse_register_array(volatileStorage, StorageType::INTEGER, abi._integer_additional_volatile_registers, as_Register);
+ parse_register_array(volatileStorage, StorageType::VECTOR, abi._vector_additional_volatile_registers, as_FloatRegister);
abi._stack_alignment_bytes = jdk_internal_foreign_abi_ABIDescriptor::stackAlignment(abi_oop);
abi._shadow_space_bytes = jdk_internal_foreign_abi_ABIDescriptor::shadowSpace(abi_oop);
- abi._target_addr_reg = parse_vmstorage(jdk_internal_foreign_abi_ABIDescriptor::targetAddrStorage(abi_oop))->as_Register();
- abi._ret_buf_addr_reg = parse_vmstorage(jdk_internal_foreign_abi_ABIDescriptor::retBufAddrStorage(abi_oop))->as_Register();
+ abi._scratch1 = parse_vmstorage(jdk_internal_foreign_abi_ABIDescriptor::scratch1(abi_oop));
+ abi._scratch2 = parse_vmstorage(jdk_internal_foreign_abi_ABIDescriptor::scratch2(abi_oop));
return abi;
}
-enum class RegType {
- INTEGER = 0,
- VECTOR = 1,
- STACK = 3
-};
-
-VMReg ForeignGlobals::vmstorage_to_vmreg(int type, int index) {
- switch(static_cast(type)) {
- case RegType::INTEGER: return ::as_Register(index)->as_VMReg();
- case RegType::VECTOR: return ::as_FloatRegister(index)->as_VMReg();
- case RegType::STACK: return VMRegImpl::stack2reg(index LP64_ONLY(* 2));
- }
- return VMRegImpl::Bad();
-}
-
-int RegSpiller::pd_reg_size(VMReg reg) {
- if (reg->is_Register()) {
+int RegSpiller::pd_reg_size(VMStorage reg) {
+ if (reg.type() == StorageType::INTEGER) {
return 8;
- } else if (reg->is_FloatRegister()) {
+ } else if (reg.type() == StorageType::VECTOR) {
return 16; // Always spill/unspill Q registers
}
return 0; // stack and BAD
}
-void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMReg reg) {
- if (reg->is_Register()) {
- masm->spill(reg->as_Register(), true, offset);
- } else if (reg->is_FloatRegister()) {
- masm->spill(reg->as_FloatRegister(), masm->Q, offset);
+void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMStorage reg) {
+ if (reg.type() == StorageType::INTEGER) {
+ masm->spill(as_Register(reg), true, offset);
+ } else if (reg.type() == StorageType::VECTOR) {
+ masm->spill(as_FloatRegister(reg), masm->Q, offset);
} else {
// stack and BAD
}
}
-void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMReg reg) {
- if (reg->is_Register()) {
- masm->unspill(reg->as_Register(), true, offset);
- } else if (reg->is_FloatRegister()) {
- masm->unspill(reg->as_FloatRegister(), masm->Q, offset);
+void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMStorage reg) {
+ if (reg.type() == StorageType::INTEGER) {
+ masm->unspill(as_Register(reg), true, offset);
+ } else if (reg.type() == StorageType::VECTOR) {
+ masm->unspill(as_FloatRegister(reg), masm->Q, offset);
} else {
// stack and BAD
}
}
-void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMReg tmp, int in_stk_bias, int out_stk_bias) const {
- assert(in_stk_bias == 0 && out_stk_bias == 0, "bias not implemented");
- Register tmp_reg = tmp->as_Register();
+static constexpr int RFP_BIAS = 16; // skip old rfp and lr
+
+static void move_reg64(MacroAssembler* masm, int out_stk_bias,
+ Register from_reg, VMStorage to_reg) {
+ int out_bias = 0;
+ switch (to_reg.type()) {
+ case StorageType::INTEGER:
+ assert(to_reg.segment_mask() == REG64_MASK, "only moves to 64-bit registers supported");
+ masm->mov(as_Register(to_reg), from_reg);
+ break;
+ case StorageType::STACK:
+ out_bias = out_stk_bias;
+ case StorageType::FRAME_DATA: {
+ Address dest(sp, to_reg.offset() + out_bias);
+ switch (to_reg.stack_size()) {
+ case 8: masm->str (from_reg, dest); break;
+ case 4: masm->strw(from_reg, dest); break;
+ case 2: masm->strh(from_reg, dest); break;
+ case 1: masm->strb(from_reg, dest); break;
+ default: ShouldNotReachHere();
+ }
+ } break;
+ default: ShouldNotReachHere();
+ }
+}
+
+static void move_stack(MacroAssembler* masm, Register tmp_reg, int in_stk_bias, int out_stk_bias,
+ VMStorage from_reg, VMStorage to_reg) {
+ Address from_addr(rfp, RFP_BIAS + from_reg.offset() + in_stk_bias);
+ int out_bias = 0;
+ switch (to_reg.type()) {
+ case StorageType::INTEGER:
+ assert(to_reg.segment_mask() == REG64_MASK, "only moves to 64-bit registers supported");
+ switch (from_reg.stack_size()) {
+ case 8: masm->ldr (as_Register(to_reg), from_addr); break;
+ case 4: masm->ldrw(as_Register(to_reg), from_addr); break;
+ case 2: masm->ldrh(as_Register(to_reg), from_addr); break;
+ case 1: masm->ldrb(as_Register(to_reg), from_addr); break;
+ default: ShouldNotReachHere();
+ }
+ break;
+ case StorageType::VECTOR:
+ assert(to_reg.segment_mask() == V128_MASK, "only moves to v128 registers supported");
+ switch (from_reg.stack_size()) {
+ case 8:
+ masm->ldrd(as_FloatRegister(to_reg), from_addr);
+ break;
+ case 4:
+ masm->ldrs(as_FloatRegister(to_reg), from_addr);
+ break;
+ default: ShouldNotReachHere();
+ }
+ break;
+ case StorageType::STACK:
+ out_bias = out_stk_bias;
+ case StorageType::FRAME_DATA: {
+ switch (from_reg.stack_size()) {
+ case 8: masm->ldr (tmp_reg, from_addr); break;
+ case 4: masm->ldrw(tmp_reg, from_addr); break;
+ case 2: masm->ldrh(tmp_reg, from_addr); break;
+ case 1: masm->ldrb(tmp_reg, from_addr); break;
+ default: ShouldNotReachHere();
+ }
+ Address dest(sp, to_reg.offset() + out_bias);
+ switch (to_reg.stack_size()) {
+ case 8: masm->str (tmp_reg, dest); break;
+ case 4: masm->strw(tmp_reg, dest); break;
+ case 2: masm->strh(tmp_reg, dest); break;
+ case 1: masm->strb(tmp_reg, dest); break;
+ default: ShouldNotReachHere();
+ }
+ } break;
+ default: ShouldNotReachHere();
+ }
+}
+
+static void move_v128(MacroAssembler* masm, int out_stk_bias,
+ FloatRegister from_reg, VMStorage to_reg) {
+ switch (to_reg.type()) {
+ case StorageType::VECTOR:
+ assert(to_reg.segment_mask() == V128_MASK, "only moves to v128 registers supported");
+ masm->fmovd(as_FloatRegister(to_reg), from_reg);
+ break;
+ case StorageType::STACK: {
+ Address dest(sp, to_reg.offset() + out_stk_bias);
+ switch (to_reg.stack_size()) {
+ case 8: masm->strd(from_reg, dest); break;
+ case 4: masm->strs(from_reg, dest); break;
+ default: ShouldNotReachHere();
+ }
+ } break;
+ default: ShouldNotReachHere();
+ }
+}
+
+void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMStorage tmp, int in_stk_bias, int out_stk_bias, const StubLocations& locs) const {
+ Register tmp_reg = as_Register(tmp);
for (int i = 0; i < _moves.length(); i++) {
Move move = _moves.at(i);
- BasicType arg_bt = move.bt;
- VMRegPair from_vmreg = move.from;
- VMRegPair to_vmreg = move.to;
-
- masm->block_comment(err_msg("bt=%s", null_safe_string(type2name(arg_bt))));
- switch (arg_bt) {
- case T_BOOLEAN:
- case T_BYTE:
- case T_SHORT:
- case T_CHAR:
- case T_INT:
- masm->move32_64(from_vmreg, to_vmreg, tmp_reg);
- break;
+ VMStorage from_reg = move.from;
+ VMStorage to_reg = move.to;
- case T_FLOAT:
- masm->float_move(from_vmreg, to_vmreg, tmp_reg);
- break;
+ // replace any placeholders
+ if (from_reg.type() == StorageType::PLACEHOLDER) {
+ from_reg = locs.get(from_reg);
+ }
+ if (to_reg.type() == StorageType::PLACEHOLDER) {
+ to_reg = locs.get(to_reg);
+ }
- case T_DOUBLE:
- masm->double_move(from_vmreg, to_vmreg, tmp_reg);
+ switch (from_reg.type()) {
+ case StorageType::INTEGER:
+ assert(from_reg.segment_mask() == REG64_MASK, "only 64-bit register supported");
+ move_reg64(masm, out_stk_bias, as_Register(from_reg), to_reg);
break;
-
- case T_LONG :
- masm->long_move(from_vmreg, to_vmreg, tmp_reg);
+ case StorageType::VECTOR:
+ assert(from_reg.segment_mask() == V128_MASK, "only v128 register supported");
+ move_v128(masm, out_stk_bias, as_FloatRegister(from_reg), to_reg);
break;
-
- default:
- fatal("found in upcall args: %s", type2name(arg_bt));
+ case StorageType::STACK:
+ move_stack(masm, tmp_reg, in_stk_bias, out_stk_bias, from_reg, to_reg);
+ break;
+ default: ShouldNotReachHere();
}
}
}
diff --git a/src/hotspot/cpu/aarch64/foreignGlobals_aarch64.hpp b/src/hotspot/cpu/aarch64/foreignGlobals_aarch64.hpp
index 4555b44f528..c4f11266871 100644
--- a/src/hotspot/cpu/aarch64/foreignGlobals_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/foreignGlobals_aarch64.hpp
@@ -42,8 +42,8 @@ struct ABIDescriptor {
int32_t _stack_alignment_bytes;
int32_t _shadow_space_bytes;
- Register _target_addr_reg;
- Register _ret_buf_addr_reg;
+ VMStorage _scratch1;
+ VMStorage _scratch2;
bool is_volatile_reg(Register reg) const;
bool is_volatile_reg(FloatRegister reg) const;
diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp
index c076f4312b1..3ea2cc5e6ac 100644
--- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp
@@ -734,12 +734,12 @@ extern "C" void pf(uintptr_t sp, uintptr_t fp, uintptr_t pc,
uintptr_t bcx, uintptr_t thread) {
if (!reg_map) {
reg_map = NEW_C_HEAP_OBJ(RegisterMap, mtInternal);
- ::new (reg_map) RegisterMap((JavaThread*)thread,
+ ::new (reg_map) RegisterMap(reinterpret_cast(thread),
RegisterMap::UpdateMap::skip,
RegisterMap::ProcessFrames::include,
RegisterMap::WalkContinuation::skip);
} else {
- *reg_map = RegisterMap((JavaThread*)thread,
+ *reg_map = RegisterMap(reinterpret_cast(thread),
RegisterMap::UpdateMap::skip,
RegisterMap::ProcessFrames::include,
RegisterMap::WalkContinuation::skip);
diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp
index 7fb736d48d4..4d82b404845 100644
--- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp
@@ -217,7 +217,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo
// instruction patching is handled with isb fences on the way back
// from the safepoint to Java. So here we can do a plain conditional
// branch with no fencing.
- Address thread_disarmed_addr(rthread, in_bytes(bs_nm->thread_disarmed_offset()));
+ Address thread_disarmed_addr(rthread, in_bytes(bs_nm->thread_disarmed_guard_value_offset()));
__ ldrw(rscratch2, thread_disarmed_addr);
__ cmp(rscratch1, rscratch2);
} else if (patching_type == NMethodPatchingType::conc_instruction_and_data_patch) {
@@ -238,7 +238,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo
// Combine the guard value (low order) with the epoch value (high order).
__ orr(rscratch1, rscratch1, rscratch2, Assembler::LSL, 32);
// Compare the global values with the thread-local values.
- Address thread_disarmed_and_epoch_addr(rthread, in_bytes(bs_nm->thread_disarmed_offset()));
+ Address thread_disarmed_and_epoch_addr(rthread, in_bytes(bs_nm->thread_disarmed_guard_value_offset()));
__ ldr(rscratch2, thread_disarmed_and_epoch_addr);
__ cmp(rscratch1, rscratch2);
} else {
@@ -246,7 +246,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo
// Subsequent loads of oops must occur after load of guard value.
// BarrierSetNMethod::disarm sets guard with release semantics.
__ membar(__ LoadLoad);
- Address thread_disarmed_addr(rthread, in_bytes(bs_nm->thread_disarmed_offset()));
+ Address thread_disarmed_addr(rthread, in_bytes(bs_nm->thread_disarmed_guard_value_offset()));
__ ldrw(rscratch2, thread_disarmed_addr);
__ cmpw(rscratch1, rscratch2);
}
diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp
index 86ef613e1c4..d79705579b6 100644
--- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp
@@ -163,32 +163,12 @@ static NativeNMethodBarrier* native_nmethod_barrier(nmethod* nm) {
return barrier;
}
-void BarrierSetNMethod::disarm(nmethod* nm) {
+void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) {
if (!supports_entry_barrier(nm)) {
return;
}
- // The patching epoch is incremented before the nmethod is disarmed. Disarming
- // is performed with a release store. In the nmethod entry barrier, the values
- // are read in the opposite order, such that the load of the nmethod guard
- // acquires the patching epoch. This way, the guard is guaranteed to block
- // entries to the nmethod, until it has safely published the requirement for
- // further fencing by mutators, before they are allowed to enter.
- BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
- bs_asm->increment_patching_epoch();
-
- // Disarms the nmethod guard emitted by BarrierSetAssembler::nmethod_entry_barrier.
- // Symmetric "LDR; DMB ISHLD" is in the nmethod barrier.
- NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
- barrier->set_value(nm, disarmed_value());
-}
-
-void BarrierSetNMethod::arm(nmethod* nm, int arm_value) {
- if (!supports_entry_barrier(nm)) {
- return;
- }
-
- if (arm_value == disarmed_value()) {
+ if (value == disarmed_guard_value()) {
// The patching epoch is incremented before the nmethod is disarmed. Disarming
// is performed with a release store. In the nmethod entry barrier, the values
// are read in the opposite order, such that the load of the nmethod guard
@@ -200,14 +180,14 @@ void BarrierSetNMethod::arm(nmethod* nm, int arm_value) {
}
NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
- barrier->set_value(nm, arm_value);
+ barrier->set_value(nm, value);
}
-bool BarrierSetNMethod::is_armed(nmethod* nm) {
+int BarrierSetNMethod::guard_value(nmethod* nm) {
if (!supports_entry_barrier(nm)) {
- return false;
+ return disarmed_guard_value();
}
NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
- return barrier->get_value(nm) != disarmed_value();
+ return barrier->get_value(nm);
}
diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
index ff88e9487ef..b16140dac67 100644
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
@@ -4387,7 +4387,7 @@ void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators,
Register dst, Address src,
Register tmp1, Register tmp2) {
BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
- decorators = AccessInternal::decorator_fixup(decorators);
+ decorators = AccessInternal::decorator_fixup(decorators, type);
bool as_raw = (decorators & AS_RAW) != 0;
if (as_raw) {
bs->BarrierSetAssembler::load_at(this, decorators, type, dst, src, tmp1, tmp2);
@@ -4400,7 +4400,7 @@ void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators,
Address dst, Register val,
Register tmp1, Register tmp2, Register tmp3) {
BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
- decorators = AccessInternal::decorator_fixup(decorators);
+ decorators = AccessInternal::decorator_fixup(decorators, type);
bool as_raw = (decorators & AS_RAW) != 0;
if (as_raw) {
bs->BarrierSetAssembler::store_at(this, decorators, type, dst, val, tmp1, tmp2, tmp3);
diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
index 2f2f5cdd51a..e376d35f1e4 100644
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -1084,9 +1084,6 @@ class MacroAssembler: public Assembler {
bool acquire, bool release, bool weak,
Register result);
-private:
- void compare_eq(Register rn, Register rm, enum operand_size size);
-
#ifdef ASSERT
// Template short-hand support to clean-up after a failed call to trampoline
// call generation (see trampoline_call() below), when a set of Labels must
@@ -1101,6 +1098,9 @@ class MacroAssembler: public Assembler {
}
#endif
+private:
+ void compare_eq(Register rn, Register rm, enum operand_size size);
+
public:
// AArch64 OpenJDK uses four different types of calls:
// - direct call: bl pc_relative_offset
diff --git a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp
index a7dfe47ffb8..45b7dbf8c56 100644
--- a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp
@@ -163,6 +163,16 @@
// Implements a variant of EncodeISOArrayNode that encode ASCII only
static const bool supports_encode_ascii_array = true;
+ // An all-set mask is used for the alltrue vector test with SVE
+ static constexpr bool vectortest_needs_second_argument(bool is_alltrue, bool is_predicate) {
+ return is_predicate && is_alltrue;
+ }
+
+ // BoolTest mask for vector test intrinsics
+ static constexpr BoolTest::mask vectortest_mask(bool is_alltrue, bool is_predicate, int vlen) {
+ return is_alltrue ? BoolTest::eq : BoolTest::ne;
+ }
+
// Returns pre-selection estimated size of a vector operation.
static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) {
switch(vopc) {
diff --git a/src/hotspot/cpu/aarch64/register_aarch64.hpp b/src/hotspot/cpu/aarch64/register_aarch64.hpp
index 82f441cf765..f7ad44aa842 100644
--- a/src/hotspot/cpu/aarch64/register_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/register_aarch64.hpp
@@ -52,9 +52,9 @@ class Register {
public:
// accessors
- int raw_encoding() const { return this - first(); }
- int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); }
- bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; }
+ constexpr int raw_encoding() const { return this - first(); }
+ constexpr int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); }
+ constexpr bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; }
// derived registers, offsets, and addresses
inline Register successor() const;
@@ -71,7 +71,7 @@ class Register {
int operator==(const Register r) const { return _encoding == r._encoding; }
int operator!=(const Register r) const { return _encoding != r._encoding; }
- const RegisterImpl* operator->() const { return RegisterImpl::first() + _encoding; }
+ constexpr const RegisterImpl* operator->() const { return RegisterImpl::first() + _encoding; }
};
extern Register::RegisterImpl all_RegisterImpls[Register::number_of_declared_registers + 1] INTERNAL_VISIBILITY;
@@ -175,9 +175,9 @@ class FloatRegister {
public:
// accessors
- int raw_encoding() const { return this - first(); }
- int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); }
- bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; }
+ constexpr int raw_encoding() const { return this - first(); }
+ constexpr int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); }
+ constexpr bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; }
// derived registers, offsets, and addresses
inline FloatRegister successor() const;
@@ -192,7 +192,7 @@ class FloatRegister {
int operator==(const FloatRegister r) const { return _encoding == r._encoding; }
int operator!=(const FloatRegister r) const { return _encoding != r._encoding; }
- const FloatRegisterImpl* operator->() const { return FloatRegisterImpl::first() + _encoding; }
+ constexpr const FloatRegisterImpl* operator->() const { return FloatRegisterImpl::first() + _encoding; }
};
extern FloatRegister::FloatRegisterImpl all_FloatRegisterImpls[FloatRegister::number_of_registers + 1] INTERNAL_VISIBILITY;
diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
index 7f4fcae1f93..40afbe3f065 100644
--- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
* Copyright (c) 2021, Azul Systems, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -1103,6 +1103,9 @@ static void gen_continuation_enter(MacroAssembler* masm,
__ cbnz(c_rarg2, call_thaw);
const address tr_call = __ trampoline_call(resolve);
+ if (tr_call == nullptr) {
+ fatal("CodeCache is full at gen_continuation_enter");
+ }
oop_maps->add_gc_map(__ pc() - start, map);
__ post_call_nop();
@@ -1110,7 +1113,10 @@ static void gen_continuation_enter(MacroAssembler* masm,
__ b(exit);
CodeBuffer* cbuf = masm->code_section()->outer();
- CompiledStaticCall::emit_to_interp_stub(*cbuf, tr_call);
+ address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, tr_call);
+ if (stub == nullptr) {
+ fatal("CodeCache is full at gen_continuation_enter");
+ }
}
// compiled entry
@@ -1127,6 +1133,9 @@ static void gen_continuation_enter(MacroAssembler* masm,
__ cbnz(c_rarg2, call_thaw);
const address tr_call = __ trampoline_call(resolve);
+ if (tr_call == nullptr) {
+ fatal("CodeCache is full at gen_continuation_enter");
+ }
oop_maps->add_gc_map(__ pc() - start, map);
__ post_call_nop();
@@ -1168,7 +1177,10 @@ static void gen_continuation_enter(MacroAssembler* masm,
}
CodeBuffer* cbuf = masm->code_section()->outer();
- CompiledStaticCall::emit_to_interp_stub(*cbuf, tr_call);
+ address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, tr_call);
+ if (stub == nullptr) {
+ fatal("CodeCache is full at gen_continuation_enter");
+ }
}
static void gen_continuation_yield(MacroAssembler* masm,
diff --git a/src/hotspot/cpu/aarch64/stackChunkFrameStream_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/stackChunkFrameStream_aarch64.inline.hpp
index 58200559181..598104264d8 100644
--- a/src/hotspot/cpu/aarch64/stackChunkFrameStream_aarch64.inline.hpp
+++ b/src/hotspot/cpu/aarch64/stackChunkFrameStream_aarch64.inline.hpp
@@ -76,12 +76,6 @@ inline intptr_t* StackChunkFrameStream::unextended_sp_for_interprete
return derelativize(frame::interpreter_frame_last_sp_offset);
}
-template
-intptr_t* StackChunkFrameStream::next_sp_for_interpreter_frame() const {
- assert_is_interpreted_and_frame_type_mixed();
- return (derelativize(frame::interpreter_frame_locals_offset) + 1 >= _end) ? _end : fp() + frame::sender_sp_offset;
-}
-
template
inline void StackChunkFrameStream::next_for_interpreter_frame() {
assert_is_interpreted_and_frame_type_mixed();
diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
index 484df788026..96b067b0ca2 100644
--- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2022, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -2361,7 +2361,10 @@ class StubGenerator: public StubCodeGenerator {
__ cbnz(value, non_block_zeroing);
__ mov(bz_base, to);
__ add(to, to, cnt_words, Assembler::LSL, LogBytesPerWord);
- __ zero_words(bz_base, cnt_words);
+ address tpc = __ zero_words(bz_base, cnt_words);
+ if (tpc == nullptr) {
+ fatal("CodeCache is full at generate_fill");
+ }
__ b(rest);
__ bind(non_block_zeroing);
__ fill_words(to, cnt_words, value);
@@ -3246,7 +3249,7 @@ class StubGenerator: public StubCodeGenerator {
__ addw(rscratch4, r1, rscratch2);
__ ldrw(rscratch1, Address(buf, k*4));
__ eorw(rscratch3, rscratch3, r4);
- __ addw(rscratch3, rscratch3, rscratch1);
+ __ addw(rscratch4, rscratch4, rscratch1);
__ addw(rscratch3, rscratch3, rscratch4);
__ rorw(rscratch2, rscratch3, 32 - s);
__ addw(r1, rscratch2, r2);
@@ -3257,13 +3260,13 @@ class StubGenerator: public StubCodeGenerator {
Register rscratch3 = r10;
Register rscratch4 = r11;
- __ eorw(rscratch2, r2, r3);
+ __ andw(rscratch3, r2, r4);
+ __ bicw(rscratch4, r3, r4);
__ ldrw(rscratch1, Address(buf, k*4));
- __ andw(rscratch3, rscratch2, r4);
__ movw(rscratch2, t);
- __ eorw(rscratch3, rscratch3, r3);
+ __ orrw(rscratch3, rscratch3, rscratch4);
__ addw(rscratch4, r1, rscratch2);
- __ addw(rscratch3, rscratch3, rscratch1);
+ __ addw(rscratch4, rscratch4, rscratch1);
__ addw(rscratch3, rscratch3, rscratch4);
__ rorw(rscratch2, rscratch3, 32 - s);
__ addw(r1, rscratch2, r2);
@@ -3279,7 +3282,7 @@ class StubGenerator: public StubCodeGenerator {
__ addw(rscratch4, r1, rscratch2);
__ ldrw(rscratch1, Address(buf, k*4));
__ eorw(rscratch3, rscratch3, r2);
- __ addw(rscratch3, rscratch3, rscratch1);
+ __ addw(rscratch4, rscratch4, rscratch1);
__ addw(rscratch3, rscratch3, rscratch4);
__ rorw(rscratch2, rscratch3, 32 - s);
__ addw(r1, rscratch2, r2);
@@ -3295,7 +3298,7 @@ class StubGenerator: public StubCodeGenerator {
__ addw(rscratch4, r1, rscratch3);
__ ldrw(rscratch1, Address(buf, k*4));
__ eorw(rscratch3, rscratch2, r3);
- __ addw(rscratch3, rscratch3, rscratch1);
+ __ addw(rscratch4, rscratch4, rscratch1);
__ addw(rscratch3, rscratch3, rscratch4);
__ rorw(rscratch2, rscratch3, 32 - s);
__ addw(r1, rscratch2, r2);
@@ -5331,7 +5334,7 @@ class StubGenerator: public StubCodeGenerator {
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
// We can get here despite the nmethod being good, if we have not
// yet applied our cross modification fence (or data fence).
- Address thread_epoch_addr(rthread, in_bytes(bs_nm->thread_disarmed_offset()) + 4);
+ Address thread_epoch_addr(rthread, in_bytes(bs_nm->thread_disarmed_guard_value_offset()) + 4);
__ lea(rscratch2, ExternalAddress(bs_asm->patching_epoch_addr()));
__ ldrw(rscratch2, rscratch2);
__ strw(rscratch2, thread_epoch_addr);
diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp
index eeb080d586a..eca8b7f1ca4 100644
--- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp
@@ -836,9 +836,12 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
__ stp(r10, rscratch1, Address(sp, 4 * wordSize));
// Move SP out of the way
__ mov(sp, rscratch1);
- } else {
- __ mov(rscratch1, sp);
+ } else {
+ // Make sure there is room for the exception oop pushed in case method throws
+ // an exception (see TemplateInterpreterGenerator::generate_throw_exception())
+ __ sub(rscratch1, sp, 2 * wordSize);
__ stp(zr, rscratch1, Address(sp, 4 * wordSize));
+ __ mov(sp, rscratch1);
}
}
diff --git a/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp b/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp
index a051a47417e..9856fbdbdc3 100644
--- a/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp
@@ -128,9 +128,10 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
Register shuffle_reg = r19;
JavaCallingConvention out_conv;
NativeCallingConvention in_conv(call_regs._arg_regs);
- ArgumentShuffle arg_shuffle(in_sig_bt, total_in_args, out_sig_bt, total_out_args, &in_conv, &out_conv, shuffle_reg->as_VMReg());
- int stack_slots = SharedRuntime::out_preserve_stack_slots() + arg_shuffle.out_arg_stack_slots();
- int out_arg_area = align_up(stack_slots * VMRegImpl::stack_slot_size, StackAlignmentInBytes);
+ ArgumentShuffle arg_shuffle(in_sig_bt, total_in_args, out_sig_bt, total_out_args, &in_conv, &out_conv, as_VMStorage(shuffle_reg));
+ int preserved_bytes = SharedRuntime::out_preserve_stack_slots() * VMRegImpl::stack_slot_size;
+ int stack_bytes = preserved_bytes + arg_shuffle.out_arg_bytes();
+ int out_arg_area = align_up(stack_bytes , StackAlignmentInBytes);
#ifndef PRODUCT
LogTarget(Trace, foreign, upcall) lt;
@@ -158,10 +159,14 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
int frame_data_offset = reg_save_area_offset + reg_save_area_size;
int frame_bottom_offset = frame_data_offset + sizeof(UpcallStub::FrameData);
+ StubLocations locs;
int ret_buf_offset = -1;
if (needs_return_buffer) {
ret_buf_offset = frame_bottom_offset;
frame_bottom_offset += ret_buf_size;
+ // use a free register for shuffling code to pick up return
+ // buffer address from
+ locs.set(StubLocations::RETURN_BUFFER, abi._scratch1);
}
int frame_size = frame_bottom_offset;
@@ -218,9 +223,9 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
arg_spilller.generate_fill(_masm, arg_save_area_offset);
if (needs_return_buffer) {
assert(ret_buf_offset != -1, "no return buffer allocated");
- __ lea(abi._ret_buf_addr_reg, Address(sp, ret_buf_offset));
+ __ lea(as_Register(locs.get(StubLocations::RETURN_BUFFER)), Address(sp, ret_buf_offset));
}
- arg_shuffle.generate(_masm, shuffle_reg->as_VMReg(), abi._shadow_space_bytes, 0);
+ arg_shuffle.generate(_masm, as_VMStorage(shuffle_reg), abi._shadow_space_bytes, 0, locs);
__ block_comment("} argument shuffle");
__ block_comment("{ receiver ");
@@ -239,7 +244,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
if (!needs_return_buffer) {
#ifdef ASSERT
if (call_regs._ret_regs.length() == 1) { // 0 or 1
- VMReg j_expected_result_reg;
+ VMStorage j_expected_result_reg;
switch (ret_type) {
case T_BOOLEAN:
case T_BYTE:
@@ -247,19 +252,18 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
case T_CHAR:
case T_INT:
case T_LONG:
- j_expected_result_reg = r0->as_VMReg();
+ j_expected_result_reg = as_VMStorage(r0);
break;
case T_FLOAT:
case T_DOUBLE:
- j_expected_result_reg = v0->as_VMReg();
+ j_expected_result_reg = as_VMStorage(v0);
break;
default:
fatal("unexpected return type: %s", type2name(ret_type));
}
// No need to move for now, since CallArranger can pick a return type
// that goes in the same reg for both CCs. But, at least assert they are the same
- assert(call_regs._ret_regs.at(0) == j_expected_result_reg,
- "unexpected result register: %s != %s", call_regs._ret_regs.at(0)->name(), j_expected_result_reg->name());
+ assert(call_regs._ret_regs.at(0) == j_expected_result_reg, "unexpected result register");
}
#endif
} else {
@@ -267,12 +271,12 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
__ lea(rscratch1, Address(sp, ret_buf_offset));
int offset = 0;
for (int i = 0; i < call_regs._ret_regs.length(); i++) {
- VMReg reg = call_regs._ret_regs.at(i);
- if (reg->is_Register()) {
- __ ldr(reg->as_Register(), Address(rscratch1, offset));
+ VMStorage reg = call_regs._ret_regs.at(i);
+ if (reg.type() == StorageType::INTEGER) {
+ __ ldr(as_Register(reg), Address(rscratch1, offset));
offset += 8;
- } else if (reg->is_FloatRegister()) {
- __ ldrd(reg->as_FloatRegister(), Address(rscratch1, offset));
+ } else if (reg.type() == StorageType::VECTOR) {
+ __ ldrd(as_FloatRegister(reg), Address(rscratch1, offset));
offset += 16; // needs to match VECTOR_REG_SIZE in AArch64Architecture (Java)
} else {
ShouldNotReachHere();
@@ -328,9 +332,13 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
receiver,
in_ByteSize(frame_data_offset));
- if (TraceOptimizedUpcallStubs) {
- blob->print_on(tty);
+#ifndef PRODUCT
+ if (lt.is_enabled()) {
+ ResourceMark rm;
+ LogStream ls(lt);
+ blob->print_on(&ls);
}
+#endif
return blob->code_begin();
}
diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
index 25853cc38b1..d86d22d7fa7 100644
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -132,7 +132,7 @@ void VM_Version::initialize() {
// Enable vendor specific features
// Ampere eMAG
- if (_cpu == CPU_AMCC && (_model == 0) && (_variant == 0x3)) {
+ if (_cpu == CPU_AMCC && (_model == CPU_MODEL_EMAG) && (_variant == 0x3)) {
if (FLAG_IS_DEFAULT(AvoidUnalignedAccesses)) {
FLAG_SET_DEFAULT(AvoidUnalignedAccesses, true);
}
@@ -144,6 +144,13 @@ void VM_Version::initialize() {
}
}
+ // Ampere CPUs: Ampere-1 and Ampere-1A
+ if (_cpu == CPU_AMPERE && ((_model == CPU_MODEL_AMPERE_1) || (_model == CPU_MODEL_AMPERE_1A))) {
+ if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps)) {
+ FLAG_SET_DEFAULT(UseSIMDForMemoryOps, true);
+ }
+ }
+
// ThunderX
if (_cpu == CPU_CAVIUM && (_model == 0xA1)) {
guarantee(_variant != 0, "Pre-release hardware no longer supported.");
@@ -222,8 +229,8 @@ void VM_Version::initialize() {
}
char buf[512];
- sprintf(buf, "0x%02x:0x%x:0x%03x:%d", _cpu, _variant, _model, _revision);
- if (_model2) sprintf(buf+strlen(buf), "(0x%03x)", _model2);
+ int buf_used_len = os::snprintf_checked(buf, sizeof(buf), "0x%02x:0x%x:0x%03x:%d", _cpu, _variant, _model, _revision);
+ if (_model2) os::snprintf_checked(buf + buf_used_len, sizeof(buf) - buf_used_len, "(0x%03x)", _model2);
#define ADD_FEATURE_IF_SUPPORTED(id, name, bit) if (VM_Version::supports_##name()) strcat(buf, ", " #name);
CPU_FEATURE_FLAGS(ADD_FEATURE_IF_SUPPORTED)
#undef ADD_FEATURE_IF_SUPPORTED
diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
index 04e9263b930..4a977d67a6e 100644
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, 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.
*
@@ -102,6 +102,14 @@ class VM_Version : public Abstract_VM_Version {
CPU_APPLE = 'a',
};
+enum Ampere_CPU_Model {
+ CPU_MODEL_EMAG = 0x0, /* CPU implementer is CPU_AMCC */
+ CPU_MODEL_ALTRA = 0xd0c, /* CPU implementer is CPU_ARM, Neoverse N1 */
+ CPU_MODEL_ALTRAMAX = 0xd0c, /* CPU implementer is CPU_ARM, Neoverse N1 */
+ CPU_MODEL_AMPERE_1 = 0xac3, /* CPU implementer is CPU_AMPERE */
+ CPU_MODEL_AMPERE_1A = 0xac4 /* CPU implementer is CPU_AMPERE */
+};
+
#define CPU_FEATURE_FLAGS(decl) \
decl(FP, fp, 0) \
decl(ASIMD, asimd, 1) \
diff --git a/src/hotspot/cpu/aarch64/vmstorage_aarch64.hpp b/src/hotspot/cpu/aarch64/vmstorage_aarch64.hpp
new file mode 100644
index 00000000000..7c6d34c802f
--- /dev/null
+++ b/src/hotspot/cpu/aarch64/vmstorage_aarch64.hpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef CPU_AARCH64_VMSTORAGE_AARCH64_INLINE_HPP
+#define CPU_AARCH64_VMSTORAGE_AARCH64_INLINE_HPP
+
+#include
+
+#include "asm/register.hpp"
+
+// keep in sync with jdk/internal/foreign/abi/aarch64/AArch64Architecture
+enum class StorageType : int8_t {
+ INTEGER = 0,
+ VECTOR = 1,
+ STACK = 2,
+ PLACEHOLDER = 3,
+// special locations used only by native code
+ FRAME_DATA = PLACEHOLDER + 1,
+ INVALID = -1
+};
+
+// need to define this before constructing VMStorage (below)
+constexpr inline bool VMStorage::is_reg(StorageType type) {
+ return type == StorageType::INTEGER || type == StorageType::VECTOR;
+}
+constexpr inline StorageType VMStorage::stack_type() { return StorageType::STACK; }
+constexpr inline StorageType VMStorage::placeholder_type() { return StorageType::PLACEHOLDER; }
+constexpr inline StorageType VMStorage::frame_data_type() { return StorageType::FRAME_DATA; }
+
+constexpr uint16_t REG64_MASK = 0b0000000000000001;
+constexpr uint16_t V128_MASK = 0b0000000000000001;
+
+inline Register as_Register(VMStorage vms) {
+ assert(vms.type() == StorageType::INTEGER, "not the right type");
+ return ::as_Register(vms.index());
+}
+
+inline FloatRegister as_FloatRegister(VMStorage vms) {
+ assert(vms.type() == StorageType::VECTOR, "not the right type");
+ return ::as_FloatRegister(vms.index());
+}
+
+constexpr inline VMStorage as_VMStorage(Register reg) {
+ return VMStorage::reg_storage(StorageType::INTEGER, REG64_MASK, reg->encoding());
+}
+
+constexpr inline VMStorage as_VMStorage(FloatRegister reg) {
+ return VMStorage::reg_storage(StorageType::VECTOR, V128_MASK, reg->encoding());
+}
+
+inline VMStorage as_VMStorage(VMReg reg) {
+ if (reg->is_Register()) {
+ return as_VMStorage(reg->as_Register());
+ } else if (reg->is_FloatRegister()) {
+ return as_VMStorage(reg->as_FloatRegister());
+ } else if (reg->is_stack()) {
+ return VMStorage::stack_storage(reg);
+ } else if (!reg->is_valid()) {
+ return VMStorage::invalid();
+ }
+
+ ShouldNotReachHere();
+ return VMStorage::invalid();
+}
+
+#endif // CPU_AARCH64_VMSTORAGE_AARCH64_INLINE_HPP
\ No newline at end of file
diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad
index ecd1c850ae4..acdbb632534 100644
--- a/src/hotspot/cpu/arm/arm.ad
+++ b/src/hotspot/cpu/arm/arm.ad
@@ -59,6 +59,9 @@ source_hpp %{
// To keep related declarations/definitions/uses close together,
// we switch between source %{ }% and source_hpp %{ }% freely as needed.
+#include "asm/macroAssembler.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
+
// Does destination need to be loaded in a register then passed to a
// branch instruction?
extern bool maybe_far_call(const CallNode *n);
@@ -286,6 +289,17 @@ void MachPrologNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
if (framesize != 0) {
st->print ("SUB R_SP, R_SP, " SIZE_FORMAT,framesize);
}
+
+ if (C->stub_function() == NULL && BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) {
+ st->print("ldr t0, [guard]\n\t");
+ st->print("ldr t1, [Rthread, #thread_disarmed_guard_value_offset]\n\t");
+ st->print("cmp t0, t1\n\t");
+ st->print("beq skip\n\t");
+ st->print("blr #nmethod_entry_barrier_stub\n\t");
+ st->print("b skip\n\t");
+ st->print("guard: int\n\t");
+ st->print("skip:\n\t");
+ }
}
#endif
@@ -318,6 +332,11 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
__ sub_slow(SP, SP, framesize);
}
+ if (C->stub_function() == NULL) {
+ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->nmethod_entry_barrier(&_masm);
+ }
+
// offset from scratch buffer is not valid
if (strcmp(cbuf.name(), "Compile::Fill_buffer") == 0) {
C->output()->set_frame_complete( __ offset() );
diff --git a/src/hotspot/cpu/arm/c1_Defs_arm.hpp b/src/hotspot/cpu/arm/c1_Defs_arm.hpp
index b8ed431891d..68b5449cd58 100644
--- a/src/hotspot/cpu/arm/c1_Defs_arm.hpp
+++ b/src/hotspot/cpu/arm/c1_Defs_arm.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -74,6 +74,10 @@ enum {
pd_float_saved_as_double = false
};
+enum {
+ pd_two_operand_lir_form = false
+};
+
#define PATCHED_ADDR (204)
#define CARDTABLEBARRIERSET_POST_BARRIER_HELPER
diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
index d6085b13e42..1e17d18b246 100644
--- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
+++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
@@ -25,6 +25,8 @@
#include "precompiled.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "c1/c1_Runtime1.hpp"
+#include "gc/shared/barrierSet.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/tlab_globals.hpp"
#include "interpreter/interpreter.hpp"
@@ -62,6 +64,10 @@ void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_by
// if this method contains a methodHandle call site
raw_push(FP, LR);
sub_slow(SP, SP, frame_size_in_bytes);
+
+ // Insert nmethod entry barrier into frame.
+ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->nmethod_entry_barrier(this);
}
void C1_MacroAssembler::remove_frame(int frame_size_in_bytes) {
diff --git a/src/hotspot/cpu/arm/c1_globals_arm.hpp b/src/hotspot/cpu/arm/c1_globals_arm.hpp
index 55917decc30..d22d39d6369 100644
--- a/src/hotspot/cpu/arm/c1_globals_arm.hpp
+++ b/src/hotspot/cpu/arm/c1_globals_arm.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -61,6 +61,5 @@ define_pd_global(bool, UseTypeProfile, false);
define_pd_global(bool, OptimizeSinglePrecision, true);
define_pd_global(bool, CSEArrayLength, true);
-define_pd_global(bool, TwoOperandLIRForm, false);
#endif // CPU_ARM_C1_GLOBALS_ARM_HPP
diff --git a/src/hotspot/cpu/arm/continuationFreezeThaw_arm.inline.hpp b/src/hotspot/cpu/arm/continuationFreezeThaw_arm.inline.hpp
index c166ca72254..f79a22751c1 100644
--- a/src/hotspot/cpu/arm/continuationFreezeThaw_arm.inline.hpp
+++ b/src/hotspot/cpu/arm/continuationFreezeThaw_arm.inline.hpp
@@ -87,10 +87,6 @@ inline void ThawBase::patch_pd(frame& f, const frame& caller) {
Unimplemented();
}
-void ThawBase::patch_chunk_pd(intptr_t* sp) {
- Unimplemented();
-}
-
template
inline void Thaw::patch_caller_links(intptr_t* sp, intptr_t* bottom) {
Unimplemented();
diff --git a/src/hotspot/cpu/arm/downcallLinker_arm.cpp b/src/hotspot/cpu/arm/downcallLinker_arm.cpp
index af69f2a58a6..37b6f43ac14 100644
--- a/src/hotspot/cpu/arm/downcallLinker_arm.cpp
+++ b/src/hotspot/cpu/arm/downcallLinker_arm.cpp
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, Red Hat, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -29,9 +30,10 @@ RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature,
int num_args,
BasicType ret_bt,
const ABIDescriptor& abi,
- const GrowableArray& input_registers,
- const GrowableArray& output_registers,
- bool needs_return_buffer) {
+ const GrowableArray& input_registers,
+ const GrowableArray& output_registers,
+ bool needs_return_buffer,
+ int captured_state_mask) {
Unimplemented();
return nullptr;
}
diff --git a/src/hotspot/cpu/arm/foreignGlobals_arm.cpp b/src/hotspot/cpu/arm/foreignGlobals_arm.cpp
index 918e89f3ee6..5438cbe5cd6 100644
--- a/src/hotspot/cpu/arm/foreignGlobals_arm.cpp
+++ b/src/hotspot/cpu/arm/foreignGlobals_arm.cpp
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, Red Hat, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -33,24 +34,19 @@ const ABIDescriptor ForeignGlobals::parse_abi_descriptor(jobject jabi) {
return {};
}
-VMReg ForeignGlobals::vmstorage_to_vmreg(int type, int index) {
- Unimplemented();
- return VMRegImpl::Bad();
-}
-
-int RegSpiller::pd_reg_size(VMReg reg) {
+int RegSpiller::pd_reg_size(VMStorage reg) {
Unimplemented();
return -1;
}
-void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMReg reg) {
+void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMStorage reg) {
Unimplemented();
}
-void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMReg reg) {
+void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMStorage reg) {
Unimplemented();
}
-void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMReg tmp, int in_stk_bias, int out_stk_bias) const {
+void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMStorage tmp, int in_stk_bias, int out_stk_bias, const StubLocations& locs) const {
Unimplemented();
}
diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp
index e521cb9a75e..e9d1a0056b7 100644
--- a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp
+++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp
@@ -23,10 +23,13 @@
*/
#include "precompiled.hpp"
+#include "gc/shared/barrierSet.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
+#include "gc/shared/barrierSetNMethod.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "memory/universe.hpp"
#include "runtime/javaThread.hpp"
+#include "runtime/stubRoutines.hpp"
#define __ masm->
@@ -195,3 +198,47 @@ void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, RegisterOrC
// Unborrow the Rthread
__ sub(Rthread, Ralloc, in_bytes(JavaThread::allocated_bytes_offset()));
}
+
+void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) {
+
+ BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
+
+ Register tmp0 = Rtemp;
+ Register tmp1 = R5; // must be callee-save register
+
+ if (bs_nm == NULL) {
+ return;
+ }
+
+ // The are no GCs that require memory barrier on arm32 now
+#ifdef ASSERT
+ NMethodPatchingType patching_type = nmethod_patching_type();
+ assert(patching_type == NMethodPatchingType::stw_instruction_and_data_patch, "Unsupported patching type");
+#endif
+
+ Label skip, guard;
+ Address thread_disarmed_addr(Rthread, in_bytes(bs_nm->thread_disarmed_guard_value_offset()));
+
+ __ block_comment("nmethod_barrier begin");
+ __ ldr_label(tmp0, guard);
+
+ // No memory barrier here
+ __ ldr(tmp1, thread_disarmed_addr);
+ __ cmp(tmp0, tmp1);
+ __ b(skip, eq);
+
+ __ mov_address(tmp0, StubRoutines::Arm::method_entry_barrier());
+ __ call(tmp0);
+ __ b(skip);
+
+ __ bind(guard);
+
+ // nmethod guard value. Skipped over in common case.
+ //
+ // Put a debug value to make any offsets skew
+ // clearly visible in coredump
+ __ emit_int32(0xDEADBEAF);
+
+ __ bind(skip);
+ __ block_comment("nmethod_barrier end");
+}
diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp
index 6f100677a8c..37e0c6525f3 100644
--- a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp
+++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp
@@ -29,6 +29,10 @@
#include "memory/allocation.hpp"
#include "oops/access.hpp"
+enum class NMethodPatchingType {
+ stw_instruction_and_data_patch,
+};
+
class BarrierSetAssembler: public CHeapObj {
private:
void incr_allocated_bytes(MacroAssembler* masm,
@@ -56,6 +60,8 @@ class BarrierSetAssembler: public CHeapObj {
);
virtual void barrier_stubs_init() {}
+ virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::stw_instruction_and_data_patch; }
+ virtual void nmethod_entry_barrier(MacroAssembler* masm);
};
#endif // CPU_ARM_GC_SHARED_BARRIERSETASSEMBLER_ARM_HPP
diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp b/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp
index a0361ddc2f4..ed15cc5ebcf 100644
--- a/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp
+++ b/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp
@@ -23,18 +23,115 @@
*/
#include "precompiled.hpp"
+#include "code/nativeInst.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
+#include "logging/log.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/javaThread.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/registerMap.hpp"
+#include "utilities/align.hpp"
#include "utilities/debug.hpp"
+// The constant below reflects the size of the barrier
+// in barrierSetAssembler_arm.cpp
+static const int entry_barrier_bytes = 9 * NativeInstruction::size();
+
+class NativeNMethodBarrier: public NativeInstruction {
+ address instruction_address() const { return addr_at(0); }
+
+ int *guard_addr() const {
+ // Last instruction in a barrier
+ return reinterpret_cast(instruction_address() + entry_barrier_bytes - wordSize);
+ }
+
+public:
+ int get_value() {
+ return Atomic::load_acquire(guard_addr());
+ }
+
+ void set_value(int value) {
+ Atomic::release_store(guard_addr(), value);
+ }
+
+ void verify() const;
+};
+
+// Check the first instruction of the nmethod entry barrier
+// to make sure that the offsets are not skewed.
+void NativeNMethodBarrier::verify() const {
+ NativeInstruction *ni = (NativeInstruction *) instruction_address();
+ if (!ni->is_ldr()) {
+ uint32_t *addr = (uint32_t *) ni;
+ tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", (intptr_t) addr, (uint32_t) *addr);
+ fatal("not an ldr instruction.");
+ }
+}
+
+static NativeNMethodBarrier* native_nmethod_barrier(nmethod* nm) {
+ address barrier_address = nm->code_begin() + nm->frame_complete_offset() - entry_barrier_bytes;
+ NativeNMethodBarrier* barrier = reinterpret_cast(barrier_address);
+ debug_only(barrier->verify());
+ return barrier;
+}
+
+/* We're called from an nmethod when we need to deoptimize it. We do
+ this by throwing away the nmethod's frame and jumping to the
+ ic_miss stub. This looks like there has been an IC miss at the
+ entry of the nmethod, so we resolve the call, which will fall back
+ to the interpreter if the nmethod has been unloaded. */
void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
- ShouldNotReachHere();
+
+ typedef struct {
+ intptr_t *sp; intptr_t *fp; address lr; address pc;
+ } frame_pointers_t;
+
+ frame_pointers_t *new_frame = (frame_pointers_t *)(return_address_ptr - 5);
+
+ JavaThread *thread = JavaThread::current();
+ RegisterMap reg_map(thread,
+ RegisterMap::UpdateMap::skip,
+ RegisterMap::ProcessFrames::include,
+ RegisterMap::WalkContinuation::skip);
+ frame frame = thread->last_frame();
+
+ assert(frame.is_compiled_frame() || frame.is_native_frame(), "must be");
+ assert(frame.cb() == nm, "must be");
+ frame = frame.sender(®_map);
+
+ LogTarget(Trace, nmethod, barrier) out;
+ if (out.is_enabled()) {
+ ResourceMark mark;
+ log_trace(nmethod, barrier)("deoptimize(nmethod: %s(%p), return_addr: %p, osr: %d, thread: %p(%s), making rsp: %p) -> %p",
+ nm->method()->name_and_sig_as_C_string(),
+ nm, *(address *) return_address_ptr, nm->is_osr_method(), thread,
+ thread->name(), frame.sp(), nm->verified_entry_point());
+ }
+
+ new_frame->sp = frame.sp();
+ new_frame->fp = frame.fp();
+ new_frame->lr = frame.pc();
+ new_frame->pc = SharedRuntime::get_handle_wrong_method_stub();
}
-void BarrierSetNMethod::disarm(nmethod* nm) {
- ShouldNotReachHere();
+void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) {
+ if (!supports_entry_barrier(nm)) {
+ return;
+ }
+
+ // Disarms the nmethod guard emitted by BarrierSetAssembler::nmethod_entry_barrier.
+ // Symmetric "LDR; DMB ISHLD" is in the nmethod barrier.
+ NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
+ barrier->set_value(value);
}
-bool BarrierSetNMethod::is_armed(nmethod* nm) {
- ShouldNotReachHere();
- return false;
+int BarrierSetNMethod::guard_value(nmethod* nm) {
+ if (!supports_entry_barrier(nm)) {
+ return disarmed_guard_value();
+ }
+
+ NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
+ return barrier->get_value();
}
diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.cpp b/src/hotspot/cpu/arm/macroAssembler_arm.cpp
index 1c7ae0f54f3..8744ac6dedd 100644
--- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp
+++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp
@@ -1643,7 +1643,7 @@ void MacroAssembler::store_heap_oop_null(Address obj, Register new_val, Register
void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators,
Address src, Register dst, Register tmp1, Register tmp2, Register tmp3) {
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
- decorators = AccessInternal::decorator_fixup(decorators);
+ decorators = AccessInternal::decorator_fixup(decorators, type);
bool as_raw = (decorators & AS_RAW) != 0;
if (as_raw) {
bs->BarrierSetAssembler::load_at(this, decorators, type, dst, src, tmp1, tmp2, tmp3);
@@ -1655,7 +1655,7 @@ void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators,
void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators,
Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null) {
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
- decorators = AccessInternal::decorator_fixup(decorators);
+ decorators = AccessInternal::decorator_fixup(decorators, type);
bool as_raw = (decorators & AS_RAW) != 0;
if (as_raw) {
bs->BarrierSetAssembler::store_at(this, decorators, type, obj, new_val, tmp1, tmp2, tmp3, is_null);
diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.hpp b/src/hotspot/cpu/arm/macroAssembler_arm.hpp
index 73e2f2c0d17..50b56bfe79a 100644
--- a/src/hotspot/cpu/arm/macroAssembler_arm.hpp
+++ b/src/hotspot/cpu/arm/macroAssembler_arm.hpp
@@ -587,9 +587,23 @@ class MacroAssembler: public Assembler {
AbstractAssembler::emit_address((address)L.data());
}
+ void ldr_label(Register rd, Label& L) {
+ ldr(rd, Address(PC, target(L) - pc() - 8));
+ }
+
void resolve_oop_handle(Register result);
void load_mirror(Register mirror, Register method, Register tmp);
+ void enter() {
+ raw_push(FP, LR);
+ mov(FP, SP);
+ }
+
+ void leave() {
+ mov(SP, FP);
+ raw_pop(FP, LR);
+ }
+
#define ARM_INSTR_1(common_mnemonic, arm32_mnemonic, arg_type) \
void common_mnemonic(arg_type arg) { \
arm32_mnemonic(arg); \
diff --git a/src/hotspot/cpu/arm/matcher_arm.hpp b/src/hotspot/cpu/arm/matcher_arm.hpp
index 3959d61e71c..1e8f7683e76 100644
--- a/src/hotspot/cpu/arm/matcher_arm.hpp
+++ b/src/hotspot/cpu/arm/matcher_arm.hpp
@@ -155,6 +155,16 @@
// Implements a variant of EncodeISOArrayNode that encode ASCII only
static const bool supports_encode_ascii_array = false;
+ // Some architecture needs a helper to check for alltrue vector
+ static constexpr bool vectortest_needs_second_argument(bool is_alltrue, bool is_predicate) {
+ return false;
+ }
+
+ // BoolTest mask for vector test intrinsics
+ static constexpr BoolTest::mask vectortest_mask(bool is_alltrue, bool is_predicate, int vlen) {
+ return BoolTest::illegal;
+ }
+
// Returns pre-selection estimated size of a vector operation.
static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) {
switch(vopc) {
diff --git a/src/hotspot/cpu/arm/nativeInst_arm_32.hpp b/src/hotspot/cpu/arm/nativeInst_arm_32.hpp
index 0c9e157c553..62419a1ddf5 100644
--- a/src/hotspot/cpu/arm/nativeInst_arm_32.hpp
+++ b/src/hotspot/cpu/arm/nativeInst_arm_32.hpp
@@ -77,9 +77,12 @@ class RawNativeInstruction {
address instruction_address() const { return addr_at(0); }
address next_raw_instruction_address() const { return addr_at(instruction_size); }
+ static int size() { return instruction_size; }
+
static RawNativeInstruction* at(address address) {
return (RawNativeInstruction*)address;
}
+
RawNativeInstruction* next_raw() const {
return at(next_raw_instruction_address());
}
diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
index ab0e79d95c1..56dcc8a1903 100644
--- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
+++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
@@ -28,6 +28,7 @@
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "compiler/oopMap.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/interpreter.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
@@ -873,6 +874,10 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
__ mov(FP, SP);
__ sub_slow(SP, SP, stack_size - 2*wordSize);
+ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ assert(bs != NULL, "Sanity");
+ bs->nmethod_entry_barrier(masm);
+
int frame_complete = __ pc() - start;
OopMapSet* oop_maps = new OopMapSet();
diff --git a/src/hotspot/cpu/arm/stackChunkFrameStream_arm.inline.hpp b/src/hotspot/cpu/arm/stackChunkFrameStream_arm.inline.hpp
index b3c2714037c..218f5841181 100644
--- a/src/hotspot/cpu/arm/stackChunkFrameStream_arm.inline.hpp
+++ b/src/hotspot/cpu/arm/stackChunkFrameStream_arm.inline.hpp
@@ -67,12 +67,6 @@ inline intptr_t* StackChunkFrameStream::unextended_sp_for_interprete
return NULL;
}
-template
-intptr_t* StackChunkFrameStream::next_sp_for_interpreter_frame() const {
- Unimplemented();
- return NULL;
-}
-
template
inline void StackChunkFrameStream::next_for_interpreter_frame() {
Unimplemented();
diff --git a/src/hotspot/cpu/arm/stubGenerator_arm.cpp b/src/hotspot/cpu/arm/stubGenerator_arm.cpp
index 85227dbb8e8..d5204915619 100644
--- a/src/hotspot/cpu/arm/stubGenerator_arm.cpp
+++ b/src/hotspot/cpu/arm/stubGenerator_arm.cpp
@@ -27,6 +27,7 @@
#include "compiler/oopMap.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
+#include "gc/shared/barrierSetNMethod.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/universe.hpp"
#include "nativeInst_arm.hpp"
@@ -2905,6 +2906,53 @@ class StubGenerator: public StubCodeGenerator {
}
+ address generate_method_entry_barrier() {
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "nmethod_entry_barrier");
+
+ Label deoptimize_label;
+
+ address start = __ pc();
+
+ // No need to save PC on Arm
+ __ set_last_Java_frame(SP, FP, false, Rtemp);
+
+ __ enter();
+
+ __ add(Rtemp, SP, wordSize); // Rtemp points to the saved lr
+ __ sub(SP, SP, 4 * wordSize); // four words for the returned {sp, fp, lr, pc}
+
+ const RegisterSet saved_regs = RegisterSet(R0, R10);
+ __ push(saved_regs);
+ __ fpush(FloatRegisterSet(D0, 16));
+
+ __ mov(c_rarg0, Rtemp);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetNMethod::nmethod_stub_entry_barrier), c_rarg0);
+
+ __ reset_last_Java_frame(Rtemp);
+
+ __ mov(Rtemp, R0);
+
+ __ fpop(FloatRegisterSet(D0, 16));
+ __ pop(saved_regs);
+
+ __ cbnz(Rtemp, deoptimize_label);
+
+ __ leave();
+ __ bx(LR);
+
+ __ BIND(deoptimize_label);
+
+ __ ldr(Rtemp, Address(SP, 0));
+ __ ldr(FP, Address(SP, wordSize));
+ __ ldr(LR, Address(SP, wordSize * 2));
+ __ ldr(R5, Address(SP, wordSize * 3));
+ __ mov(SP, Rtemp);
+ __ bx(R5);
+
+ return start;
+ }
+
#define COMPILE_CRYPTO
#include "stubRoutinesCrypto_arm.cpp"
@@ -3097,6 +3145,11 @@ class StubGenerator: public StubCodeGenerator {
// arraycopy stubs used by compilers
generate_arraycopy_stubs();
+ BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
+ if (bs_nm != NULL) {
+ StubRoutines::Arm::_method_entry_barrier = generate_method_entry_barrier();
+ }
+
#ifdef COMPILE_CRYPTO
// generate AES intrinsics code
if (UseAESIntrinsics) {
diff --git a/src/hotspot/cpu/arm/stubRoutines_arm.cpp b/src/hotspot/cpu/arm/stubRoutines_arm.cpp
index 6ae6d1fe8d1..98280862e98 100644
--- a/src/hotspot/cpu/arm/stubRoutines_arm.cpp
+++ b/src/hotspot/cpu/arm/stubRoutines_arm.cpp
@@ -33,3 +33,5 @@ address StubRoutines::Arm::_partial_subtype_check = NULL;
address StubRoutines::_atomic_load_long_entry = NULL;
address StubRoutines::_atomic_store_long_entry = NULL;
+
+address StubRoutines::Arm::_method_entry_barrier = NULL;
diff --git a/src/hotspot/cpu/arm/stubRoutines_arm.hpp b/src/hotspot/cpu/arm/stubRoutines_arm.hpp
index c21c08f3e54..2a46e254ee2 100644
--- a/src/hotspot/cpu/arm/stubRoutines_arm.hpp
+++ b/src/hotspot/cpu/arm/stubRoutines_arm.hpp
@@ -42,11 +42,13 @@ class Arm {
static address _idiv_irem_entry;
static address _partial_subtype_check;
+ static address _method_entry_barrier;
public:
static address idiv_irem_entry() { return _idiv_irem_entry; }
static address partial_subtype_check() { return _partial_subtype_check; }
+ static address method_entry_barrier() { return _method_entry_barrier; }
};
static bool returns_to_call_stub(address return_pc) {
diff --git a/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersDiscarding.java b/src/hotspot/cpu/arm/vmstorage_arm.hpp
similarity index 52%
rename from test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersDiscarding.java
rename to src/hotspot/cpu/arm/vmstorage_arm.hpp
index 640000a8efc..fda9ceac0a6 100644
--- a/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersDiscarding.java
+++ b/src/hotspot/cpu/arm/vmstorage_arm.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -21,29 +21,32 @@
* questions.
*/
-import org.reactivestreams.tck.TestEnvironment;
-import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+#ifndef CPU_ARM_VMSTORAGE_ARM_INLINE_HPP
+#define CPU_ARM_VMSTORAGE_ARM_INLINE_HPP
-import java.net.http.HttpResponse.BodySubscribers;
-import java.nio.ByteBuffer;
-import java.util.List;
-import java.util.concurrent.Flow.Subscriber;
+#include
-/* See TckDriver.java for more information */
-public class BodySubscribersDiscarding
- extends FlowSubscriberBlackboxVerification> {
+#include "asm/register.hpp"
- public BodySubscribersDiscarding() {
- super(new TestEnvironment(450L));
- }
+enum class StorageType : int8_t {
+ STACK = 0,
+ PLACEHOLDER = 1,
+// special locations used only by native code
+ FRAME_DATA = PLACEHOLDER + 1,
+ INVALID = -1
+};
- @Override
- public Subscriber> createFlowSubscriber() {
- return BodySubscribers.discarding();
- }
+// need to define this before constructing VMStorage (below)
+constexpr inline bool VMStorage::is_reg(StorageType type) {
+ return false;
+}
+constexpr inline StorageType VMStorage::stack_type() { return StorageType::STACK; }
+constexpr inline StorageType VMStorage::placeholder_type() { return StorageType::PLACEHOLDER; }
+constexpr inline StorageType VMStorage::frame_data_type() { return StorageType::FRAME_DATA; }
- @Override
- public List createElement(int element) {
- return S.listOfBuffersFromBufferOfNBytes(element % 17);
- }
+inline VMStorage as_VMStorage(VMReg reg) {
+ ShouldNotReachHere();
+ return VMStorage::invalid();
}
+
+#endif // CPU_ARM_VMSTORAGE_ARM_INLINE_HPP
\ No newline at end of file
diff --git a/src/hotspot/cpu/ppc/assembler_ppc.hpp b/src/hotspot/cpu/ppc/assembler_ppc.hpp
index d32f2cbee36..7ea6d8e5876 100644
--- a/src/hotspot/cpu/ppc/assembler_ppc.hpp
+++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp
@@ -95,7 +95,7 @@ class AddressLiteral {
protected:
// creation
- AddressLiteral() : _address(NULL), _rspec(NULL) {}
+ AddressLiteral() : _address(NULL), _rspec() {}
public:
AddressLiteral(address addr, RelocationHolder const& rspec)
diff --git a/src/hotspot/cpu/ppc/c1_Defs_ppc.hpp b/src/hotspot/cpu/ppc/c1_Defs_ppc.hpp
index 01d4ba39092..0d18d889da1 100644
--- a/src/hotspot/cpu/ppc/c1_Defs_ppc.hpp
+++ b/src/hotspot/cpu/ppc/c1_Defs_ppc.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -73,4 +73,8 @@ enum {
pd_float_saved_as_double = true
};
+enum {
+ pd_two_operand_lir_form = false
+};
+
#endif // CPU_PPC_C1_DEFS_PPC_HPP
diff --git a/src/hotspot/cpu/ppc/c1_globals_ppc.hpp b/src/hotspot/cpu/ppc/c1_globals_ppc.hpp
index af6db7555dd..23604b5c083 100644
--- a/src/hotspot/cpu/ppc/c1_globals_ppc.hpp
+++ b/src/hotspot/cpu/ppc/c1_globals_ppc.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2019 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -61,6 +61,5 @@ define_pd_global(bool, UseTypeProfile, false);
define_pd_global(bool, OptimizeSinglePrecision, false);
define_pd_global(bool, CSEArrayLength, true);
-define_pd_global(bool, TwoOperandLIRForm, false);
#endif // CPU_PPC_C1_GLOBALS_PPC_HPP
diff --git a/src/hotspot/cpu/ppc/c2_safepointPollStubTable_ppc.cpp b/src/hotspot/cpu/ppc/c2_CodeStubs_ppc.cpp
similarity index 80%
rename from src/hotspot/cpu/ppc/c2_safepointPollStubTable_ppc.cpp
rename to src/hotspot/cpu/ppc/c2_CodeStubs_ppc.cpp
index b65b91df1b8..f99f9e978cf 100644
--- a/src/hotspot/cpu/ppc/c2_safepointPollStubTable_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c2_CodeStubs_ppc.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2021 SAP SE. All rights reserved.
+ * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2022, SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,19 +24,22 @@
*/
#include "precompiled.hpp"
-#include "macroAssembler_ppc.inline.hpp"
-#include "opto/compile.hpp"
-#include "opto/node.hpp"
-#include "opto/output.hpp"
+#include "opto/c2_MacroAssembler.hpp"
+#include "opto/c2_CodeStubs.hpp"
#include "runtime/sharedRuntime.hpp"
#define __ masm.
-void C2SafepointPollStubTable::emit_stub_impl(MacroAssembler& masm, C2SafepointPollStub* entry) const {
+
+int C2SafepointPollStub::max_size() const {
+ return 56;
+}
+
+void C2SafepointPollStub::emit(C2_MacroAssembler& masm) {
assert(SharedRuntime::polling_page_return_handler_blob() != NULL,
"polling page return stub not created yet");
address stub = SharedRuntime::polling_page_return_handler_blob()->entry_point();
- __ bind(entry->_stub_label);
+ __ bind(entry());
// Using pc relative address computation.
{
Label next_pc;
@@ -45,7 +48,7 @@ void C2SafepointPollStubTable::emit_stub_impl(MacroAssembler& masm, C2SafepointP
}
int current_offset = __ offset();
// Code size should not depend on offset: see _stub_size computation in output.cpp
- __ load_const32(R12, entry->_safepoint_offset - current_offset);
+ __ load_const32(R12, _safepoint_offset - current_offset);
__ mflr(R0);
__ add(R12, R12, R0);
__ std(R12, in_bytes(JavaThread::saved_exception_pc_offset()), R16_thread);
diff --git a/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp b/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp
index 86afc73e286..13679cf6669 100644
--- a/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp
+++ b/src/hotspot/cpu/ppc/downcallLinker_ppc.cpp
@@ -30,9 +30,10 @@ RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature,
int num_args,
BasicType ret_bt,
const ABIDescriptor& abi,
- const GrowableArray& input_registers,
- const GrowableArray& output_registers,
- bool needs_return_buffer) {
+ const GrowableArray& input_registers,
+ const GrowableArray& output_registers,
+ bool needs_return_buffer,
+ int captured_state_mask) {
Unimplemented();
return nullptr;
}
diff --git a/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp b/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp
index 53eb53ec7cb..b685023656d 100644
--- a/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp
+++ b/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp
@@ -35,24 +35,19 @@ const ABIDescriptor ForeignGlobals::parse_abi_descriptor(jobject jabi) {
return {};
}
-VMReg ForeignGlobals::vmstorage_to_vmreg(int type, int index) {
- Unimplemented();
- return VMRegImpl::Bad();
-}
-
-int RegSpiller::pd_reg_size(VMReg reg) {
+int RegSpiller::pd_reg_size(VMStorage reg) {
Unimplemented();
return -1;
}
-void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMReg reg) {
+void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMStorage reg) {
Unimplemented();
}
-void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMReg reg) {
+void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMStorage reg) {
Unimplemented();
}
-void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMReg tmp, int in_stk_bias, int out_stk_bias) const {
+void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMStorage tmp, int in_stk_bias, int out_stk_bias, const StubLocations& locs) const {
Unimplemented();
}
diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp
index 219e167ef60..9e871481090 100644
--- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp
@@ -163,7 +163,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Register t
__ load_const32(tmp, 0 /* Value is patched */); // 2 instructions
// Low order half of 64 bit value is currently used.
- __ ld(R0, in_bytes(bs_nm->thread_disarmed_offset()), R16_thread);
+ __ ld(R0, in_bytes(bs_nm->thread_disarmed_guard_value_offset()), R16_thread);
__ cmpw(CCR0, R0, tmp);
__ bnectrl(CCR0);
diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp
index 698953671f1..d1d0e5ab024 100644
--- a/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp
+++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp
@@ -118,29 +118,20 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
// Thus, there's nothing to do here.
}
-void BarrierSetNMethod::disarm(nmethod* nm) {
+void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) {
if (!supports_entry_barrier(nm)) {
return;
}
NativeNMethodBarrier* barrier = get_nmethod_barrier(nm);
- barrier->release_set_guard_value(disarmed_value());
+ barrier->release_set_guard_value(value);
}
-void BarrierSetNMethod::arm(nmethod* nm, int arm_value) {
+int BarrierSetNMethod::guard_value(nmethod* nm) {
if (!supports_entry_barrier(nm)) {
- return;
- }
-
- NativeNMethodBarrier* barrier = get_nmethod_barrier(nm);
- barrier->release_set_guard_value(arm_value);
-}
-
-bool BarrierSetNMethod::is_armed(nmethod* nm) {
- if (!supports_entry_barrier(nm)) {
- return false;
+ return disarmed_guard_value();
}
NativeNMethodBarrier* barrier = get_nmethod_barrier(nm);
- return barrier->get_guard_value() != disarmed_value();
+ return barrier->get_guard_value();
}
diff --git a/src/hotspot/cpu/ppc/globals_ppc.hpp b/src/hotspot/cpu/ppc/globals_ppc.hpp
index 44b321635e1..527e5f5b4da 100644
--- a/src/hotspot/cpu/ppc/globals_ppc.hpp
+++ b/src/hotspot/cpu/ppc/globals_ppc.hpp
@@ -54,7 +54,7 @@ define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES);
define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES);
define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES);
-define_pd_global(bool, VMContinuations, true);
+define_pd_global(bool, VMContinuations, AIX_ONLY(false) NOT_AIX(true));
// Use large code-entry alignment.
define_pd_global(uintx, CodeCacheSegmentSize, 128);
diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.inline.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.inline.hpp
index 5be76916b21..d4a08310dd9 100644
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.inline.hpp
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.inline.hpp
@@ -357,7 +357,7 @@ inline void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorat
ON_UNKNOWN_OOP_REF)) == 0, "unsupported decorator");
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bool as_raw = (decorators & AS_RAW) != 0;
- decorators = AccessInternal::decorator_fixup(decorators);
+ decorators = AccessInternal::decorator_fixup(decorators, type);
if (as_raw) {
bs->BarrierSetAssembler::store_at(this, decorators, type,
base, ind_or_offs, val,
@@ -377,7 +377,7 @@ inline void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorato
assert((decorators & ~(AS_RAW | IN_HEAP | IN_NATIVE | IS_ARRAY | IS_NOT_NULL |
ON_PHANTOM_OOP_REF | ON_WEAK_OOP_REF)) == 0, "unsupported decorator");
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
- decorators = AccessInternal::decorator_fixup(decorators);
+ decorators = AccessInternal::decorator_fixup(decorators, type);
bool as_raw = (decorators & AS_RAW) != 0;
if (as_raw) {
bs->BarrierSetAssembler::load_at(this, decorators, type,
diff --git a/src/hotspot/cpu/ppc/matcher_ppc.hpp b/src/hotspot/cpu/ppc/matcher_ppc.hpp
index 05e06a21b1c..f78cb2d7803 100644
--- a/src/hotspot/cpu/ppc/matcher_ppc.hpp
+++ b/src/hotspot/cpu/ppc/matcher_ppc.hpp
@@ -164,6 +164,16 @@
// Implements a variant of EncodeISOArrayNode that encode ASCII only
static const bool supports_encode_ascii_array = true;
+ // Some architecture needs a helper to check for alltrue vector
+ static constexpr bool vectortest_needs_second_argument(bool is_alltrue, bool is_predicate) {
+ return false;
+ }
+
+ // BoolTest mask for vector test intrinsics
+ static constexpr BoolTest::mask vectortest_mask(bool is_alltrue, bool is_predicate, int vlen) {
+ return BoolTest::illegal;
+ }
+
// Returns pre-selection estimated size of a vector operation.
static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) {
switch(vopc) {
diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad
index 296bf160089..17d0dfc4e34 100644
--- a/src/hotspot/cpu/ppc/ppc.ad
+++ b/src/hotspot/cpu/ppc/ppc.ad
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2012, 2022 SAP SE. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
@@ -982,6 +982,7 @@ source_hpp %{
source %{
+#include "opto/c2_CodeStubs.hpp"
#include "oops/klass.inline.hpp"
void PhaseOutput::pd_perform_mach_node_analysis() {
@@ -1616,7 +1617,9 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
Label dummy_label;
Label* code_stub = &dummy_label;
if (!UseSIGTRAP && !C->output()->in_scratch_emit_size()) {
- code_stub = &C->output()->safepoint_poll_table()->add_safepoint(__ offset());
+ C2SafepointPollStub* stub = new (C->comp_arena()) C2SafepointPollStub(__ offset());
+ C->output()->add_stub(stub);
+ code_stub = &stub->entry();
__ relocate(relocInfo::poll_return_type);
}
__ safepoint_poll(*code_stub, temp, true /* at_return */, true /* in_nmethod */);
@@ -6534,6 +6537,7 @@ instruct storeNKlass(memory dst, iRegN_P2N src) %{
// Store Pointer
instruct storeP(memoryAlg4 dst, iRegPsrc src) %{
match(Set dst (StoreP dst src));
+ predicate(n->as_Store()->barrier_data() == 0);
ins_cost(MEMORY_REF_COST);
format %{ "STD $src, $dst \t// ptr" %}
@@ -14374,6 +14378,12 @@ instruct safePoint_poll(iRegPdst poll) %{
// Call Java Static Instruction
+source %{
+
+#include "runtime/continuation.hpp"
+
+%}
+
// Schedulable version of call static node.
instruct CallStaticJavaDirect(method meth) %{
match(CallStaticJava);
diff --git a/src/hotspot/cpu/ppc/stackChunkFrameStream_ppc.inline.hpp b/src/hotspot/cpu/ppc/stackChunkFrameStream_ppc.inline.hpp
index 06b0f045f1c..e4489660f46 100644
--- a/src/hotspot/cpu/ppc/stackChunkFrameStream_ppc.inline.hpp
+++ b/src/hotspot/cpu/ppc/stackChunkFrameStream_ppc.inline.hpp
@@ -80,12 +80,6 @@ inline intptr_t* StackChunkFrameStream::unextended_sp_for_interprete
return derelativize(ijava_idx(esp)) + 1 - frame::metadata_words; // On PPC esp points to the next free slot
}
-template
-intptr_t* StackChunkFrameStream::next_sp_for_interpreter_frame() const {
- Unimplemented();
- return NULL;
-}
-
template
inline void StackChunkFrameStream::next_for_interpreter_frame() {
assert_is_interpreted_and_frame_type_mixed();
diff --git a/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersOfByteArray.java b/src/hotspot/cpu/ppc/vmstorage_ppc.hpp
similarity index 52%
rename from test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersOfByteArray.java
rename to src/hotspot/cpu/ppc/vmstorage_ppc.hpp
index 18991f63ddb..46efafebe0c 100644
--- a/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersOfByteArray.java
+++ b/src/hotspot/cpu/ppc/vmstorage_ppc.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -21,29 +21,32 @@
* questions.
*/
-import org.reactivestreams.tck.TestEnvironment;
-import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+#ifndef CPU_PPC_VMSTORAGE_PPC_INLINE_HPP
+#define CPU_PPC_VMSTORAGE_PPC_INLINE_HPP
-import java.net.http.HttpResponse.BodySubscribers;
-import java.nio.ByteBuffer;
-import java.util.List;
-import java.util.concurrent.Flow.Subscriber;
+#include
-/* See TckDriver.java for more information */
-public class BodySubscribersOfByteArray
- extends FlowSubscriberBlackboxVerification> {
+#include "asm/register.hpp"
- public BodySubscribersOfByteArray() {
- super(new TestEnvironment(450L));
- }
+enum class StorageType : int8_t {
+ STACK = 0,
+ PLACEHOLDER = 1,
+// special locations used only by native code
+ FRAME_DATA = PLACEHOLDER + 1,
+ INVALID = -1
+};
- @Override
- public Subscriber> createFlowSubscriber() {
- return BodySubscribers.ofByteArray();
- }
+// need to define this before constructing VMStorage (below)
+constexpr inline bool VMStorage::is_reg(StorageType type) {
+ return false;
+}
+constexpr inline StorageType VMStorage::stack_type() { return StorageType::STACK; }
+constexpr inline StorageType VMStorage::placeholder_type() { return StorageType::PLACEHOLDER; }
+constexpr inline StorageType VMStorage::frame_data_type() { return StorageType::FRAME_DATA; }
- @Override
- public List createElement(int element) {
- return S.listOfBuffersFromBufferOfNBytes(element % 17);
- }
+inline VMStorage as_VMStorage(VMReg reg) {
+ ShouldNotReachHere();
+ return VMStorage::invalid();
}
+
+#endif // CPU_PPC_VMSTORAGE_PPC_INLINE_HPP
\ No newline at end of file
diff --git a/src/hotspot/cpu/riscv/assembler_riscv.cpp b/src/hotspot/cpu/riscv/assembler_riscv.cpp
index 2fb75c802cf..6a581a4d081 100644
--- a/src/hotspot/cpu/riscv/assembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/assembler_riscv.cpp
@@ -40,8 +40,20 @@ int AbstractAssembler::code_fill_byte() {
return 0;
}
-Address::Address(address target, relocInfo::relocType rtype) : _base(noreg), _offset(0), _mode(literal) {
- _target = target;
+#ifdef ASSERT
+
+void Address::assert_is_literal() const {
+ assert(_mode == literal, "addressing mode is non-literal: %d", _mode);
+}
+
+void Address::assert_is_nonliteral() const {
+ assert(_mode != literal, "unexpected literal addressing mode");
+ assert(_mode != no_mode, "unexpected no_mode addressing mode");
+}
+
+#endif // ASSERT
+
+static RelocationHolder address_relocation(address target, relocInfo::relocType rtype) {
switch (rtype) {
case relocInfo::oop_type:
case relocInfo::metadata_type:
@@ -49,30 +61,29 @@ Address::Address(address target, relocInfo::relocType rtype) : _base(noreg), _of
// but in cases like icBuffer they are literals in the code stream that
// we don't have a section for. We use none so that we get a literal address
// which is always patchable.
- break;
+ return RelocationHolder::none;
case relocInfo::external_word_type:
- _rspec = external_word_Relocation::spec(target);
- break;
+ return external_word_Relocation::spec(target);
case relocInfo::internal_word_type:
- _rspec = internal_word_Relocation::spec(target);
- break;
+ return internal_word_Relocation::spec(target);
case relocInfo::opt_virtual_call_type:
- _rspec = opt_virtual_call_Relocation::spec();
- break;
+ return opt_virtual_call_Relocation::spec();
case relocInfo::static_call_type:
- _rspec = static_call_Relocation::spec();
- break;
+ return static_call_Relocation::spec();
case relocInfo::runtime_call_type:
- _rspec = runtime_call_Relocation::spec();
- break;
+ return runtime_call_Relocation::spec();
case relocInfo::poll_type:
case relocInfo::poll_return_type:
- _rspec = Relocation::spec_simple(rtype);
- break;
+ return Relocation::spec_simple(rtype);
case relocInfo::none:
- _rspec = RelocationHolder::none;
- break;
+ return RelocationHolder::none;
default:
ShouldNotReachHere();
+ return RelocationHolder::none;
}
}
+
+Address::Address(address target, relocInfo::relocType rtype) :
+ _mode(literal),
+ _literal(target, address_relocation(target, rtype))
+{}
diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp
index b381f727a83..b39366646c8 100644
--- a/src/hotspot/cpu/riscv/assembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp
@@ -30,6 +30,10 @@
#include "asm/register.hpp"
#include "assembler_riscv.inline.hpp"
#include "metaprogramming/enableIf.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+#include
#define XLEN 64
@@ -153,62 +157,128 @@ const FloatRegister g_FPArgReg[Argument::n_float_register_parameters_c] = {
class Address {
public:
- enum mode { no_mode, base_plus_offset, pcrel, literal };
+ enum mode { no_mode, base_plus_offset, literal };
private:
- Register _base;
- Register _index;
- int64_t _offset;
- enum mode _mode;
+ struct Nonliteral {
+ Nonliteral(Register base, Register index, int64_t offset)
+ : _base(base), _index(index), _offset(offset) {}
+ Register _base;
+ Register _index;
+ int64_t _offset;
+ };
+
+ struct Literal {
+ Literal(address target, const RelocationHolder& rspec)
+ : _target(target), _rspec(rspec) {}
+ // If the target is far we'll need to load the ea of this to a
+ // register to reach it. Otherwise if near we can do PC-relative
+ // addressing.
+ address _target;
+
+ RelocationHolder _rspec;
+ };
+
+ void assert_is_nonliteral() const NOT_DEBUG_RETURN;
+ void assert_is_literal() const NOT_DEBUG_RETURN;
- RelocationHolder _rspec;
+ // Discriminated union, based on _mode.
+ // - no_mode: uses dummy _nonliteral, for ease of copying.
+ // - literal: only _literal is used.
+ // - others: only _nonliteral is used.
+ enum mode _mode;
+ union {
+ Nonliteral _nonliteral;
+ Literal _literal;
+ };
- // If the target is far we'll need to load the ea of this to a
- // register to reach it. Otherwise if near we can do PC-relative
- // addressing.
- address _target;
+ // Helper for copy constructor and assignment operator.
+ // Copy mode-relevant part of a into this.
+ void copy_data(const Address& a) {
+ assert(_mode == a._mode, "precondition");
+ if (_mode == literal) {
+ new (&_literal) Literal(a._literal);
+ } else {
+ // non-literal mode or no_mode.
+ new (&_nonliteral) Nonliteral(a._nonliteral);
+ }
+ }
public:
- Address()
- : _base(noreg), _index(noreg), _offset(0), _mode(no_mode), _target(NULL) { }
+ // no_mode initializes _nonliteral for ease of copying.
+ Address() :
+ _mode(no_mode),
+ _nonliteral(noreg, noreg, 0)
+ {}
- Address(Register r)
- : _base(r), _index(noreg), _offset(0), _mode(base_plus_offset), _target(NULL) { }
+ Address(Register r) :
+ _mode(base_plus_offset),
+ _nonliteral(r, noreg, 0)
+ {}
template::value)>
- Address(Register r, T o)
- : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(NULL) {}
+ Address(Register r, T o) :
+ _mode(base_plus_offset),
+ _nonliteral(r, noreg, o)
+ {}
- Address(Register r, ByteSize disp)
- : Address(r, in_bytes(disp)) {}
+ Address(Register r, ByteSize disp) : Address(r, in_bytes(disp)) {}
- Address(address target, RelocationHolder const& rspec)
- : _base(noreg),
- _index(noreg),
- _offset(0),
- _mode(literal),
- _rspec(rspec),
- _target(target) { }
+ Address(address target, const RelocationHolder& rspec) :
+ _mode(literal),
+ _literal(target, rspec)
+ {}
Address(address target, relocInfo::relocType rtype = relocInfo::external_word_type);
+ Address(const Address& a) : _mode(a._mode) { copy_data(a); }
+
+ // Verify the value is trivially destructible regardless of mode, so our
+ // destructor can also be trivial, and so our assignment operator doesn't
+ // need to destruct the old value before copying over it.
+ static_assert(std::is_trivially_destructible::value, "must be");
+ static_assert(std::is_trivially_destructible::value, "must be");
+
+ Address& operator=(const Address& a) {
+ _mode = a._mode;
+ copy_data(a);
+ return *this;
+ }
+
+ ~Address() = default;
+
const Register base() const {
- guarantee((_mode == base_plus_offset | _mode == pcrel | _mode == literal), "wrong mode");
- return _base;
+ assert_is_nonliteral();
+ return _nonliteral._base;
}
+
long offset() const {
- return _offset;
+ assert_is_nonliteral();
+ return _nonliteral._offset;
}
+
Register index() const {
- return _index;
+ assert_is_nonliteral();
+ return _nonliteral._index;
}
+
mode getMode() const {
return _mode;
}
- bool uses(Register reg) const { return _base == reg; }
- const address target() const { return _target; }
- const RelocationHolder& rspec() const { return _rspec; }
+ bool uses(Register reg) const {
+ return base() == reg;
+ }
+
+ const address target() const {
+ assert_is_literal();
+ return _literal._target;
+ }
+
+ const RelocationHolder& rspec() const {
+ assert_is_literal();
+ return _literal._rspec;
+ }
};
// Convenience classes
@@ -728,6 +798,8 @@ enum operand_size { int8, int16, int32, uint32, int64 };
INSN(fsqrt_d, 0b1010011, 0b00000, 0b0101101);
INSN(fcvt_s_d, 0b1010011, 0b00001, 0b0100000);
INSN(fcvt_d_s, 0b1010011, 0b00000, 0b0100001);
+ INSN(fcvt_s_h, 0b1010011, 0b00010, 0b0100000);
+ INSN(fcvt_h_s, 0b1010011, 0b00000, 0b0100010);
#undef INSN
// Immediate Instruction
@@ -984,6 +1056,7 @@ enum operand_size { int8, int16, int32, uint32, int64 };
INSN(fmv_w_x, 0b1010011, 0b000, 0b00000, 0b1111000);
INSN(fmv_d_x, 0b1010011, 0b000, 0b00000, 0b1111001);
+ INSN(fmv_h_x, 0b1010011, 0b000, 0b00000, 0b1111010);
#undef INSN
@@ -1004,6 +1077,7 @@ enum operand_size { int8, int16, int32, uint32, int64 };
INSN(fclass_d, 0b1010011, 0b001, 0b00000, 0b1110001);
INSN(fmv_x_w, 0b1010011, 0b000, 0b00000, 0b1110000);
INSN(fmv_x_d, 0b1010011, 0b000, 0b00000, 0b1110001);
+ INSN(fmv_x_h, 0b1010011, 0b000, 0b00000, 0b1110010);
#undef INSN
@@ -1670,7 +1744,7 @@ enum Nf {
// ====================================
// RISC-V Bit-Manipulation Extension
-// Currently only support Zba and Zbb bitmanip extensions.
+// Currently only support Zba, Zbb and Zbs bitmanip extensions.
// ====================================
#define INSN(NAME, op, funct3, funct7) \
void NAME(Register Rd, Register Rs1, Register Rs2) { \
@@ -1745,6 +1819,7 @@ enum Nf {
INSN(rori, 0b0010011, 0b101, 0b011000);
INSN(slli_uw, 0b0011011, 0b001, 0b000010);
+ INSN(bexti, 0b0010011, 0b101, 0b010010);
#undef INSN
diff --git a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp
index b241a753050..197216d6eca 100644
--- a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp
@@ -43,7 +43,9 @@ void C1SafepointPollStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
InternalAddress safepoint_pc(__ pc() - __ offset() + safepoint_offset());
__ relocate(safepoint_pc.rspec(), [&] {
- __ la(t0, safepoint_pc.target());
+ int32_t offset;
+ __ la_patchable(t0, safepoint_pc.target(), offset);
+ __ addi(t0, t0, offset);
});
__ sd(t0, Address(xthread, JavaThread::saved_exception_pc_offset()));
diff --git a/src/hotspot/cpu/riscv/c1_Defs_riscv.hpp b/src/hotspot/cpu/riscv/c1_Defs_riscv.hpp
index 9e132a52699..967bfc9d539 100644
--- a/src/hotspot/cpu/riscv/c1_Defs_riscv.hpp
+++ b/src/hotspot/cpu/riscv/c1_Defs_riscv.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -81,4 +81,8 @@ enum {
pd_float_saved_as_double = false
};
+enum {
+ pd_two_operand_lir_form = false
+};
+
#endif // CPU_RISCV_C1_DEFS_RISCV_HPP
diff --git a/src/hotspot/cpu/riscv/c1_globals_riscv.hpp b/src/hotspot/cpu/riscv/c1_globals_riscv.hpp
index fe46f7b21c8..311405dbc2b 100644
--- a/src/hotspot/cpu/riscv/c1_globals_riscv.hpp
+++ b/src/hotspot/cpu/riscv/c1_globals_riscv.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -60,6 +60,5 @@ define_pd_global(bool, UseTypeProfile, false);
define_pd_global(bool, OptimizeSinglePrecision, true );
define_pd_global(bool, CSEArrayLength, false);
-define_pd_global(bool, TwoOperandLIRForm, false);
#endif // CPU_RISCV_C1_GLOBALS_RISCV_HPP
diff --git a/src/hotspot/cpu/riscv/c2_safepointPollStubTable_riscv.cpp b/src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp
similarity index 59%
rename from src/hotspot/cpu/riscv/c2_safepointPollStubTable_riscv.cpp
rename to src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp
index d22a6a75843..4ddd6f3c2c3 100644
--- a/src/hotspot/cpu/riscv/c2_safepointPollStubTable_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -24,25 +24,52 @@
*/
#include "precompiled.hpp"
-#include "asm/macroAssembler.hpp"
-#include "opto/compile.hpp"
-#include "opto/node.hpp"
-#include "opto/output.hpp"
+#include "opto/c2_CodeStubs.hpp"
+#include "opto/c2_MacroAssembler.hpp"
#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
#define __ masm.
-void C2SafepointPollStubTable::emit_stub_impl(MacroAssembler& masm, C2SafepointPollStub* entry) const {
+
+int C2SafepointPollStub::max_size() const {
+ return 13 * 4;
+}
+
+void C2SafepointPollStub::emit(C2_MacroAssembler& masm) {
assert(SharedRuntime::polling_page_return_handler_blob() != NULL,
"polling page return stub not created yet");
address stub = SharedRuntime::polling_page_return_handler_blob()->entry_point();
RuntimeAddress callback_addr(stub);
- __ bind(entry->_stub_label);
- InternalAddress safepoint_pc(__ pc() - __ offset() + entry->_safepoint_offset);
+ __ bind(entry());
+ InternalAddress safepoint_pc(__ pc() - __ offset() + _safepoint_offset);
__ relocate(safepoint_pc.rspec(), [&] {
- __ la(t0, safepoint_pc.target());
+ int32_t offset;
+ __ la_patchable(t0, safepoint_pc.target(), offset);
+ __ addi(t0, t0, offset);
});
__ sd(t0, Address(xthread, JavaThread::saved_exception_pc_offset()));
__ far_jump(callback_addr);
}
+
+int C2EntryBarrierStub::max_size() const {
+ // 4 bytes for alignment
+ return 8 * 4 + 4;
+}
+
+void C2EntryBarrierStub::emit(C2_MacroAssembler& masm) {
+ __ bind(entry());
+
+ int32_t offset = 0;
+ __ movptr(t0, StubRoutines::riscv::method_entry_barrier(), offset);
+ __ jalr(ra, t0, offset);
+ __ j(continuation());
+
+ // make guard value 4-byte aligned so that it can be accessed by atomic instructions on RISC-V
+ __ align(4);
+ __ bind(guard());
+ __ relocate(entry_guard_Relocation::spec());
+ __ emit_int32(0); // nmethod guard value
+}
+
#undef __
diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
index e4c892280d6..09c4274a84b 100644
--- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2023, 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.
*
@@ -243,37 +243,6 @@ void C2_MacroAssembler::string_indexof_char(Register str1, Register cnt1,
typedef void (MacroAssembler::* load_chr_insn)(Register rd, const Address &adr, Register temp);
-void C2_MacroAssembler::emit_entry_barrier_stub(C2EntryBarrierStub* stub) {
- IncompressibleRegion ir(this); // Fixed length: see C2_MacroAssembler::entry_barrier_stub_size()
-
- // make guard value 4-byte aligned so that it can be accessed by atomic instructions on riscv
- int alignment_bytes = align(4);
-
- bind(stub->slow_path());
-
- int32_t offset = 0;
- movptr(t0, StubRoutines::riscv::method_entry_barrier(), offset);
- jalr(ra, t0, offset);
- j(stub->continuation());
-
- bind(stub->guard());
- relocate(entry_guard_Relocation::spec());
- assert_alignment(pc());
- emit_int32(0); // nmethod guard value
- // make sure the stub with a fixed code size
- if (alignment_bytes == 2) {
- assert(UseRVC, "bad alignment");
- c_nop();
- } else {
- assert(alignment_bytes == 0, "bad alignment");
- nop();
- }
-}
-
-int C2_MacroAssembler::entry_barrier_stub_size() {
- return 8 * 4 + 4; // 4 bytes for alignment margin
-}
-
// Search for needle in haystack and return index or -1
// x10: result
// x11: haystack
@@ -593,7 +562,12 @@ void C2_MacroAssembler::string_indexof(Register haystack, Register needle,
stub = RuntimeAddress(StubRoutines::riscv::string_indexof_linear_uu());
assert(stub.target() != NULL, "string_indexof_linear_uu stub has not been generated");
}
- trampoline_call(stub);
+ address call = trampoline_call(stub);
+ if (call == nullptr) {
+ DEBUG_ONLY(reset_labels(LINEARSEARCH, DONE, NOMATCH));
+ ciEnv::current()->record_failure("CodeCache is full");
+ return;
+ }
j(DONE);
bind(NOMATCH);
@@ -996,7 +970,12 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2,
ShouldNotReachHere();
}
assert(stub.target() != NULL, "compare_long_string stub has not been generated");
- trampoline_call(stub);
+ address call = trampoline_call(stub);
+ if (call == nullptr) {
+ DEBUG_ONLY(reset_labels(DONE, SHORT_LOOP, SHORT_STRING, SHORT_LAST, SHORT_LOOP_TAIL, SHORT_LAST2, SHORT_LAST_INIT, SHORT_LOOP_START));
+ ciEnv::current()->record_failure("CodeCache is full");
+ return;
+ }
j(DONE);
bind(SHORT_STRING);
@@ -1726,4 +1705,4 @@ void C2_MacroAssembler::rvv_reduce_integral(Register dst, VectorRegister tmp,
}
vmv_x_s(dst, tmp);
-}
\ No newline at end of file
+}
diff --git a/src/hotspot/cpu/riscv/codeBuffer_riscv.cpp b/src/hotspot/cpu/riscv/codeBuffer_riscv.cpp
index b4746649f19..eedaff87b2c 100644
--- a/src/hotspot/cpu/riscv/codeBuffer_riscv.cpp
+++ b/src/hotspot/cpu/riscv/codeBuffer_riscv.cpp
@@ -53,7 +53,14 @@ static bool emit_shared_trampolines(CodeBuffer* cb, CodeBuffer::SharedTrampoline
bool p_succeeded = true;
auto emit = [&](address dest, const CodeBuffer::Offsets &offsets) {
masm.set_code_section(cb->stubs());
- masm.align(wordSize, NativeCallTrampolineStub::data_offset);
+ if (!is_aligned(masm.offset() + NativeCallTrampolineStub::data_offset, wordSize)) {
+ if (cb->stubs()->maybe_expand_to_ensure_remaining(NativeInstruction::instruction_size) && cb->blob() == NULL) {
+ ciEnv::current()->record_failure("CodeCache is full");
+ p_succeeded = false;
+ return p_succeeded;
+ }
+ masm.align(wordSize, NativeCallTrampolineStub::data_offset);
+ }
LinkedListIterator it(offsets.head());
int offset = *it.next();
diff --git a/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp b/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp
index 9f69f681ba3..7863cbe6415 100644
--- a/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp
+++ b/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp
@@ -199,11 +199,6 @@ inline void ThawBase::prefetch_chunk_pd(void* start, int size) {
Prefetch::read(start, size - 64);
}
-void ThawBase::patch_chunk_pd(intptr_t* sp) {
- intptr_t* fp = _cont.entryFP();
- *(intptr_t**)(sp - 2) = fp;
-}
-
template
inline void Thaw::patch_caller_links(intptr_t* sp, intptr_t* bottom) {
// Fast path depends on !PreserveFramePointer. See can_thaw_fast().
diff --git a/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp b/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp
index 9bd1f8002db..7d757e75180 100644
--- a/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp
+++ b/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp
@@ -31,9 +31,10 @@ RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature,
int num_args,
BasicType ret_bt,
const ABIDescriptor& abi,
- const GrowableArray& input_registers,
- const GrowableArray& output_registers,
- bool needs_return_buffer) {
+ const GrowableArray& input_registers,
+ const GrowableArray& output_registers,
+ bool needs_return_buffer,
+ int captured_state_mask) {
Unimplemented();
return nullptr;
}
diff --git a/src/hotspot/cpu/riscv/foreignGlobals_riscv.cpp b/src/hotspot/cpu/riscv/foreignGlobals_riscv.cpp
index a239ed40df3..aefbb56a491 100644
--- a/src/hotspot/cpu/riscv/foreignGlobals_riscv.cpp
+++ b/src/hotspot/cpu/riscv/foreignGlobals_riscv.cpp
@@ -35,25 +35,19 @@ const ABIDescriptor ForeignGlobals::parse_abi_descriptor(jobject jabi) {
return {};
}
-VMReg ForeignGlobals::vmstorage_to_vmreg(int type, int index) {
- Unimplemented();
- return VMRegImpl::Bad();
-}
-
-int RegSpiller::pd_reg_size(VMReg reg) {
+int RegSpiller::pd_reg_size(VMStorage reg) {
Unimplemented();
return -1;
}
-void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMReg reg) {
+void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMStorage reg) {
Unimplemented();
}
-void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMReg reg) {
+void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMStorage reg) {
Unimplemented();
}
-void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMReg tmp, int in_stk_bias, int out_stk_bias) const {
+void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMStorage tmp, int in_stk_bias, int out_stk_bias, const StubLocations& locs) const {
Unimplemented();
}
-
diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp
index 4b102b576fa..60b5ffa41f8 100644
--- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp
@@ -220,7 +220,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo
// instruction patching is synchronized with global icache_flush() by
// the write hart on riscv. So here we can do a plain conditional
// branch with no fencing.
- Address thread_disarmed_addr(xthread, in_bytes(bs_nm->thread_disarmed_offset()));
+ Address thread_disarmed_addr(xthread, in_bytes(bs_nm->thread_disarmed_guard_value_offset()));
__ lwu(t1, thread_disarmed_addr);
break;
}
@@ -245,7 +245,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo
__ slli(t1, t1, 32);
__ orr(t0, t0, t1);
// Compare the global values with the thread-local values
- Address thread_disarmed_and_epoch_addr(xthread, in_bytes(bs_nm->thread_disarmed_offset()));
+ Address thread_disarmed_and_epoch_addr(xthread, in_bytes(bs_nm->thread_disarmed_guard_value_offset()));
__ ld(t1, thread_disarmed_and_epoch_addr);
break;
}
diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp
index 33126326a97..b8e61ff3a1d 100644
--- a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp
+++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp
@@ -171,32 +171,12 @@ static NativeNMethodBarrier* native_nmethod_barrier(nmethod* nm) {
return barrier;
}
-void BarrierSetNMethod::disarm(nmethod* nm) {
+void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) {
if (!supports_entry_barrier(nm)) {
return;
}
- // The patching epoch is incremented before the nmethod is disarmed. Disarming
- // is performed with a release store. In the nmethod entry barrier, the values
- // are read in the opposite order, such that the load of the nmethod guard
- // acquires the patching epoch. This way, the guard is guaranteed to block
- // entries to the nmethod, util it has safely published the requirement for
- // further fencing by mutators, before they are allowed to enter.
- BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
- bs_asm->increment_patching_epoch();
-
- // Disarms the nmethod guard emitted by BarrierSetAssembler::nmethod_entry_barrier.
- // Symmetric "LD; FENCE IR, IR" is in the nmethod barrier.
- NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
- barrier->set_value(nm, disarmed_value());
-}
-
-void BarrierSetNMethod::arm(nmethod* nm, int arm_value) {
- if (!supports_entry_barrier(nm)) {
- return;
- }
-
- if (arm_value == disarmed_value()) {
+ if (value == disarmed_guard_value()) {
// The patching epoch is incremented before the nmethod is disarmed. Disarming
// is performed with a release store. In the nmethod entry barrier, the values
// are read in the opposite order, such that the load of the nmethod guard
@@ -208,14 +188,14 @@ void BarrierSetNMethod::arm(nmethod* nm, int arm_value) {
}
NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
- barrier->set_value(nm, arm_value);
+ barrier->set_value(nm, value);
}
-bool BarrierSetNMethod::is_armed(nmethod* nm) {
+int BarrierSetNMethod::guard_value(nmethod* nm) {
if (!supports_entry_barrier(nm)) {
- return false;
+ return disarmed_guard_value();
}
NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
- return barrier->get_value(nm) != disarmed_value();
+ return barrier->get_value(nm);
}
diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp
index 962ba7f8593..580ded4b093 100644
--- a/src/hotspot/cpu/riscv/globals_riscv.hpp
+++ b/src/hotspot/cpu/riscv/globals_riscv.hpp
@@ -102,6 +102,8 @@ define_pd_global(intx, InlineSmallCode, 1000);
product(bool, UseRVV, false, EXPERIMENTAL, "Use RVV instructions") \
product(bool, UseZba, false, EXPERIMENTAL, "Use Zba instructions") \
product(bool, UseZbb, false, EXPERIMENTAL, "Use Zbb instructions") \
+ product(bool, UseZbs, false, EXPERIMENTAL, "Use Zbs instructions") \
+ product(bool, UseZfhmin, false, EXPERIMENTAL, "Use Zfhmin instructions") \
product(bool, UseZic64b, false, EXPERIMENTAL, "Use Zic64b instructions") \
product(bool, UseZicbom, false, EXPERIMENTAL, "Use Zicbom instructions") \
product(bool, UseZicbop, false, EXPERIMENTAL, "Use Zicbop instructions") \
diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
index 779e7912b43..ebdb5f04dce 100644
--- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
@@ -210,6 +210,7 @@ void MacroAssembler::post_call_nop() {
}
relocate(post_call_nop_Relocation::spec(), [&] {
nop();
+ li32(zr, 0);
});
}
@@ -407,10 +408,13 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file,
push_reg(RegSet::of(ra, t0, t1, c_rarg0), sp);
mv(c_rarg0, reg); // c_rarg0 : x10
- // The length of the instruction sequence emitted should be independent
- // of the value of the local char buffer address so that the size of mach
- // nodes for scratch emit and normal emit matches.
- movptr(t0, (address)b);
+ {
+ // The length of the instruction sequence emitted should not depend
+ // on the address of the char buffer so that the size of mach nodes for
+ // scratch emit and normal emit matches.
+ IncompressibleRegion ir(this); // Fixed length
+ movptr(t0, (address) b);
+ }
// call indirectly to solve generation ordering problem
ExternalAddress target(StubRoutines::verify_oop_subroutine_entry_address());
@@ -449,10 +453,13 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f
ld(x10, addr);
}
- // The length of the instruction sequence emitted should be independent
- // of the value of the local char buffer address so that the size of mach
- // nodes for scratch emit and normal emit matches.
- movptr(t0, (address)b);
+ {
+ // The length of the instruction sequence emitted should not depend
+ // on the address of the char buffer so that the size of mach nodes for
+ // scratch emit and normal emit matches.
+ IncompressibleRegion ir(this); // Fixed length
+ movptr(t0, (address) b);
+ }
// call indirectly to solve generation ordering problem
ExternalAddress target(StubRoutines::verify_oop_subroutine_entry_address());
@@ -1383,7 +1390,7 @@ static int patch_imm_in_li64(address branch, address target) {
return LI64_INSTRUCTIONS_NUM * NativeInstruction::instruction_size;
}
-static int patch_imm_in_li32(address branch, int32_t target) {
+int MacroAssembler::patch_imm_in_li32(address branch, int32_t target) {
const int LI32_INSTRUCTIONS_NUM = 2; // lui + addiw
int64_t upper = (intptr_t)target;
int32_t lower = (((int32_t)target) << 20) >> 20;
@@ -1447,7 +1454,7 @@ static address get_target_of_li64(address insn_addr) {
return (address)target_address;
}
-static address get_target_of_li32(address insn_addr) {
+address MacroAssembler::get_target_of_li32(address insn_addr) {
assert_cond(insn_addr != NULL);
intptr_t target_address = (((int64_t)Assembler::sextract(((unsigned*)insn_addr)[0], 31, 12)) & 0xfffff) << 12; // Lui.
target_address += ((int64_t)Assembler::sextract(((unsigned*)insn_addr)[1], 31, 20)); // Addiw.
@@ -1993,7 +2000,7 @@ void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators,
Register dst, Address src,
Register tmp1, Register tmp2) {
BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
- decorators = AccessInternal::decorator_fixup(decorators);
+ decorators = AccessInternal::decorator_fixup(decorators, type);
bool as_raw = (decorators & AS_RAW) != 0;
if (as_raw) {
bs->BarrierSetAssembler::load_at(this, decorators, type, dst, src, tmp1, tmp2);
@@ -2018,7 +2025,7 @@ void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators,
Address dst, Register val,
Register tmp1, Register tmp2, Register tmp3) {
BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
- decorators = AccessInternal::decorator_fixup(decorators);
+ decorators = AccessInternal::decorator_fixup(decorators, type);
bool as_raw = (decorators & AS_RAW) != 0;
if (as_raw) {
bs->BarrierSetAssembler::store_at(this, decorators, type, dst, val, tmp1, tmp2, tmp3);
@@ -3128,6 +3135,9 @@ address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset,
return NULL; // CodeBuffer::expand failed
}
+ // We are always 4-byte aligned here.
+ assert_alignment(pc());
+
// Create a trampoline stub relocation which relates this trampoline stub
// with the call instruction at insts_call_instruction_offset in the
// instructions code-section.
diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
index 811eef7f8ab..18c0e7057c4 100644
--- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* 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.
@@ -387,6 +387,9 @@ class MacroAssembler: public Assembler {
static int patch_oop(address insn_addr, address o);
+ static address get_target_of_li32(address insn_addr);
+ static int patch_imm_in_li32(address branch, int32_t target);
+
// Return whether code is emitted to a scratch blob.
virtual bool in_scratch_emit_size() {
return false;
@@ -1325,8 +1328,6 @@ class MacroAssembler: public Assembler {
jalr(x0, x1, 0);
}
-private:
-
#ifdef ASSERT
// Template short-hand support to clean-up after a failed call to trampoline
// call generation (see trampoline_call() below), when a set of Labels must
@@ -1340,6 +1341,9 @@ class MacroAssembler: public Assembler {
lbl.reset();
}
#endif
+
+private:
+
void repne_scan(Register addr, Register value, Register count, Register tmp);
// Return true if an address is within the 48-bit RISCV64 address space.
diff --git a/src/hotspot/cpu/riscv/matcher_riscv.hpp b/src/hotspot/cpu/riscv/matcher_riscv.hpp
index ff93ddf80a4..7d234d42b9b 100644
--- a/src/hotspot/cpu/riscv/matcher_riscv.hpp
+++ b/src/hotspot/cpu/riscv/matcher_riscv.hpp
@@ -161,6 +161,16 @@
// Implements a variant of EncodeISOArrayNode that encode ASCII only
static const bool supports_encode_ascii_array = false;
+ // Some architecture needs a helper to check for alltrue vector
+ static constexpr bool vectortest_needs_second_argument(bool is_alltrue, bool is_predicate) {
+ return false;
+ }
+
+ // BoolTest mask for vector test intrinsics
+ static constexpr BoolTest::mask vectortest_mask(bool is_alltrue, bool is_predicate, int vlen) {
+ return BoolTest::illegal;
+ }
+
// Returns pre-selection estimated size of a vector operation.
static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) {
switch(vopc) {
diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
index e7be863660d..d7385f59737 100644
--- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
+++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp
@@ -444,8 +444,16 @@ void NativePostCallNop::make_deopt() {
NativeDeoptInstruction::insert(addr_at(0));
}
+int NativePostCallNop::displacement() const {
+ // Discard the high 32 bits
+ return (int)(intptr_t)MacroAssembler::get_target_of_li32(addr_at(4));
+}
+
void NativePostCallNop::patch(jint diff) {
- // unsupported for now
+ assert(diff != 0, "must be");
+ assert(is_lui_to_zr_at(addr_at(4)) && is_addiw_to_zr_at(addr_at(8)), "must be");
+
+ MacroAssembler::patch_imm_in_li32(addr_at(4), diff);
}
void NativeDeoptInstruction::verify() {
diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp
index a6ed27870c4..72a7b62c124 100644
--- a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp
+++ b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp
@@ -78,7 +78,9 @@ class NativeInstruction {
static bool is_jump_at(address instr) { assert_cond(instr != NULL); return is_branch_at(instr) || is_jal_at(instr) || is_jalr_at(instr); }
static bool is_addi_at(address instr) { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0010011 && extract_funct3(instr) == 0b000; }
static bool is_addiw_at(address instr) { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0011011 && extract_funct3(instr) == 0b000; }
+ static bool is_addiw_to_zr_at(address instr) { assert_cond(instr != NULL); return is_addiw_at(instr) && extract_rd(instr) == zr; }
static bool is_lui_at(address instr) { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0110111; }
+ static bool is_lui_to_zr_at(address instr) { assert_cond(instr != NULL); return is_lui_at(instr) && extract_rd(instr) == zr; }
static bool is_slli_shift_at(address instr, uint32_t shift) {
assert_cond(instr != NULL);
return (extract_opcode(instr) == 0b0010011 && // opcode field
@@ -554,10 +556,22 @@ inline NativeMembar *NativeMembar_at(address addr) {
return (NativeMembar*)addr;
}
+// A NativePostCallNop takes the form of three instructions:
+// nop; lui zr, hi20; addiw zr, lo12
+//
+// The nop is patchable for a deoptimization trap. The lui and addiw
+// instructions execute as nops but have a 20/12-bit payload in which we
+// can store an offset from the initial nop to the nmethod.
class NativePostCallNop: public NativeInstruction {
public:
- bool check() const { return is_nop(); }
- int displacement() const { return 0; }
+ bool check() const {
+ // Check for two instructions: nop; lui zr, hi20
+ // These instructions only ever appear together in a post-call
+ // NOP, so it's unnecessary to check that the third instruction is
+ // an addiw as well.
+ return is_nop() && is_lui_to_zr_at(addr_at(4));
+ }
+ int displacement() const;
void patch(jint diff);
void make_deopt();
};
diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad
index c496754d070..e3c0242cfd7 100644
--- a/src/hotspot/cpu/riscv/riscv.ad
+++ b/src/hotspot/cpu/riscv/riscv.ad
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
// 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.
@@ -1303,7 +1303,7 @@ void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
if (C->stub_function() == NULL && BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) {
st->print("ld t0, [guard]\n\t");
st->print("membar LoadLoad\n\t");
- st->print("ld t1, [xthread, #thread_disarmed_offset]\n\t");
+ st->print("ld t1, [xthread, #thread_disarmed_guard_value_offset]\n\t");
st->print("beq t0, t1, skip\n\t");
st->print("jalr #nmethod_entry_barrier_stub\n\t");
st->print("j skip\n\t");
@@ -1361,8 +1361,9 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
Label* guard = &dummy_guard;
if (!Compile::current()->output()->in_scratch_emit_size()) {
// Use real labels from actual stub when not emitting code for purpose of measuring its size
- C2EntryBarrierStub* stub = Compile::current()->output()->entry_barrier_table()->add_entry_barrier();
- slow_path = &stub->slow_path();
+ C2EntryBarrierStub* stub = new (Compile::current()->comp_arena()) C2EntryBarrierStub();
+ Compile::current()->output()->add_stub(stub);
+ slow_path = &stub->entry();
continuation = &stub->continuation();
guard = &stub->guard();
}
@@ -1443,7 +1444,9 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
Label dummy_label;
Label* code_stub = &dummy_label;
if (!C->output()->in_scratch_emit_size()) {
- code_stub = &C->output()->safepoint_poll_table()->add_safepoint(__ offset());
+ C2SafepointPollStub* stub = new (C->comp_arena()) C2SafepointPollStub(__ offset());
+ C->output()->add_stub(stub);
+ code_stub = &stub->entry();
}
__ relocate(relocInfo::poll_return_type);
__ safepoint_poll(*code_stub, true /* at_return */, false /* acquire */, true /* in_nmethod */);
@@ -1839,6 +1842,10 @@ const bool Matcher::match_rule_supported(int opcode) {
case Op_CountTrailingZerosI:
case Op_CountTrailingZerosL:
return UseZbb;
+
+ case Op_ConvF2HF:
+ case Op_ConvHF2F:
+ return UseZfhmin;
}
return true; // Per default match rules are supported.
@@ -2984,6 +2991,14 @@ operand immI_16bits()
interface(CONST_INTER);
%}
+operand immIpowerOf2() %{
+ predicate(is_power_of_2((juint)(n->get_int())));
+ match(ConI);
+ op_cost(0);
+ format %{ %}
+ interface(CONST_INTER);
+%}
+
// Long Immediate: low 32-bit mask
operand immL_32bits()
%{
@@ -5103,6 +5118,7 @@ instruct storeimmL0(immL0 zero, memory mem)
instruct storeP(iRegP src, memory mem)
%{
match(Set mem (StoreP mem src));
+ predicate(n->as_Store()->barrier_data() == 0);
ins_cost(STORE_COST);
format %{ "sd $src, $mem\t# ptr, #@storeP" %}
@@ -5118,6 +5134,7 @@ instruct storeP(iRegP src, memory mem)
instruct storeimmP0(immP0 zero, memory mem)
%{
match(Set mem (StoreP mem zero));
+ predicate(n->as_Store()->barrier_data() == 0);
ins_cost(STORE_COST);
format %{ "sd zr, $mem\t# ptr, #@storeimmP0" %}
@@ -8124,6 +8141,44 @@ instruct convL2F_reg_reg(fRegF dst, iRegL src) %{
ins_pipe(fp_l2f);
%}
+// float <-> half float
+
+instruct convHF2F_reg_reg(fRegF dst, iRegINoSp src, fRegF tmp) %{
+ predicate(UseZfhmin);
+ match(Set dst (ConvHF2F src));
+ effect(TEMP tmp);
+
+ ins_cost(XFER_COST);
+ format %{ "fmv.h.x $tmp, $src\t#@convHF2F_reg_reg\n\t"
+ "fcvt.s.h $dst, $tmp\t#@convHF2F_reg_reg"
+ %}
+
+ ins_encode %{
+ __ fmv_h_x($tmp$$FloatRegister, $src$$Register);
+ __ fcvt_s_h($dst$$FloatRegister, $tmp$$FloatRegister);
+ %}
+
+ ins_pipe(fp_i2f);
+%}
+
+instruct convF2HF_reg_reg(iRegINoSp dst, fRegF src, fRegF tmp) %{
+ predicate(UseZfhmin);
+ match(Set dst (ConvF2HF src));
+ effect(TEMP tmp);
+
+ ins_cost(XFER_COST);
+ format %{ "fcvt.h.s $tmp, $src\t#@convF2HF_reg_reg\n\t"
+ "fmv.x.h $dst, $tmp\t#@convF2HF_reg_reg"
+ %}
+
+ ins_encode %{
+ __ fcvt_h_s($tmp$$FloatRegister, $src$$FloatRegister);
+ __ fmv_x_h($dst$$Register, $tmp$$FloatRegister);
+ %}
+
+ ins_pipe(fp_f2i);
+%}
+
// double <-> int
instruct convD2I_reg_reg(iRegINoSp dst, fRegD src) %{
diff --git a/src/hotspot/cpu/riscv/riscv_b.ad b/src/hotspot/cpu/riscv/riscv_b.ad
index bbebe13f0a8..0d29fc06e00 100644
--- a/src/hotspot/cpu/riscv/riscv_b.ad
+++ b/src/hotspot/cpu/riscv/riscv_b.ad
@@ -524,4 +524,18 @@ instruct ornL_reg_reg_b(iRegLNoSp dst, iRegL src1, iRegL src2, immL_M1 m1) %{
%}
ins_pipe(ialu_reg_reg);
-%}
\ No newline at end of file
+%}
+
+// AndI 0b0..010..0 + ConvI2B
+instruct convI2Bool_andI_reg_immIpowerOf2(iRegINoSp dst, iRegIorL2I src, immIpowerOf2 mask) %{
+ predicate(UseZbs);
+ match(Set dst (Conv2B (AndI src mask)));
+ ins_cost(ALU_COST);
+
+ format %{ "bexti $dst, $src, $mask\t#@convI2Bool_andI_reg_immIpowerOf2" %}
+ ins_encode %{
+ __ bexti($dst$$Register, $src$$Register, exact_log2((juint)($mask$$constant)));
+ %}
+
+ ins_pipe(ialu_reg_reg);
+%}
diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad
index 1132e46c64a..5cdf49dadb8 100644
--- a/src/hotspot/cpu/riscv/riscv_v.ad
+++ b/src/hotspot/cpu/riscv/riscv_v.ad
@@ -74,7 +74,6 @@ source %{
case Op_VectorCastL2X:
case Op_VectorCastS2X:
case Op_VectorInsert:
- case Op_VectorLoadConst:
case Op_VectorLoadMask:
case Op_VectorLoadShuffle:
case Op_VectorMaskCmp:
@@ -2077,3 +2076,20 @@ instruct vclearArray_reg_reg(iRegL_R29 cnt, iRegP_R28 base, Universe dummy,
ins_pipe(pipe_class_memory);
%}
+
+// Vector Load Const
+instruct vloadcon(vReg dst, immI0 src) %{
+ match(Set dst (VectorLoadConst src));
+ ins_cost(VEC_COST);
+ format %{ "vloadcon $dst\t# generate iota indices" %}
+ ins_encode %{
+ BasicType bt = Matcher::vector_element_basic_type(this);
+ Assembler::SEW sew = Assembler::elemtype_to_sew(bt);
+ __ vsetvli(t0, x0, sew);
+ __ vid_v(as_VectorRegister($dst$$reg));
+ if (is_floating_point_type(bt)) {
+ __ vfcvt_f_x_v(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg));
+ }
+ %}
+ ins_pipe(pipe_slow);
+%}
\ No newline at end of file
diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp
index d2992b9012b..136508af21d 100644
--- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp
+++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* 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.
@@ -978,6 +978,9 @@ static void gen_continuation_enter(MacroAssembler* masm,
__ align(NativeInstruction::instruction_size);
const address tr_call = __ trampoline_call(resolve);
+ if (tr_call == nullptr) {
+ fatal("CodeCache is full at gen_continuation_enter");
+ }
oop_maps->add_gc_map(__ pc() - start, map);
__ post_call_nop();
@@ -985,7 +988,10 @@ static void gen_continuation_enter(MacroAssembler* masm,
__ j(exit);
CodeBuffer* cbuf = masm->code_section()->outer();
- CompiledStaticCall::emit_to_interp_stub(*cbuf, tr_call);
+ address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, tr_call);
+ if (stub == nullptr) {
+ fatal("CodeCache is full at gen_continuation_enter");
+ }
}
// compiled entry
@@ -1005,6 +1011,9 @@ static void gen_continuation_enter(MacroAssembler* masm,
__ align(NativeInstruction::instruction_size);
const address tr_call = __ trampoline_call(resolve);
+ if (tr_call == nullptr) {
+ fatal("CodeCache is full at gen_continuation_enter");
+ }
oop_maps->add_gc_map(__ pc() - start, map);
__ post_call_nop();
@@ -1045,7 +1054,10 @@ static void gen_continuation_enter(MacroAssembler* masm,
}
CodeBuffer* cbuf = masm->code_section()->outer();
- CompiledStaticCall::emit_to_interp_stub(*cbuf, tr_call);
+ address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, tr_call);
+ if (stub == nullptr) {
+ fatal("CodeCache is full at gen_continuation_enter");
+ }
}
static void gen_continuation_yield(MacroAssembler* masm,
diff --git a/src/hotspot/cpu/riscv/stackChunkFrameStream_riscv.inline.hpp b/src/hotspot/cpu/riscv/stackChunkFrameStream_riscv.inline.hpp
index 9fb17e6e4e2..38ee1de6470 100644
--- a/src/hotspot/cpu/riscv/stackChunkFrameStream_riscv.inline.hpp
+++ b/src/hotspot/cpu/riscv/stackChunkFrameStream_riscv.inline.hpp
@@ -76,12 +76,6 @@ inline intptr_t* StackChunkFrameStream::unextended_sp_for_interprete
return derelativize(frame::interpreter_frame_last_sp_offset);
}
-template
-intptr_t* StackChunkFrameStream::next_sp_for_interpreter_frame() const {
- assert_is_interpreted_and_frame_type_mixed();
- return (derelativize(frame::interpreter_frame_locals_offset) + 1 >= _end) ? _end : fp() + frame::sender_sp_offset;
-}
-
template
inline void StackChunkFrameStream::next_for_interpreter_frame() {
assert_is_interpreted_and_frame_type_mixed();
diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
index 5bc26b9cbfe..4f34f824bd5 100644
--- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
+++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
@@ -2461,7 +2461,7 @@ class StubGenerator: public StubCodeGenerator {
if (bs_asm->nmethod_patching_type() == NMethodPatchingType::conc_instruction_and_data_patch) {
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
- Address thread_epoch_addr(xthread, in_bytes(bs_nm->thread_disarmed_offset()) + 4);
+ Address thread_epoch_addr(xthread, in_bytes(bs_nm->thread_disarmed_guard_value_offset()) + 4);
__ la(t1, ExternalAddress(bs_asm->patching_epoch_addr()));
__ lwu(t1, t1);
__ sw(t1, thread_epoch_addr);
diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp
index 49a2b87c232..213e360c20e 100644
--- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp
+++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp
@@ -776,8 +776,12 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
// Move SP out of the way
__ mv(sp, t0);
} else {
- __ sd(sp, Address(sp, 5 * wordSize));
+ // Make sure there is room for the exception oop pushed in case method throws
+ // an exception (see TemplateInterpreterGenerator::generate_throw_exception())
+ __ sub(t0, sp, 2 * wordSize);
+ __ sd(t0, Address(sp, 5 * wordSize));
__ sd(zr, Address(sp, 4 * wordSize));
+ __ mv(sp, t0);
}
}
diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp
index 6afef7ae546..9ba73a00808 100644
--- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp
+++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp
@@ -59,6 +59,9 @@ void VM_Version::initialize() {
if (FLAG_IS_DEFAULT(UseZbb)) {
FLAG_SET_DEFAULT(UseZbb, true);
}
+ if (FLAG_IS_DEFAULT(UseZbs)) {
+ FLAG_SET_DEFAULT(UseZbs, true);
+ }
if (FLAG_IS_DEFAULT(UseZic64b)) {
FLAG_SET_DEFAULT(UseZic64b, true);
}
@@ -71,6 +74,9 @@ void VM_Version::initialize() {
if (FLAG_IS_DEFAULT(UseZicboz)) {
FLAG_SET_DEFAULT(UseZicboz, true);
}
+ if (FLAG_IS_DEFAULT(UseZfhmin)) {
+ FLAG_SET_DEFAULT(UseZfhmin, true);
+ }
}
if (UseZic64b) {
diff --git a/src/hotspot/cpu/riscv/vmstorage_riscv.hpp b/src/hotspot/cpu/riscv/vmstorage_riscv.hpp
new file mode 100644
index 00000000000..93940376229
--- /dev/null
+++ b/src/hotspot/cpu/riscv/vmstorage_riscv.hpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef CPU_RISCV_VMSTORAGE_RISCV_INLINE_HPP
+#define CPU_RISCV_VMSTORAGE_RISCV_INLINE_HPP
+
+#include
+
+#include "asm/register.hpp"
+
+enum class StorageType : int8_t {
+ STACK = 0,
+ PLACEHOLDER = 1,
+// special locations used only by native code
+ FRAME_DATA = PLACEHOLDER + 1,
+ INVALID = -1
+};
+
+// need to define this before constructing VMStorage (below)
+constexpr inline bool VMStorage::is_reg(StorageType type) {
+ return false;
+}
+constexpr inline StorageType VMStorage::stack_type() { return StorageType::STACK; }
+constexpr inline StorageType VMStorage::placeholder_type() { return StorageType::PLACEHOLDER; }
+constexpr inline StorageType VMStorage::frame_data_type() { return StorageType::FRAME_DATA; }
+
+inline VMStorage as_VMStorage(VMReg reg) {
+ ShouldNotReachHere();
+ return VMStorage::invalid();
+}
+
+#endif // CPU_RISCV_VMSTORAGE_RISCV_INLINE_HPP
\ No newline at end of file
diff --git a/src/hotspot/cpu/s390/assembler_s390.hpp b/src/hotspot/cpu/s390/assembler_s390.hpp
index 4258f971078..a0a86a707dd 100644
--- a/src/hotspot/cpu/s390/assembler_s390.hpp
+++ b/src/hotspot/cpu/s390/assembler_s390.hpp
@@ -295,7 +295,7 @@ class AddressLiteral {
protected:
// creation
- AddressLiteral() : _address(NULL), _rspec(NULL) {}
+ AddressLiteral() : _address(NULL), _rspec() {}
public:
AddressLiteral(address addr, RelocationHolder const& rspec)
diff --git a/src/hotspot/cpu/s390/c1_Defs_s390.hpp b/src/hotspot/cpu/s390/c1_Defs_s390.hpp
index 8ee07273b3b..3fc3ee2772c 100644
--- a/src/hotspot/cpu/s390/c1_Defs_s390.hpp
+++ b/src/hotspot/cpu/s390/c1_Defs_s390.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -68,4 +68,8 @@ enum {
pd_float_saved_as_double = false
};
+enum {
+ pd_two_operand_lir_form = true
+};
+
#endif // CPU_S390_C1_DEFS_S390_HPP
diff --git a/src/hotspot/cpu/s390/c1_globals_s390.hpp b/src/hotspot/cpu/s390/c1_globals_s390.hpp
index a939b32bd5b..130a53ad084 100644
--- a/src/hotspot/cpu/s390/c1_globals_s390.hpp
+++ b/src/hotspot/cpu/s390/c1_globals_s390.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -61,6 +61,5 @@ define_pd_global(bool, UseTypeProfile, false);
define_pd_global(bool, OptimizeSinglePrecision, false);
define_pd_global(bool, CSEArrayLength, true);
-define_pd_global(bool, TwoOperandLIRForm, true);
#endif // CPU_S390_C1_GLOBALS_S390_HPP
diff --git a/src/hotspot/cpu/s390/continuationFreezeThaw_s390.inline.hpp b/src/hotspot/cpu/s390/continuationFreezeThaw_s390.inline.hpp
index a97e700ee3a..5b9c5d9a8bd 100644
--- a/src/hotspot/cpu/s390/continuationFreezeThaw_s390.inline.hpp
+++ b/src/hotspot/cpu/s390/continuationFreezeThaw_s390.inline.hpp
@@ -87,10 +87,6 @@ inline void ThawBase::patch_pd(frame& f, const frame& caller) {
Unimplemented();
}
-void ThawBase::patch_chunk_pd(intptr_t* sp) {
- Unimplemented();
-}
-
template
inline void Thaw::patch_caller_links(intptr_t* sp, intptr_t* bottom) {
Unimplemented();
diff --git a/src/hotspot/cpu/s390/downcallLinker_s390.cpp b/src/hotspot/cpu/s390/downcallLinker_s390.cpp
index af69f2a58a6..37b6f43ac14 100644
--- a/src/hotspot/cpu/s390/downcallLinker_s390.cpp
+++ b/src/hotspot/cpu/s390/downcallLinker_s390.cpp
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, Red Hat, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -29,9 +30,10 @@ RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature,
int num_args,
BasicType ret_bt,
const ABIDescriptor& abi,
- const GrowableArray& input_registers,
- const GrowableArray& output_registers,
- bool needs_return_buffer) {
+ const GrowableArray& input_registers,
+ const GrowableArray& output_registers,
+ bool needs_return_buffer,
+ int captured_state_mask) {
Unimplemented();
return nullptr;
}
diff --git a/src/hotspot/cpu/s390/foreignGlobals_s390.cpp b/src/hotspot/cpu/s390/foreignGlobals_s390.cpp
index 918e89f3ee6..5438cbe5cd6 100644
--- a/src/hotspot/cpu/s390/foreignGlobals_s390.cpp
+++ b/src/hotspot/cpu/s390/foreignGlobals_s390.cpp
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, Red Hat, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -33,24 +34,19 @@ const ABIDescriptor ForeignGlobals::parse_abi_descriptor(jobject jabi) {
return {};
}
-VMReg ForeignGlobals::vmstorage_to_vmreg(int type, int index) {
- Unimplemented();
- return VMRegImpl::Bad();
-}
-
-int RegSpiller::pd_reg_size(VMReg reg) {
+int RegSpiller::pd_reg_size(VMStorage reg) {
Unimplemented();
return -1;
}
-void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMReg reg) {
+void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMStorage reg) {
Unimplemented();
}
-void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMReg reg) {
+void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMStorage reg) {
Unimplemented();
}
-void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMReg tmp, int in_stk_bias, int out_stk_bias) const {
+void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMStorage tmp, int in_stk_bias, int out_stk_bias, const StubLocations& locs) const {
Unimplemented();
}
diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp
index ea7b6a4552c..97df78d12d8 100644
--- a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp
+++ b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp
@@ -135,7 +135,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) {
__ load_const(Z_R1_scratch, (uint64_t)StubRoutines::zarch::nmethod_entry_barrier()); // 2*6 bytes
// Load value from current java object:
- __ z_lg(Z_R0_scratch, in_bytes(bs_nm->thread_disarmed_offset()), Z_thread); // 6 bytes
+ __ z_lg(Z_R0_scratch, in_bytes(bs_nm->thread_disarmed_guard_value_offset()), Z_thread); // 6 bytes
// Compare to current patched value:
__ z_cfi(Z_R0_scratch, /* to be patched */ -1); // 6 bytes (2 + 4 byte imm val)
diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp
index 46089266f8e..a912cfcaf82 100644
--- a/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp
+++ b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp
@@ -101,29 +101,20 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
return;
}
-void BarrierSetNMethod::arm(nmethod* nm, int arm_value) {
+void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) {
if (!supports_entry_barrier(nm)) {
return;
}
NativeMethodBarrier* barrier = get_nmethod_barrier(nm);
- barrier->set_guard_value(arm_value);
+ barrier->set_guard_value(value);
}
-void BarrierSetNMethod::disarm(nmethod* nm) {
+int BarrierSetNMethod::guard_value(nmethod* nm) {
if (!supports_entry_barrier(nm)) {
- return;
- }
-
- NativeMethodBarrier* barrier = get_nmethod_barrier(nm);
- barrier->set_guard_value(disarmed_value());
-}
-
-bool BarrierSetNMethod::is_armed(nmethod* nm) {
- if (!supports_entry_barrier(nm)) {
- return false;
+ return disarmed_guard_value();
}
NativeMethodBarrier* barrier = get_nmethod_barrier(nm);
- return barrier->get_guard_value() != disarmed_value();
+ return barrier->get_guard_value();
}
diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp
index 5a26adf5ec9..46897266b20 100644
--- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp
+++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp
@@ -3858,7 +3858,7 @@ void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators,
assert((decorators & ~(AS_RAW | IN_HEAP | IN_NATIVE | IS_ARRAY | IS_NOT_NULL |
ON_UNKNOWN_OOP_REF)) == 0, "unsupported decorator");
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
- decorators = AccessInternal::decorator_fixup(decorators);
+ decorators = AccessInternal::decorator_fixup(decorators, type);
bool as_raw = (decorators & AS_RAW) != 0;
if (as_raw) {
bs->BarrierSetAssembler::store_at(this, decorators, type,
@@ -3877,7 +3877,7 @@ void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators,
assert((decorators & ~(AS_RAW | IN_HEAP | IN_NATIVE | IS_ARRAY | IS_NOT_NULL |
ON_PHANTOM_OOP_REF | ON_WEAK_OOP_REF)) == 0, "unsupported decorator");
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
- decorators = AccessInternal::decorator_fixup(decorators);
+ decorators = AccessInternal::decorator_fixup(decorators, type);
bool as_raw = (decorators & AS_RAW) != 0;
if (as_raw) {
bs->BarrierSetAssembler::load_at(this, decorators, type,
diff --git a/src/hotspot/cpu/s390/matcher_s390.hpp b/src/hotspot/cpu/s390/matcher_s390.hpp
index 436271c3022..d683f35a8a4 100644
--- a/src/hotspot/cpu/s390/matcher_s390.hpp
+++ b/src/hotspot/cpu/s390/matcher_s390.hpp
@@ -153,6 +153,16 @@
// Implements a variant of EncodeISOArrayNode that encode ASCII only
static const bool supports_encode_ascii_array = true;
+ // Some architecture needs a helper to check for alltrue vector
+ static constexpr bool vectortest_needs_second_argument(bool is_alltrue, bool is_predicate) {
+ return false;
+ }
+
+ // BoolTest mask for vector test intrinsics
+ static constexpr BoolTest::mask vectortest_mask(bool is_alltrue, bool is_predicate, int vlen) {
+ return BoolTest::illegal;
+ }
+
// Returns pre-selection estimated size of a vector operation.
static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) {
switch(vopc) {
diff --git a/src/hotspot/cpu/s390/stackChunkFrameStream_s390.inline.hpp b/src/hotspot/cpu/s390/stackChunkFrameStream_s390.inline.hpp
index 2df1e38a9de..4f372c982d5 100644
--- a/src/hotspot/cpu/s390/stackChunkFrameStream_s390.inline.hpp
+++ b/src/hotspot/cpu/s390/stackChunkFrameStream_s390.inline.hpp
@@ -67,12 +67,6 @@ inline intptr_t* StackChunkFrameStream::unextended_sp_for_interprete
return NULL;
}
-template
-intptr_t* StackChunkFrameStream::next_sp_for_interpreter_frame() const {
- Unimplemented();
- return NULL;
-}
-
template
inline void StackChunkFrameStream::next_for_interpreter_frame() {
Unimplemented();
diff --git a/src/hotspot/cpu/s390/vmstorage_s390.hpp b/src/hotspot/cpu/s390/vmstorage_s390.hpp
new file mode 100644
index 00000000000..702e57efb94
--- /dev/null
+++ b/src/hotspot/cpu/s390/vmstorage_s390.hpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef CPU_S390_VMSTORAGE_S390_INLINE_HPP
+#define CPU_S390_VMSTORAGE_S390_INLINE_HPP
+
+#include
+
+#include "asm/register.hpp"
+
+enum class StorageType : int8_t {
+ STACK = 0,
+ PLACEHOLDER = 1,
+// special locations used only by native code
+ FRAME_DATA = PLACEHOLDER + 1,
+ INVALID = -1
+};
+
+// need to define this before constructing VMStorage (below)
+constexpr inline bool VMStorage::is_reg(StorageType type) {
+ return false;
+}
+constexpr inline StorageType VMStorage::stack_type() { return StorageType::STACK; }
+constexpr inline StorageType VMStorage::placeholder_type() { return StorageType::PLACEHOLDER; }
+constexpr inline StorageType VMStorage::frame_data_type() { return StorageType::FRAME_DATA; }
+
+inline VMStorage as_VMStorage(VMReg reg) {
+ ShouldNotReachHere();
+ return VMStorage::invalid();
+}
+
+#endif // CPU_S390_VMSTORAGE_S390_INLINE_HPP
\ No newline at end of file
diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp
index ad7543cfb78..67ff8a97c7a 100644
--- a/src/hotspot/cpu/x86/assembler_x86.cpp
+++ b/src/hotspot/cpu/x86/assembler_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1931,14 +1931,14 @@ void Assembler::vcvtdq2pd(XMMRegister dst, XMMRegister src, int vector_len) {
}
void Assembler::vcvtps2ph(XMMRegister dst, XMMRegister src, int imm8, int vector_len) {
- assert(VM_Version::supports_avx512vl() || VM_Version::supports_f16c(), "");
+ assert(VM_Version::supports_evex() || VM_Version::supports_f16c(), "");
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /*uses_vl */ true);
int encode = vex_prefix_and_encode(src->encoding(), 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
emit_int24(0x1D, (0xC0 | encode), imm8);
}
void Assembler::evcvtps2ph(Address dst, KRegister mask, XMMRegister src, int imm8, int vector_len) {
- assert(VM_Version::supports_avx512vl(), "");
+ assert(VM_Version::supports_evex(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /*uses_vl */ true);
attributes.set_address_attributes(/* tuple_type */ EVEX_HVM, /* input_size_in_bits */ EVEX_64bit);
@@ -1951,13 +1951,34 @@ void Assembler::evcvtps2ph(Address dst, KRegister mask, XMMRegister src, int imm
emit_int8(imm8);
}
+void Assembler::vcvtps2ph(Address dst, XMMRegister src, int imm8, int vector_len) {
+ assert(VM_Version::supports_evex() || VM_Version::supports_f16c(), "");
+ InstructionMark im(this);
+ InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /*uses_vl */ true);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_HVM, /* input_size_in_bits */ EVEX_NObit);
+ vex_prefix(dst, 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
+ emit_int8(0x1D);
+ emit_operand(src, dst, 1);
+ emit_int8(imm8);
+}
+
void Assembler::vcvtph2ps(XMMRegister dst, XMMRegister src, int vector_len) {
- assert(VM_Version::supports_avx512vl() || VM_Version::supports_f16c(), "");
+ assert(VM_Version::supports_evex() || VM_Version::supports_f16c(), "");
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */false, /* no_mask_reg */ true, /* uses_vl */ true);
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int16(0x13, (0xC0 | encode));
}
+void Assembler::vcvtph2ps(XMMRegister dst, Address src, int vector_len) {
+ assert(VM_Version::supports_evex() || VM_Version::supports_f16c(), "");
+ InstructionMark im(this);
+ InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /*uses_vl */ true);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_HVM, /* input_size_in_bits */ EVEX_NObit);
+ vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int8(0x13);
+ emit_operand(dst, src, 0);
+}
+
void Assembler::cvtdq2ps(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -2474,7 +2495,7 @@ void Assembler::jmp_literal(address dest, RelocationHolder const& rspec) {
assert(dest != NULL, "must have a target");
intptr_t disp = dest - (pc() + sizeof(int32_t));
assert(is_simm32(disp), "must be 32bit offset (jmp)");
- emit_data(disp, rspec.reloc(), call32_operand);
+ emit_data(disp, rspec, call32_operand);
}
void Assembler::jmpb_0(Label& L, const char* file, int line) {
@@ -5426,13 +5447,38 @@ void Assembler::vptest(XMMRegister dst, XMMRegister src, int vector_len) {
emit_int16(0x17, (0xC0 | encode));
}
+void Assembler::vtestps(XMMRegister dst, XMMRegister src, int vector_len) {
+ assert(VM_Version::supports_avx(), "");
+ InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
+ int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int16(0x0E, (0xC0 | encode));
+}
+
void Assembler::evptestmb(KRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
- assert(VM_Version::supports_avx512vlbw(), "");
- // Encoding: EVEX.NDS.XXX.66.0F.W0 DB /r
+ assert(vector_len == AVX_512bit ? VM_Version::supports_avx512bw() : VM_Version::supports_avx512vlbw(), "");
+ // Encoding: EVEX.NDS.XXX.66.0F38.W0 DB /r
+ 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(0x26, (0xC0 | encode));
+}
+
+void Assembler::evptestmd(KRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
+ assert(vector_len == AVX_512bit ? VM_Version::supports_evex() : VM_Version::supports_avx512vl(), "");
+ // Encoding: EVEX.NDS.XXX.66.0F38.W0 DB /r
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((unsigned char)0x26, (0xC0 | encode));
+ emit_int16(0x27, (0xC0 | encode));
+}
+
+void Assembler::evptestnmd(KRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
+ assert(vector_len == AVX_512bit ? VM_Version::supports_evex() : VM_Version::supports_avx512vl(), "");
+ // Encoding: EVEX.NDS.XXX.F3.0F38.W0 DB /r
+ 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_F3, VEX_OPCODE_0F_38, &attributes);
+ emit_int16(0x27, (0xC0 | encode));
}
void Assembler::punpcklbw(XMMRegister dst, Address src) {
@@ -13407,6 +13453,11 @@ void Assembler::orq(Register dst, int32_t imm32) {
emit_arith(0x81, 0xC8, dst, 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::orq(Register dst, Address src) {
InstructionMark im(this);
emit_int16(get_prefixq(src, dst), 0x0B);
diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp
index 7b4288e775e..a4bd8bf4864 100644
--- a/src/hotspot/cpu/x86/assembler_x86.hpp
+++ b/src/hotspot/cpu/x86/assembler_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1160,6 +1160,8 @@ class Assembler : public AbstractAssembler {
void vcvtps2ph(XMMRegister dst, XMMRegister src, int imm8, int vector_len);
void vcvtph2ps(XMMRegister dst, XMMRegister src, int vector_len);
void evcvtps2ph(Address dst, KRegister mask, XMMRegister src, int imm8, int vector_len);
+ void vcvtps2ph(Address dst, XMMRegister src, int imm8, int vector_len);
+ void vcvtph2ps(XMMRegister dst, Address src, int vector_len);
// Convert Packed Signed Doubleword Integers to Packed Single-Precision Floating-Point Value
void cvtdq2ps(XMMRegister dst, XMMRegister src);
@@ -1734,6 +1736,7 @@ class Assembler : public AbstractAssembler {
void orq(Address dst, int32_t imm32);
void orq(Address dst, Register src);
void orq(Register dst, int32_t imm32);
+ void orq_imm32(Register dst, int32_t imm32);
void orq(Register dst, Address src);
void orq(Register dst, Register src);
@@ -1971,9 +1974,12 @@ class Assembler : public AbstractAssembler {
void vptest(XMMRegister dst, Address src);
void evptestmb(KRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
+ void evptestmd(KRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
+ void evptestnmd(KRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
// Vector compare
void vptest(XMMRegister dst, XMMRegister src, int vector_len);
+ void vtestps(XMMRegister dst, XMMRegister src, int vector_len);
// Interleave Low Bytes
void punpcklbw(XMMRegister dst, XMMRegister src);
diff --git a/src/hotspot/cpu/x86/c1_Defs_x86.hpp b/src/hotspot/cpu/x86/c1_Defs_x86.hpp
index c8529d9afda..40a48622571 100644
--- a/src/hotspot/cpu/x86/c1_Defs_x86.hpp
+++ b/src/hotspot/cpu/x86/c1_Defs_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -75,4 +75,8 @@ enum {
pd_float_saved_as_double = true
};
+enum {
+ pd_two_operand_lir_form = true
+};
+
#endif // CPU_X86_C1_DEFS_X86_HPP
diff --git a/src/hotspot/cpu/x86/c1_globals_x86.hpp b/src/hotspot/cpu/x86/c1_globals_x86.hpp
index 9212e321d65..b2085a0b4b3 100644
--- a/src/hotspot/cpu/x86/c1_globals_x86.hpp
+++ b/src/hotspot/cpu/x86/c1_globals_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -59,6 +59,5 @@ define_pd_global(bool, UseTypeProfile, false);
define_pd_global(bool, OptimizeSinglePrecision, true );
define_pd_global(bool, CSEArrayLength, false);
-define_pd_global(bool, TwoOperandLIRForm, true );
#endif // CPU_X86_C1_GLOBALS_X86_HPP
diff --git a/src/hotspot/cpu/x86/c2_safepointPollStubTable_x86.cpp b/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp
similarity index 72%
rename from src/hotspot/cpu/x86/c2_safepointPollStubTable_x86.cpp
rename to src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp
index c3d4850a5db..acae574bcf3 100644
--- a/src/hotspot/cpu/x86/c2_safepointPollStubTable_x86.cpp
+++ b/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,22 +23,26 @@
*/
#include "precompiled.hpp"
-#include "asm/macroAssembler.hpp"
-#include "opto/compile.hpp"
-#include "opto/node.hpp"
-#include "opto/output.hpp"
+#include "opto/c2_MacroAssembler.hpp"
+#include "opto/c2_CodeStubs.hpp"
#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
#define __ masm.
-void C2SafepointPollStubTable::emit_stub_impl(MacroAssembler& masm, C2SafepointPollStub* entry) const {
+
+int C2SafepointPollStub::max_size() const {
+ return 33;
+}
+
+void C2SafepointPollStub::emit(C2_MacroAssembler& masm) {
assert(SharedRuntime::polling_page_return_handler_blob() != NULL,
"polling page return stub not created yet");
address stub = SharedRuntime::polling_page_return_handler_blob()->entry_point();
RuntimeAddress callback_addr(stub);
- __ bind(entry->_stub_label);
- InternalAddress safepoint_pc(masm.pc() - masm.offset() + entry->_safepoint_offset);
+ __ bind(entry());
+ InternalAddress safepoint_pc(masm.pc() - masm.offset() + _safepoint_offset);
#ifdef _LP64
__ lea(rscratch1, safepoint_pc);
__ movptr(Address(r15_thread, JavaThread::saved_exception_pc_offset()), rscratch1);
@@ -57,4 +61,15 @@ void C2SafepointPollStubTable::emit_stub_impl(MacroAssembler& masm, C2SafepointP
#endif
__ jump(callback_addr);
}
+
+int C2EntryBarrierStub::max_size() const {
+ return 10;
+}
+
+void C2EntryBarrierStub::emit(C2_MacroAssembler& masm) {
+ __ bind(entry());
+ __ call(RuntimeAddress(StubRoutines::x86::method_entry_barrier()));
+ __ jmp(continuation(), false /* maybe_short */);
+}
+
#undef __
diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
index 26c19ee6f1d..91949213a20 100644
--- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
@@ -138,8 +138,9 @@ void C2_MacroAssembler::verified_entry(int framesize, int stack_bang_size, bool
Label* continuation = &dummy_continuation;
if (!Compile::current()->output()->in_scratch_emit_size()) {
// Use real labels from actual stub when not emitting code for the purpose of measuring its size
- C2EntryBarrierStub* stub = Compile::current()->output()->entry_barrier_table()->add_entry_barrier();
- slow_path = &stub->slow_path();
+ C2EntryBarrierStub* stub = new (Compile::current()->comp_arena()) C2EntryBarrierStub();
+ Compile::current()->output()->add_stub(stub);
+ slow_path = &stub->entry();
continuation = &stub->continuation();
}
bs->nmethod_entry_barrier(this, slow_path, continuation);
@@ -151,16 +152,6 @@ void C2_MacroAssembler::verified_entry(int framesize, int stack_bang_size, bool
}
}
-void C2_MacroAssembler::emit_entry_barrier_stub(C2EntryBarrierStub* stub) {
- bind(stub->slow_path());
- call(RuntimeAddress(StubRoutines::x86::method_entry_barrier()));
- jmp(stub->continuation(), false /* maybe_short */);
-}
-
-int C2_MacroAssembler::entry_barrier_stub_size() {
- return 10;
-}
-
inline Assembler::AvxVectorLen C2_MacroAssembler::vector_length_encoding(int vlen_in_bytes) {
switch (vlen_in_bytes) {
case 4: // fall-through
@@ -2415,58 +2406,32 @@ void C2_MacroAssembler::evpblend(BasicType typ, XMMRegister dst, KRegister kmask
}
}
-void C2_MacroAssembler::vectortest(int bt, int vlen, XMMRegister src1, XMMRegister src2,
- XMMRegister vtmp1, XMMRegister vtmp2, KRegister mask) {
- switch(vlen) {
- case 4:
- assert(vtmp1 != xnoreg, "required.");
- // Broadcast lower 32 bits to 128 bits before ptest
- pshufd(vtmp1, src1, 0x0);
- if (bt == BoolTest::overflow) {
- assert(vtmp2 != xnoreg, "required.");
- pshufd(vtmp2, src2, 0x0);
- } else {
- assert(vtmp2 == xnoreg, "required.");
- vtmp2 = src2;
- }
- ptest(vtmp1, vtmp2);
- break;
- case 8:
- assert(vtmp1 != xnoreg, "required.");
- // Broadcast lower 64 bits to 128 bits before ptest
- pshufd(vtmp1, src1, 0x4);
- if (bt == BoolTest::overflow) {
- assert(vtmp2 != xnoreg, "required.");
- pshufd(vtmp2, src2, 0x4);
- } else {
- assert(vtmp2 == xnoreg, "required.");
- vtmp2 = src2;
- }
- ptest(vtmp1, vtmp2);
- break;
- case 16:
- assert((vtmp1 == xnoreg) && (vtmp2 == xnoreg), "required.");
- ptest(src1, src2);
- break;
- case 32:
- assert((vtmp1 == xnoreg) && (vtmp2 == xnoreg), "required.");
- vptest(src1, src2, Assembler::AVX_256bit);
- break;
- case 64:
- {
- assert((vtmp1 == xnoreg) && (vtmp2 == xnoreg), "required.");
- evpcmpeqb(mask, src1, src2, Assembler::AVX_512bit);
- if (bt == BoolTest::ne) {
- ktestql(mask, mask);
- } else {
- assert(bt == BoolTest::overflow, "required");
- kortestql(mask, mask);
- }
- }
- break;
- default:
- assert(false,"Should not reach here.");
- break;
+void C2_MacroAssembler::vectortest(BasicType bt, XMMRegister src1, XMMRegister src2, XMMRegister vtmp, int vlen_in_bytes) {
+ assert(vlen_in_bytes <= 32, "");
+ int esize = type2aelembytes(bt);
+ if (vlen_in_bytes == 32) {
+ assert(vtmp == xnoreg, "required.");
+ if (esize >= 4) {
+ vtestps(src1, src2, AVX_256bit);
+ } else {
+ vptest(src1, src2, AVX_256bit);
+ }
+ return;
+ }
+ if (vlen_in_bytes < 16) {
+ // Duplicate the lower part to fill the whole register,
+ // Don't need to do so for src2
+ assert(vtmp != xnoreg, "required");
+ int shuffle_imm = (vlen_in_bytes == 4) ? 0x00 : 0x04;
+ pshufd(vtmp, src1, shuffle_imm);
+ } else {
+ assert(vtmp == xnoreg, "required");
+ vtmp = src1;
+ }
+ if (esize >= 4 && VM_Version::supports_avx()) {
+ vtestps(vtmp, src2, AVX_128bit);
+ } else {
+ ptest(vtmp, src2);
}
}
diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp
index 029918a4f36..2bd90fc24ea 100644
--- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp
+++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp
@@ -138,8 +138,7 @@
void get_elem(BasicType typ, XMMRegister dst, XMMRegister src, int elemindex, XMMRegister vtmp = xnoreg);
// vector test
- void vectortest(int bt, int vlen, XMMRegister src1, XMMRegister src2,
- XMMRegister vtmp1 = xnoreg, XMMRegister vtmp2 = xnoreg, KRegister mask = knoreg);
+ void vectortest(BasicType bt, XMMRegister src1, XMMRegister src2, XMMRegister vtmp, int vlen_in_bytes);
// Covert B2X
void vconvert_b2x(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vlen_enc);
diff --git a/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp b/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp
index 0b2b51f6e45..fc804b3795a 100644
--- a/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp
+++ b/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp
@@ -199,11 +199,6 @@ inline void Thaw::patch_caller_links(intptr_t* sp, intptr_t* bottom) {
assert(!PreserveFramePointer, "Frame pointers need to be fixed");
}
-void ThawBase::patch_chunk_pd(intptr_t* sp) {
- intptr_t* fp = _cont.entryFP();
- *(intptr_t**)(sp - frame::sender_sp_offset) = fp;
-}
-
// Slow path
inline frame ThawBase::new_entry_frame() {
diff --git a/src/hotspot/cpu/x86/crc32c.h b/src/hotspot/cpu/x86/crc32c.h
index dfdbd525e77..b2d4a90619d 100644
--- a/src/hotspot/cpu/x86/crc32c.h
+++ b/src/hotspot/cpu/x86/crc32c.h
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
+* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,15 +39,15 @@ enum {
// based on ubench study using methodology described in
// V. Gopal et al. / Fast CRC Computation for iSCSI Polynomial Using CRC32 Instruction April 2011 8
//
- // arbitrary value between 27 and 256
- CRC32C_MIDDLE = 8 * 86,
+ // arbitrary value between 9 and 256
+ CRC32C_MIDDLE = 8 * 74,
// V. Gopal et al. / Fast CRC Computation for iSCSI Polynomial Using CRC32 Instruction April 2011 9
- // shows that 240 and 1024 are equally good choices as the 216==8*27
+ // shows that 240 and 1024 are equally good choices as the 216==8*9*3
//
// Selecting the smallest value which resulted in a significant performance improvement over
// sequential version
- CRC32C_LOW = 8 * 27,
+ CRC32C_LOW = 8 * 9,
CRC32C_NUM_ChunkSizeInBytes = 3,
diff --git a/src/hotspot/cpu/x86/downcallLinker_x86_32.cpp b/src/hotspot/cpu/x86/downcallLinker_x86_32.cpp
index 3fc43c5031e..3f1241970f2 100644
--- a/src/hotspot/cpu/x86/downcallLinker_x86_32.cpp
+++ b/src/hotspot/cpu/x86/downcallLinker_x86_32.cpp
@@ -28,9 +28,10 @@ RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature,
int num_args,
BasicType ret_bt,
const ABIDescriptor& abi,
- const GrowableArray& input_registers,
- const GrowableArray& output_registers,
- bool needs_return_buffer) {
+ const GrowableArray& input_registers,
+ const GrowableArray& output_registers,
+ bool needs_return_buffer,
+ int captured_state_mask) {
Unimplemented();
return nullptr;
}
diff --git a/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp
index 06bf0099a91..9637057b6ab 100644
--- a/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp
+++ b/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp
@@ -41,13 +41,14 @@ class DowncallStubGenerator : public StubCodeGenerator {
BasicType _ret_bt;
const ABIDescriptor& _abi;
- const GrowableArray& _input_registers;
- const GrowableArray& _output_registers;
+ const GrowableArray& _input_registers;
+ const GrowableArray& _output_registers;
bool _needs_return_buffer;
+ int _captured_state_mask;
int _frame_complete;
- int _framesize;
+ int _frame_size_slots;
OopMapSet* _oop_maps;
public:
DowncallStubGenerator(CodeBuffer* buffer,
@@ -55,9 +56,10 @@ class DowncallStubGenerator : public StubCodeGenerator {
int num_args,
BasicType ret_bt,
const ABIDescriptor& abi,
- const GrowableArray& input_registers,
- const GrowableArray& output_registers,
- bool needs_return_buffer)
+ const GrowableArray& input_registers,
+ const GrowableArray& output_registers,
+ bool needs_return_buffer,
+ int captured_state_mask)
: StubCodeGenerator(buffer, PrintMethodHandleStubs),
_signature(signature),
_num_args(num_args),
@@ -66,8 +68,9 @@ class DowncallStubGenerator : public StubCodeGenerator {
_input_registers(input_registers),
_output_registers(output_registers),
_needs_return_buffer(needs_return_buffer),
+ _captured_state_mask(captured_state_mask),
_frame_complete(0),
- _framesize(0),
+ _frame_size_slots(0),
_oop_maps(NULL) {
}
@@ -77,8 +80,8 @@ class DowncallStubGenerator : public StubCodeGenerator {
return _frame_complete;
}
- int framesize() const {
- return (_framesize >> (LogBytesPerWord - LogBytesPerInt));
+ int framesize() const { // frame size in 64-bit words
+ return (_frame_size_slots >> (LogBytesPerWord - LogBytesPerInt));
}
OopMapSet* oop_maps() const {
@@ -92,12 +95,15 @@ RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature,
int num_args,
BasicType ret_bt,
const ABIDescriptor& abi,
- const GrowableArray& input_registers,
- const GrowableArray& output_registers,
- bool needs_return_buffer) {
- int locs_size = 64;
+ const GrowableArray& input_registers,
+ const GrowableArray& output_registers,
+ bool needs_return_buffer,
+ int captured_state_mask) {
+ int locs_size = 64;
CodeBuffer code("nep_invoker_blob", native_invoker_code_size, locs_size);
- DowncallStubGenerator g(&code, signature, num_args, ret_bt, abi, input_registers, output_registers, needs_return_buffer);
+ DowncallStubGenerator g(&code, signature, num_args, ret_bt, abi,
+ input_registers, output_registers,
+ needs_return_buffer, captured_state_mask);
g.generate();
code.log_section_sizes("nep_invoker_blob");
@@ -133,10 +139,10 @@ void DowncallStubGenerator::generate() {
// out arg area (e.g. for stack args)
};
- Register shufffle_reg = rbx;
+ VMStorage shuffle_reg = as_VMStorage(rbx);
JavaCallingConvention in_conv;
NativeCallingConvention out_conv(_input_registers);
- ArgumentShuffle arg_shuffle(_signature, _num_args, _signature, _num_args, &in_conv, &out_conv, shufffle_reg->as_VMReg());
+ ArgumentShuffle arg_shuffle(_signature, _num_args, _signature, _num_args, &in_conv, &out_conv, shuffle_reg);
#ifndef PRODUCT
LogTarget(Trace, foreign, downcall) lt;
@@ -149,34 +155,38 @@ void DowncallStubGenerator::generate() {
// in bytes
int allocated_frame_size = 0;
- if (_needs_return_buffer) {
- allocated_frame_size += 8; // store address
- }
- allocated_frame_size += arg_shuffle.out_arg_stack_slots() << LogBytesPerInt;
allocated_frame_size += _abi._shadow_space_bytes;
+ allocated_frame_size += arg_shuffle.out_arg_bytes();
- int ret_buf_addr_rsp_offset = -1;
- if (_needs_return_buffer) {
- // the above
- ret_buf_addr_rsp_offset = allocated_frame_size - 8;
- }
-
- // when we don't use a return buffer we need to spill the return value around our slowpath calls
- // when we use a return buffer case this SHOULD be unused.
+ // when we don't use a return buffer we need to spill the return value around our slow path calls
+ bool should_save_return_value = !_needs_return_buffer;
RegSpiller out_reg_spiller(_output_registers);
int spill_rsp_offset = -1;
- if (!_needs_return_buffer) {
+ if (should_save_return_value) {
spill_rsp_offset = 0;
- // spill area can be shared with the above, so we take the max of the 2
+ // spill area can be shared with shadow space and out args,
+ // since they are only used before the call,
+ // and spill area is only used after.
allocated_frame_size = out_reg_spiller.spill_size_bytes() > allocated_frame_size
? out_reg_spiller.spill_size_bytes()
: allocated_frame_size;
}
+
+ StubLocations locs;
+ locs.set(StubLocations::TARGET_ADDRESS, _abi._scratch1);
+ if (_needs_return_buffer) {
+ locs.set_frame_data(StubLocations::RETURN_BUFFER, allocated_frame_size);
+ allocated_frame_size += BytesPerWord;
+ }
+ if (_captured_state_mask != 0) {
+ locs.set_frame_data(StubLocations::CAPTURED_STATE_BUFFER, allocated_frame_size);
+ allocated_frame_size += BytesPerWord;
+ }
+
allocated_frame_size = align_up(allocated_frame_size, 16);
- // _framesize is in 32-bit stack slots:
- _framesize += framesize_base + (allocated_frame_size >> LogBytesPerInt);
- assert(is_even(_framesize/2), "sp not 16-byte aligned");
+ _frame_size_slots += framesize_base + (allocated_frame_size >> LogBytesPerInt);
+ assert(is_even(_frame_size_slots/2), "sp not 16-byte aligned");
_oop_maps = new OopMapSet();
address start = __ pc();
@@ -192,7 +202,7 @@ void DowncallStubGenerator::generate() {
__ block_comment("{ thread java2native");
__ set_last_Java_frame(rsp, rbp, (address)the_pc, rscratch1);
- OopMap* map = new OopMap(_framesize, 0);
+ OopMap* map = new OopMap(_frame_size_slots, 0);
_oop_maps->add_gc_map(the_pc - start, map);
// State transition
@@ -200,45 +210,22 @@ void DowncallStubGenerator::generate() {
__ block_comment("} thread java2native");
__ block_comment("{ argument shuffle");
- arg_shuffle.generate(_masm, shufffle_reg->as_VMReg(), 0, _abi._shadow_space_bytes);
- if (_needs_return_buffer) {
- // spill our return buffer address
- assert(ret_buf_addr_rsp_offset != -1, "no return buffer addr spill");
- __ movptr(Address(rsp, ret_buf_addr_rsp_offset), _abi._ret_buf_addr_reg);
- }
+ arg_shuffle.generate(_masm, shuffle_reg, 0, _abi._shadow_space_bytes, locs);
__ block_comment("} argument shuffle");
- __ call(_abi._target_addr_reg);
+ __ call(as_Register(locs.get(StubLocations::TARGET_ADDRESS)));
// this call is assumed not to have killed r15_thread
- if (!_needs_return_buffer) {
- // FIXME: this assumes we return in rax/xmm0, which might not be the case
- // Unpack native results.
- switch (_ret_bt) {
- case T_BOOLEAN: __ c2bool(rax); break;
- case T_CHAR : __ movzwl(rax, rax); break;
- case T_BYTE : __ sign_extend_byte (rax); break;
- case T_SHORT : __ sign_extend_short(rax); break;
- case T_INT : /* nothing to do */ break;
- case T_DOUBLE :
- case T_FLOAT :
- // Result is in xmm0 we'll save as needed
- break;
- case T_VOID: break;
- case T_LONG: break;
- default : ShouldNotReachHere();
- }
- } else {
- assert(ret_buf_addr_rsp_offset != -1, "no return buffer addr spill");
- __ movptr(rscratch1, Address(rsp, ret_buf_addr_rsp_offset));
+ if (_needs_return_buffer) {
+ __ movptr(rscratch1, Address(rsp, locs.data_offset(StubLocations::RETURN_BUFFER)));
int offset = 0;
for (int i = 0; i < _output_registers.length(); i++) {
- VMReg reg = _output_registers.at(i);
- if (reg->is_Register()) {
- __ movptr(Address(rscratch1, offset), reg->as_Register());
+ VMStorage reg = _output_registers.at(i);
+ if (reg.type() == StorageType::INTEGER) {
+ __ movptr(Address(rscratch1, offset), as_Register(reg));
offset += 8;
- } else if (reg->is_XMMRegister()) {
- __ movdqu(Address(rscratch1, offset), reg->as_XMMRegister());
+ } else if (reg.type() == StorageType::VECTOR) {
+ __ movdqu(Address(rscratch1, offset), as_XMMRegister(reg));
offset += 16;
} else {
ShouldNotReachHere();
@@ -246,6 +233,34 @@ void DowncallStubGenerator::generate() {
}
}
+ //////////////////////////////////////////////////////////////////////////////
+
+ if (_captured_state_mask != 0) {
+ __ block_comment("{ save thread local");
+ __ vzeroupper();
+
+ if (should_save_return_value) {
+ out_reg_spiller.generate_spill(_masm, spill_rsp_offset);
+ }
+
+ __ movptr(c_rarg0, Address(rsp, locs.data_offset(StubLocations::CAPTURED_STATE_BUFFER)));
+ __ movl(c_rarg1, _captured_state_mask);
+ __ mov(r12, rsp); // remember sp
+ __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
+ __ andptr(rsp, -16); // align stack as required by ABI
+ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, DowncallLinker::capture_state)));
+ __ mov(rsp, r12); // restore sp
+ __ reinit_heapbase();
+
+ if (should_save_return_value) {
+ out_reg_spiller.generate_fill(_masm, spill_rsp_offset);
+ }
+
+ __ block_comment("} save thread local");
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
__ block_comment("{ thread native2java");
__ restore_cpu_control_state_after_jni(rscratch1);
@@ -289,7 +304,7 @@ void DowncallStubGenerator::generate() {
__ bind(L_safepoint_poll_slow_path);
__ vzeroupper();
- if(!_needs_return_buffer) {
+ if (should_save_return_value) {
out_reg_spiller.generate_spill(_masm, spill_rsp_offset);
}
@@ -301,7 +316,7 @@ void DowncallStubGenerator::generate() {
__ mov(rsp, r12); // restore sp
__ reinit_heapbase();
- if(!_needs_return_buffer) {
+ if (should_save_return_value) {
out_reg_spiller.generate_fill(_masm, spill_rsp_offset);
}
@@ -314,7 +329,7 @@ void DowncallStubGenerator::generate() {
__ bind(L_reguard);
__ vzeroupper();
- if(!_needs_return_buffer) {
+ if (should_save_return_value) {
out_reg_spiller.generate_spill(_masm, spill_rsp_offset);
}
@@ -325,7 +340,7 @@ void DowncallStubGenerator::generate() {
__ mov(rsp, r12); // restore sp
__ reinit_heapbase();
- if(!_needs_return_buffer) {
+ if (should_save_return_value) {
out_reg_spiller.generate_fill(_masm, spill_rsp_offset);
}
diff --git a/src/hotspot/cpu/x86/foreignGlobals_x86.hpp b/src/hotspot/cpu/x86/foreignGlobals_x86.hpp
index 160aa468539..19999a416ea 100644
--- a/src/hotspot/cpu/x86/foreignGlobals_x86.hpp
+++ b/src/hotspot/cpu/x86/foreignGlobals_x86.hpp
@@ -40,8 +40,8 @@ struct ABIDescriptor {
int32_t _stack_alignment_bytes;
int32_t _shadow_space_bytes;
- Register _target_addr_reg;
- Register _ret_buf_addr_reg;
+ VMStorage _scratch1;
+ VMStorage _scratch2;
bool is_volatile_reg(Register reg) const;
bool is_volatile_reg(XMMRegister reg) const;
diff --git a/src/hotspot/cpu/x86/foreignGlobals_x86_32.cpp b/src/hotspot/cpu/x86/foreignGlobals_x86_32.cpp
index e196727674d..8a31955f4d1 100644
--- a/src/hotspot/cpu/x86/foreignGlobals_x86_32.cpp
+++ b/src/hotspot/cpu/x86/foreignGlobals_x86_32.cpp
@@ -33,24 +33,19 @@ const ABIDescriptor ForeignGlobals::parse_abi_descriptor(jobject jabi) {
return {};
}
-VMReg ForeignGlobals::vmstorage_to_vmreg(int type, int index) {
- Unimplemented();
- return VMRegImpl::Bad();
-}
-
-int RegSpiller::pd_reg_size(VMReg reg) {
+int RegSpiller::pd_reg_size(VMStorage reg) {
Unimplemented();
return -1;
}
-void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMReg reg) {
+void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMStorage reg) {
Unimplemented();
}
-void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMReg reg) {
+void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMStorage reg) {
Unimplemented();
}
-void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMReg tmp, int in_stk_bias, int out_stk_bias) const {
+void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMStorage tmp, int in_stk_bias, int out_stk_bias, const StubLocations& locs) const {
Unimplemented();
}
diff --git a/src/hotspot/cpu/x86/foreignGlobals_x86_64.cpp b/src/hotspot/cpu/x86/foreignGlobals_x86_64.cpp
index 3b3d5ff00df..74afbe4fd61 100644
--- a/src/hotspot/cpu/x86/foreignGlobals_x86_64.cpp
+++ b/src/hotspot/cpu/x86/foreignGlobals_x86_64.cpp
@@ -40,123 +40,154 @@ bool ABIDescriptor::is_volatile_reg(XMMRegister reg) const {
|| _vector_additional_volatile_registers.contains(reg);
}
-static constexpr int INTEGER_TYPE = 0;
-static constexpr int VECTOR_TYPE = 1;
-static constexpr int X87_TYPE = 2;
-
const ABIDescriptor ForeignGlobals::parse_abi_descriptor(jobject jabi) {
oop abi_oop = JNIHandles::resolve_non_null(jabi);
ABIDescriptor abi;
objArrayOop inputStorage = jdk_internal_foreign_abi_ABIDescriptor::inputStorage(abi_oop);
- parse_register_array(inputStorage, INTEGER_TYPE, abi._integer_argument_registers, as_Register);
- parse_register_array(inputStorage, VECTOR_TYPE, abi._vector_argument_registers, as_XMMRegister);
+ parse_register_array(inputStorage, StorageType::INTEGER, abi._integer_argument_registers, as_Register);
+ parse_register_array(inputStorage, StorageType::VECTOR, abi._vector_argument_registers, as_XMMRegister);
objArrayOop outputStorage = jdk_internal_foreign_abi_ABIDescriptor::outputStorage(abi_oop);
- parse_register_array(outputStorage, INTEGER_TYPE, abi._integer_return_registers, as_Register);
- parse_register_array(outputStorage, VECTOR_TYPE, abi._vector_return_registers, as_XMMRegister);
- objArrayOop subarray = oop_cast(outputStorage->obj_at(X87_TYPE));
+ parse_register_array(outputStorage, StorageType::INTEGER, abi._integer_return_registers, as_Register);
+ parse_register_array(outputStorage, StorageType::VECTOR, abi._vector_return_registers, as_XMMRegister);
+ objArrayOop subarray = oop_cast(outputStorage->obj_at((int) StorageType::X87));
abi._X87_return_registers_noof = subarray->length();
objArrayOop volatileStorage = jdk_internal_foreign_abi_ABIDescriptor::volatileStorage(abi_oop);
- parse_register_array(volatileStorage, INTEGER_TYPE, abi._integer_additional_volatile_registers, as_Register);
- parse_register_array(volatileStorage, VECTOR_TYPE, abi._vector_additional_volatile_registers, as_XMMRegister);
+ parse_register_array(volatileStorage, StorageType::INTEGER, abi._integer_additional_volatile_registers, as_Register);
+ parse_register_array(volatileStorage, StorageType::VECTOR, abi._vector_additional_volatile_registers, as_XMMRegister);
abi._stack_alignment_bytes = jdk_internal_foreign_abi_ABIDescriptor::stackAlignment(abi_oop);
abi._shadow_space_bytes = jdk_internal_foreign_abi_ABIDescriptor::shadowSpace(abi_oop);
- abi._target_addr_reg = parse_vmstorage(jdk_internal_foreign_abi_ABIDescriptor::targetAddrStorage(abi_oop))->as_Register();
- abi._ret_buf_addr_reg = parse_vmstorage(jdk_internal_foreign_abi_ABIDescriptor::retBufAddrStorage(abi_oop))->as_Register();
+ abi._scratch1 = parse_vmstorage(jdk_internal_foreign_abi_ABIDescriptor::scratch1(abi_oop));
+ abi._scratch2 = parse_vmstorage(jdk_internal_foreign_abi_ABIDescriptor::scratch2(abi_oop));
return abi;
}
-enum class RegType {
- INTEGER = 0,
- VECTOR = 1,
- X87 = 2,
- STACK = 3
-};
-
-VMReg ForeignGlobals::vmstorage_to_vmreg(int type, int index) {
- switch(static_cast(type)) {
- case RegType::INTEGER: return ::as_Register(index)->as_VMReg();
- case RegType::VECTOR: return ::as_XMMRegister(index)->as_VMReg();
- case RegType::STACK: return VMRegImpl::stack2reg(index LP64_ONLY(* 2)); // numbering on x64 goes per 64-bits
- case RegType::X87: break;
- }
- return VMRegImpl::Bad();
-}
-
-int RegSpiller::pd_reg_size(VMReg reg) {
- if (reg->is_Register()) {
+int RegSpiller::pd_reg_size(VMStorage reg) {
+ if (reg.type() == StorageType::INTEGER) {
return 8;
- } else if (reg->is_XMMRegister()) {
+ } else if (reg.type() == StorageType::VECTOR) {
return 16;
}
return 0; // stack and BAD
}
-void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMReg reg) {
- if (reg->is_Register()) {
- masm->movptr(Address(rsp, offset), reg->as_Register());
- } else if (reg->is_XMMRegister()) {
- masm->movdqu(Address(rsp, offset), reg->as_XMMRegister());
+void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMStorage reg) {
+ if (reg.type() == StorageType::INTEGER) {
+ masm->movptr(Address(rsp, offset), as_Register(reg));
+ } else if (reg.type() == StorageType::VECTOR) {
+ masm->movdqu(Address(rsp, offset), as_XMMRegister(reg));
} else {
// stack and BAD
}
}
-void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMReg reg) {
- if (reg->is_Register()) {
- masm->movptr(reg->as_Register(), Address(rsp, offset));
- } else if (reg->is_XMMRegister()) {
- masm->movdqu(reg->as_XMMRegister(), Address(rsp, offset));
+void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMStorage reg) {
+ if (reg.type() == StorageType::INTEGER) {
+ masm->movptr(as_Register(reg), Address(rsp, offset));
+ } else if (reg.type() == StorageType::VECTOR) {
+ masm->movdqu(as_XMMRegister(reg), Address(rsp, offset));
} else {
// stack and BAD
}
}
-void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMReg tmp, int in_stk_bias, int out_stk_bias) const {
- Register tmp_reg = tmp->as_Register();
+static constexpr int RBP_BIAS = 16; // skip old rbp and return address
+
+static void move_reg64(MacroAssembler* masm, int out_stk_bias,
+ Register from_reg, VMStorage to_reg) {
+ int out_bias = 0;
+ switch (to_reg.type()) {
+ case StorageType::INTEGER:
+ assert(to_reg.segment_mask() == REG64_MASK, "only moves to 64-bit registers supported");
+ masm->movq(as_Register(to_reg), from_reg);
+ break;
+ case StorageType::STACK:
+ out_bias = out_stk_bias;
+ case StorageType::FRAME_DATA:
+ assert(to_reg.stack_size() == 8, "only moves with 64-bit targets supported");
+ masm->movq(Address(rsp, to_reg.offset() + out_bias), from_reg);
+ break;
+ default: ShouldNotReachHere();
+ }
+}
+
+static void move_stack64(MacroAssembler* masm, Register tmp_reg, int out_stk_bias,
+ Address from_address, VMStorage to_reg) {
+ int out_bias = 0;
+ switch (to_reg.type()) {
+ case StorageType::INTEGER:
+ assert(to_reg.segment_mask() == REG64_MASK, "only moves to 64-bit registers supported");
+ masm->movq(as_Register(to_reg), from_address);
+ break;
+ case StorageType::VECTOR:
+ assert(to_reg.segment_mask() == XMM_MASK, "only moves to xmm registers supported");
+ masm->movdqu(as_XMMRegister(to_reg), from_address);
+ break;
+ case StorageType::STACK:
+ out_bias = out_stk_bias;
+ case StorageType::FRAME_DATA:
+ assert(to_reg.stack_size() == 8, "only moves with 64-bit targets supported");
+ masm->movq(tmp_reg, from_address);
+ masm->movq(Address(rsp, to_reg.offset() + out_bias), tmp_reg);
+ break;
+ default: ShouldNotReachHere();
+ }
+}
+
+static void move_xmm(MacroAssembler* masm, int out_stk_bias,
+ XMMRegister from_reg, VMStorage to_reg) {
+ switch (to_reg.type()) {
+ case StorageType::INTEGER: // windows vargarg floats
+ assert(to_reg.segment_mask() == REG64_MASK, "only moves to 64-bit registers supported");
+ masm->movq(as_Register(to_reg), from_reg);
+ break;
+ case StorageType::VECTOR:
+ assert(to_reg.segment_mask() == XMM_MASK, "only moves to xmm registers supported");
+ masm->movdqu(as_XMMRegister(to_reg), from_reg);
+ break;
+ case StorageType::STACK:
+ assert(to_reg.stack_size() == 8, "only moves with 64-bit targets supported");
+ masm->movq(Address(rsp, to_reg.offset() + out_stk_bias), from_reg);
+ break;
+ default: ShouldNotReachHere();
+ }
+}
+
+void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMStorage tmp, int in_stk_bias, int out_stk_bias, const StubLocations& locs) const {
+ Register tmp_reg = as_Register(tmp);
for (int i = 0; i < _moves.length(); i++) {
Move move = _moves.at(i);
- BasicType arg_bt = move.bt;
- VMRegPair from_vmreg = move.from;
- VMRegPair to_vmreg = move.to;
-
- masm->block_comment(err_msg("bt=%s", null_safe_string(type2name(arg_bt))));
- switch (arg_bt) {
- case T_BOOLEAN:
- case T_BYTE:
- case T_SHORT:
- case T_CHAR:
- case T_INT:
- masm->move32_64(from_vmreg, to_vmreg, tmp_reg, in_stk_bias, out_stk_bias);
- break;
+ VMStorage from_reg = move.from;
+ VMStorage to_reg = move.to;
- case T_FLOAT:
- if (to_vmreg.first()->is_Register()) { // Windows vararg call
- masm->movq(to_vmreg.first()->as_Register(), from_vmreg.first()->as_XMMRegister());
- } else {
- masm->float_move(from_vmreg, to_vmreg, tmp_reg, in_stk_bias, out_stk_bias);
- }
- break;
+ // replace any placeholders
+ if (from_reg.type() == StorageType::PLACEHOLDER) {
+ from_reg = locs.get(from_reg);
+ }
+ if (to_reg.type() == StorageType::PLACEHOLDER) {
+ to_reg = locs.get(to_reg);
+ }
- case T_DOUBLE:
- if (to_vmreg.first()->is_Register()) { // Windows vararg call
- masm->movq(to_vmreg.first()->as_Register(), from_vmreg.first()->as_XMMRegister());
- } else {
- masm->double_move(from_vmreg, to_vmreg, tmp_reg, in_stk_bias, out_stk_bias);
- }
+ switch (from_reg.type()) {
+ case StorageType::INTEGER:
+ assert(from_reg.segment_mask() == REG64_MASK, "only 64-bit register supported");
+ move_reg64(masm, out_stk_bias, as_Register(from_reg), to_reg);
break;
-
- case T_LONG:
- masm->long_move(from_vmreg, to_vmreg, tmp_reg, in_stk_bias, out_stk_bias);
+ case StorageType::VECTOR:
+ assert(from_reg.segment_mask() == XMM_MASK, "only xmm register supported");
+ move_xmm(masm, out_stk_bias, as_XMMRegister(from_reg), to_reg);
break;
-
- default:
- fatal("found in upcall args: %s", type2name(arg_bt));
+ case StorageType::STACK: {
+ assert(from_reg.stack_size() == 8, "only stack_size 8 supported");
+ Address from_addr(rbp, RBP_BIAS + from_reg.offset() + in_stk_bias);
+ move_stack64(masm, tmp_reg, out_stk_bias, from_addr, to_reg);
+ } break;
+ default: ShouldNotReachHere();
}
}
}
diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp
index 51a22b50163..58df83d4e4d 100644
--- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp
@@ -279,7 +279,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo
return;
}
Register thread = r15_thread;
- Address disarmed_addr(thread, in_bytes(bs_nm->thread_disarmed_offset()));
+ Address disarmed_addr(thread, in_bytes(bs_nm->thread_disarmed_guard_value_offset()));
// The immediate is the last 4 bytes, so if we align the start of the cmp
// instruction to 4 bytes, we know that the second half of it is also 4
// byte aligned, which means that the immediate will not cross a cache line
@@ -310,7 +310,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label*, La
Register tmp = rdi;
__ push(tmp);
- __ movptr(tmp, (intptr_t)bs_nm->disarmed_value_address());
+ __ movptr(tmp, (intptr_t)bs_nm->disarmed_guard_value_address());
Address disarmed_addr(tmp, 0);
__ align(4);
__ cmpl_imm32(disarmed_addr, 0);
diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp
index fa2f18c5389..648d5fbabe9 100644
--- a/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp
+++ b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp
@@ -56,7 +56,7 @@ class NativeNMethodCmpBarrier: public NativeInstruction {
address instruction_address() const { return addr_at(0); }
address immediate_address() const { return addr_at(imm_offset); }
- jint get_immedate() const { return int_at(imm_offset); }
+ jint get_immediate() const { return int_at(imm_offset); }
void set_immediate(jint imm) { set_int_at(imm_offset, imm); }
void verify() const;
};
@@ -176,29 +176,20 @@ static NativeNMethodCmpBarrier* native_nmethod_barrier(nmethod* nm) {
return barrier;
}
-void BarrierSetNMethod::disarm(nmethod* nm) {
+void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) {
if (!supports_entry_barrier(nm)) {
return;
}
NativeNMethodCmpBarrier* cmp = native_nmethod_barrier(nm);
- cmp->set_immediate(disarmed_value());
+ cmp->set_immediate(value);
}
-void BarrierSetNMethod::arm(nmethod* nm, int arm_value) {
+int BarrierSetNMethod::guard_value(nmethod* nm) {
if (!supports_entry_barrier(nm)) {
- return;
- }
-
- NativeNMethodCmpBarrier* cmp = native_nmethod_barrier(nm);
- cmp->set_immediate(arm_value);
-}
-
-bool BarrierSetNMethod::is_armed(nmethod* nm) {
- if (!supports_entry_barrier(nm)) {
- return false;
+ return disarmed_guard_value();
}
NativeNMethodCmpBarrier* cmp = native_nmethod_barrier(nm);
- return (disarmed_value() != cmp->get_immedate());
+ return cmp->get_immediate();
}
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 f3e19b41733..44f3f221fae 100644
--- a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad
+++ b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad
@@ -35,7 +35,7 @@ source %{
static void z_load_barrier(MacroAssembler& _masm, const MachNode* node, Address ref_addr, Register ref, Register tmp, uint8_t barrier_data) {
if (barrier_data == ZLoadBarrierElided) {
- return; // Elided.
+ return;
}
ZLoadBarrierStubC2* const stub = ZLoadBarrierStubC2::create(node, ref_addr, ref, tmp, barrier_data);
{
@@ -60,6 +60,27 @@ static void z_load_barrier_cmpxchg(MacroAssembler& _masm, const MachNode* node,
__ bind(*stub->continuation());
}
+static void z_cmpxchg_common(MacroAssembler& _masm, const MachNode* node, Register mem_reg, Register newval, Register tmp) {
+ // Compare value (oldval) is in rax
+ const Address mem = Address(mem_reg, 0);
+
+ if (node->barrier_data() != ZLoadBarrierElided) {
+ __ movptr(tmp, rax);
+ }
+
+ __ lock();
+ __ cmpxchgptr(newval, mem);
+
+ if (node->barrier_data() != ZLoadBarrierElided) {
+ Label good;
+ z_load_barrier_cmpxchg(_masm, node, mem, rax, tmp, good);
+ __ movptr(rax, tmp);
+ __ lock();
+ __ cmpxchgptr(newval, mem);
+ __ bind(good);
+ }
+}
+
%}
// Load Pointer
@@ -81,7 +102,7 @@ instruct zLoadP(rRegP dst, memory mem, rFlagsReg cr)
ins_pipe(ialu_reg_mem);
%}
-instruct zCompareAndExchangeP(memory mem, rax_RegP oldval, rRegP newval, rRegP tmp, rFlagsReg cr) %{
+instruct zCompareAndExchangeP(indirect mem, rax_RegP oldval, rRegP newval, rRegP tmp, rFlagsReg cr) %{
match(Set oldval (CompareAndExchangeP mem (Binary oldval newval)));
predicate(UseZGC && n->as_LoadStore()->barrier_data() == ZLoadBarrierStrong);
effect(KILL cr, TEMP tmp);
@@ -90,26 +111,14 @@ instruct zCompareAndExchangeP(memory mem, rax_RegP oldval, rRegP newval, rRegP t
"cmpxchgq $newval, $mem" %}
ins_encode %{
- if (barrier_data() != ZLoadBarrierElided) { // barrier could be elided by ZBarrierSetC2::analyze_dominating_barriers()
- __ movptr($tmp$$Register, $oldval$$Register);
- }
- __ lock();
- __ cmpxchgptr($newval$$Register, $mem$$Address);
-
- if (barrier_data() != ZLoadBarrierElided) {
- Label good;
- z_load_barrier_cmpxchg(_masm, this, $mem$$Address, $oldval$$Register, $tmp$$Register, good);
- __ movptr($oldval$$Register, $tmp$$Register);
- __ lock();
- __ cmpxchgptr($newval$$Register, $mem$$Address);
- __ bind(good);
- }
+ precond($oldval$$Register == rax);
+ z_cmpxchg_common(_masm, this, $mem$$Register, $newval$$Register, $tmp$$Register);
%}
ins_pipe(pipe_cmpxchg);
%}
-instruct zCompareAndSwapP(rRegI res, memory mem, rRegP newval, rRegP tmp, rFlagsReg cr, rax_RegP oldval) %{
+instruct zCompareAndSwapP(rRegI res, indirect mem, rRegP newval, rRegP tmp, rFlagsReg cr, rax_RegP oldval) %{
match(Set res (CompareAndSwapP mem (Binary oldval newval)));
match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
predicate(UseZGC && n->as_LoadStore()->barrier_data() == ZLoadBarrierStrong);
@@ -121,20 +130,10 @@ instruct zCompareAndSwapP(rRegI res, memory mem, rRegP newval, rRegP tmp, rFlags
"movzbl $res, $res" %}
ins_encode %{
- if (barrier_data() != ZLoadBarrierElided) { // barrier could be elided by ZBarrierSetC2::analyze_dominating_barriers()
- __ movptr($tmp$$Register, $oldval$$Register);
- }
- __ lock();
- __ cmpxchgptr($newval$$Register, $mem$$Address);
-
+ precond($oldval$$Register == rax);
+ z_cmpxchg_common(_masm, this, $mem$$Register, $newval$$Register, $tmp$$Register);
if (barrier_data() != ZLoadBarrierElided) {
- Label good;
- z_load_barrier_cmpxchg(_masm, this, $mem$$Address, $oldval$$Register, $tmp$$Register, good);
- __ movptr($oldval$$Register, $tmp$$Register);
- __ lock();
- __ cmpxchgptr($newval$$Register, $mem$$Address);
- __ bind(good);
- __ cmpptr($tmp$$Register, $oldval$$Register);
+ __ cmpptr($tmp$$Register, rax);
}
__ setb(Assembler::equal, $res$$Register);
__ movzbl($res$$Register, $res$$Register);
@@ -143,7 +142,7 @@ instruct zCompareAndSwapP(rRegI res, memory mem, rRegP newval, rRegP tmp, rFlags
ins_pipe(pipe_cmpxchg);
%}
-instruct zXChgP(memory mem, rRegP newval, rFlagsReg cr) %{
+instruct zXChgP(indirect mem, rRegP newval, rFlagsReg cr) %{
match(Set newval (GetAndSetP mem newval));
predicate(UseZGC && n->as_LoadStore()->barrier_data() != 0);
effect(KILL cr);
@@ -151,7 +150,7 @@ instruct zXChgP(memory mem, rRegP newval, rFlagsReg cr) %{
format %{ "xchgq $newval, $mem" %}
ins_encode %{
- __ xchgptr($newval$$Register, $mem$$Address);
+ __ xchgptr($newval$$Register, Address($mem$$Register, 0));
z_load_barrier(_masm, this, Address(noreg, 0), $newval$$Register, noreg /* tmp */, barrier_data());
%}
diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp
index 387a63c804a..0a5314d8faa 100644
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -5108,7 +5108,7 @@ void MacroAssembler::store_klass(Register dst, Register src, Register tmp) {
void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators, Register dst, Address src,
Register tmp1, Register thread_tmp) {
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
- decorators = AccessInternal::decorator_fixup(decorators);
+ decorators = AccessInternal::decorator_fixup(decorators, type);
bool as_raw = (decorators & AS_RAW) != 0;
if (as_raw) {
bs->BarrierSetAssembler::load_at(this, decorators, type, dst, src, tmp1, thread_tmp);
@@ -5120,7 +5120,7 @@ void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators, Reg
void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators, Address dst, Register val,
Register tmp1, Register tmp2, Register tmp3) {
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
- decorators = AccessInternal::decorator_fixup(decorators);
+ decorators = AccessInternal::decorator_fixup(decorators, type);
bool as_raw = (decorators & AS_RAW) != 0;
if (as_raw) {
bs->BarrierSetAssembler::store_at(this, decorators, type, dst, val, tmp1, tmp2, tmp3);
@@ -8228,24 +8228,27 @@ void MacroAssembler::crc32c_ipl_alg2_alt2(Register in_out, Register in1, Registe
addl(tmp1, in2);
addq(tmp1, in1);
- BIND(L_wordByWord);
cmpq(in1, tmp1);
- jcc(Assembler::greaterEqual, L_byteByByteProlog);
- crc32(in_out, Address(in1, 0), 4);
- addq(in1, 4);
- jmp(L_wordByWord);
+ jccb(Assembler::greaterEqual, L_byteByByteProlog);
+ align(16);
+ BIND(L_wordByWord);
+ crc32(in_out, Address(in1, 0), 8);
+ addq(in1, 8);
+ cmpq(in1, tmp1);
+ jcc(Assembler::less, L_wordByWord);
BIND(L_byteByByteProlog);
andl(in2, 0x00000007);
movl(tmp2, 1);
- BIND(L_byteByByte);
cmpl(tmp2, in2);
jccb(Assembler::greater, L_exit);
+ BIND(L_byteByByte);
crc32(in_out, Address(in1, 0), 1);
incq(in1);
incl(tmp2);
- jmp(L_byteByByte);
+ cmpl(tmp2, in2);
+ jcc(Assembler::lessEqual, L_byteByByte);
BIND(L_exit);
}
@@ -9013,26 +9016,6 @@ void MacroAssembler::evand(BasicType type, XMMRegister dst, KRegister mask, XMMR
}
}
-void MacroAssembler::anytrue(Register dst, uint masklen, KRegister src1, KRegister src2) {
- masklen = masklen < 8 ? 8 : masklen;
- ktest(masklen, src1, src2);
- setb(Assembler::notZero, dst);
- movzbl(dst, dst);
-}
-
-void MacroAssembler::alltrue(Register dst, uint masklen, KRegister src1, KRegister src2, KRegister kscratch) {
- if (masklen < 8) {
- knotbl(kscratch, src2);
- kortestbl(src1, kscratch);
- setb(Assembler::carrySet, dst);
- movzbl(dst, dst);
- } else {
- ktest(masklen, src1, src2);
- setb(Assembler::carrySet, dst);
- movzbl(dst, dst);
- }
-}
-
void MacroAssembler::kortest(uint masklen, KRegister src1, KRegister src2) {
switch(masklen) {
case 8:
diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp
index 5a0a3d8c9a1..2baff498df6 100644
--- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp
@@ -1768,9 +1768,6 @@ class MacroAssembler: public Assembler {
using Assembler::vpternlogq;
void vpternlogq(XMMRegister dst, int imm8, XMMRegister src2, AddressLiteral src3, int vector_len, Register rscratch = noreg);
- void alltrue(Register dst, uint masklen, KRegister src1, KRegister src2, KRegister kscratch);
- void anytrue(Register dst, uint masklen, KRegister src, KRegister kscratch);
-
void cmov32( Condition cc, Register dst, Address src);
void cmov32( Condition cc, Register dst, Register src);
diff --git a/src/hotspot/cpu/x86/matcher_x86.hpp b/src/hotspot/cpu/x86/matcher_x86.hpp
index bc6524aed55..82a39fe8b1d 100644
--- a/src/hotspot/cpu/x86/matcher_x86.hpp
+++ b/src/hotspot/cpu/x86/matcher_x86.hpp
@@ -183,6 +183,25 @@
// Implements a variant of EncodeISOArrayNode that encode ASCII only
static const bool supports_encode_ascii_array = true;
+ // Without predicated input, an all-one vector is needed for the alltrue vector test
+ static constexpr bool vectortest_needs_second_argument(bool is_alltrue, bool is_predicate) {
+ return is_alltrue && !is_predicate;
+ }
+
+ // BoolTest mask for vector test intrinsics
+ static constexpr BoolTest::mask vectortest_mask(bool is_alltrue, bool is_predicate, int vlen) {
+ if (!is_alltrue) {
+ return BoolTest::ne;
+ }
+ if (!is_predicate) {
+ return BoolTest::lt;
+ }
+ if ((vlen == 8 && !VM_Version::supports_avx512dq()) || vlen < 8) {
+ return BoolTest::eq;
+ }
+ return BoolTest::lt;
+ }
+
// Returns pre-selection estimated size of a vector operation.
// Currently, it's a rudimentary heuristic based on emitted code size for complex
// IR nodes used by unroll policy. Idea is to constrain unrolling factor and prevent
diff --git a/src/hotspot/cpu/x86/register_x86.hpp b/src/hotspot/cpu/x86/register_x86.hpp
index 83d12a809e0..e310646ba93 100644
--- a/src/hotspot/cpu/x86/register_x86.hpp
+++ b/src/hotspot/cpu/x86/register_x86.hpp
@@ -56,9 +56,9 @@ class Register {
public:
// accessors
- int raw_encoding() const { return this - first(); }
- int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); }
- bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; }
+ constexpr int raw_encoding() const { return this - first(); }
+ constexpr int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); }
+ constexpr bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; }
bool has_byte_register() const { return 0 <= raw_encoding() && raw_encoding() < number_of_byte_registers; }
// derived registers, offsets, and addresses
@@ -74,7 +74,7 @@ class Register {
int operator==(const Register r) const { return _encoding == r._encoding; }
int operator!=(const Register r) const { return _encoding != r._encoding; }
- const RegisterImpl* operator->() const { return RegisterImpl::first() + _encoding; }
+ constexpr const RegisterImpl* operator->() const { return RegisterImpl::first() + _encoding; }
};
extern Register::RegisterImpl all_RegisterImpls[Register::number_of_registers + 1] INTERNAL_VISIBILITY;
@@ -202,9 +202,9 @@ class XMMRegister {
public:
// accessors
- int raw_encoding() const { return this - first(); }
- int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); }
- bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; }
+ constexpr int raw_encoding() const { return this - first(); }
+ constexpr int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); }
+ constexpr bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; }
// derived registers, offsets, and addresses
inline XMMRegister successor() const;
@@ -219,7 +219,7 @@ class XMMRegister {
int operator==(const XMMRegister r) const { return _encoding == r._encoding; }
int operator!=(const XMMRegister r) const { return _encoding != r._encoding; }
- const XMMRegisterImpl* operator->() const { return XMMRegisterImpl::first() + _encoding; }
+ constexpr const XMMRegisterImpl* operator->() const { return XMMRegisterImpl::first() + _encoding; }
// Actually available XMM registers for use, depending on actual CPU capabilities and flags.
static int available_xmm_registers() {
diff --git a/src/hotspot/cpu/x86/stackChunkFrameStream_x86.inline.hpp b/src/hotspot/cpu/x86/stackChunkFrameStream_x86.inline.hpp
index 70f10dc646d..6240de27b6b 100644
--- a/src/hotspot/cpu/x86/stackChunkFrameStream_x86.inline.hpp
+++ b/src/hotspot/cpu/x86/stackChunkFrameStream_x86.inline.hpp
@@ -76,12 +76,6 @@ inline intptr_t* StackChunkFrameStream::unextended_sp_for_interprete
return derelativize(frame::interpreter_frame_last_sp_offset);
}
-template
-intptr_t* StackChunkFrameStream::next_sp_for_interpreter_frame() const {
- assert_is_interpreted_and_frame_type_mixed();
- return (derelativize(frame::interpreter_frame_locals_offset) + 1 >= _end) ? _end : fp() + frame::sender_sp_offset;
-}
-
template
inline void StackChunkFrameStream::next_for_interpreter_frame() {
assert_is_interpreted_and_frame_type_mixed();
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp
index 95dc03200eb..d7a613052a3 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp
@@ -3709,7 +3709,7 @@ void StubGenerator::generate_initial() {
StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32();
}
- if (UsePolyIntrinsics) {
+ if (UsePoly1305Intrinsics) {
StubRoutines::_poly1305_processBlocks = generate_poly1305_processBlocks();
}
diff --git a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp
index e37491edfe8..3e3214b51b1 100644
--- a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp
+++ b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp
@@ -175,12 +175,13 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
const CallRegs call_regs = ForeignGlobals::parse_call_regs(jconv);
CodeBuffer buffer("upcall_stub", /* code_size = */ 2048, /* locs_size = */ 1024);
- Register shuffle_reg = rbx;
+ VMStorage shuffle_reg = as_VMStorage(rbx);
JavaCallingConvention out_conv;
NativeCallingConvention in_conv(call_regs._arg_regs);
- ArgumentShuffle arg_shuffle(in_sig_bt, total_in_args, out_sig_bt, total_out_args, &in_conv, &out_conv, shuffle_reg->as_VMReg());
- int stack_slots = SharedRuntime::out_preserve_stack_slots() + arg_shuffle.out_arg_stack_slots();
- int out_arg_area = align_up(stack_slots * VMRegImpl::stack_slot_size, StackAlignmentInBytes);
+ ArgumentShuffle arg_shuffle(in_sig_bt, total_in_args, out_sig_bt, total_out_args, &in_conv, &out_conv, shuffle_reg);
+ int preserved_bytes = SharedRuntime::out_preserve_stack_slots() * VMRegImpl::stack_slot_size;
+ int stack_bytes = preserved_bytes + arg_shuffle.out_arg_bytes();
+ int out_arg_area = align_up(stack_bytes , StackAlignmentInBytes);
#ifndef PRODUCT
LogTarget(Trace, foreign, upcall) lt;
@@ -208,10 +209,14 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
int frame_data_offset = reg_save_area_offset + reg_save_area_size;
int frame_bottom_offset = frame_data_offset + sizeof(UpcallStub::FrameData);
+ StubLocations locs;
int ret_buf_offset = -1;
if (needs_return_buffer) {
ret_buf_offset = frame_bottom_offset;
frame_bottom_offset += ret_buf_size;
+ // use a free register for shuffling code to pick up return
+ // buffer address from
+ locs.set(StubLocations::RETURN_BUFFER, abi._scratch1);
}
int frame_size = frame_bottom_offset;
@@ -273,9 +278,9 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
arg_spilller.generate_fill(_masm, arg_save_area_offset);
if (needs_return_buffer) {
assert(ret_buf_offset != -1, "no return buffer allocated");
- __ lea(abi._ret_buf_addr_reg, Address(rsp, ret_buf_offset));
+ __ lea(as_Register(locs.get(StubLocations::RETURN_BUFFER)), Address(rsp, ret_buf_offset));
}
- arg_shuffle.generate(_masm, shuffle_reg->as_VMReg(), abi._shadow_space_bytes, 0);
+ arg_shuffle.generate(_masm, shuffle_reg, abi._shadow_space_bytes, 0, locs);
__ block_comment("} argument shuffle");
__ block_comment("{ receiver ");
@@ -293,7 +298,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
if (!needs_return_buffer) {
#ifdef ASSERT
if (call_regs._ret_regs.length() == 1) { // 0 or 1
- VMReg j_expected_result_reg;
+ VMStorage j_expected_result_reg;
switch (ret_type) {
case T_BOOLEAN:
case T_BYTE:
@@ -301,19 +306,18 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
case T_CHAR:
case T_INT:
case T_LONG:
- j_expected_result_reg = rax->as_VMReg();
+ j_expected_result_reg = as_VMStorage(rax);
break;
case T_FLOAT:
case T_DOUBLE:
- j_expected_result_reg = xmm0->as_VMReg();
+ j_expected_result_reg = as_VMStorage(xmm0);
break;
default:
fatal("unexpected return type: %s", type2name(ret_type));
}
// No need to move for now, since CallArranger can pick a return type
// that goes in the same reg for both CCs. But, at least assert they are the same
- assert(call_regs._ret_regs.at(0) == j_expected_result_reg,
- "unexpected result register: %s != %s", call_regs._ret_regs.at(0)->name(), j_expected_result_reg->name());
+ assert(call_regs._ret_regs.at(0) == j_expected_result_reg, "unexpected result register");
}
#endif
} else {
@@ -321,12 +325,12 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
__ lea(rscratch1, Address(rsp, ret_buf_offset));
int offset = 0;
for (int i = 0; i < call_regs._ret_regs.length(); i++) {
- VMReg reg = call_regs._ret_regs.at(i);
- if (reg->is_Register()) {
- __ movptr(reg->as_Register(), Address(rscratch1, offset));
+ VMStorage reg = call_regs._ret_regs.at(i);
+ if (reg.type() == StorageType::INTEGER) {
+ __ movptr(as_Register(reg), Address(rscratch1, offset));
offset += 8;
- } else if (reg->is_XMMRegister()) {
- __ movdqu(reg->as_XMMRegister(), Address(rscratch1, offset));
+ } else if (reg.type() == StorageType::VECTOR) {
+ __ movdqu(as_XMMRegister(reg), Address(rscratch1, offset));
offset += 16;
} else {
ShouldNotReachHere();
@@ -389,9 +393,13 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
receiver,
in_ByteSize(frame_data_offset));
- if (TraceOptimizedUpcallStubs) {
- blob->print_on(tty);
+#ifndef PRODUCT
+ if (lt.is_enabled()) {
+ ResourceMark rm;
+ LogStream ls(lt);
+ blob->print_on(&ls);
}
+#endif
return blob->code_begin();
}
diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp
index 5a0a085401b..ba2da1fcd1a 100644
--- a/src/hotspot/cpu/x86/vm_version_x86.cpp
+++ b/src/hotspot/cpu/x86/vm_version_x86.cpp
@@ -956,6 +956,7 @@ void VM_Version::get_processor_features() {
if (UseAVX < 1) {
_features &= ~CPU_AVX;
_features &= ~CPU_VZEROUPPER;
+ _features &= ~CPU_F16C;
}
if (logical_processors_per_package() == 1) {
@@ -1350,14 +1351,14 @@ void VM_Version::get_processor_features() {
#ifdef _LP64
if (supports_avx512ifma() && supports_avx512vlbw() && MaxVectorSize >= 64) {
- if (FLAG_IS_DEFAULT(UsePolyIntrinsics)) {
- FLAG_SET_DEFAULT(UsePolyIntrinsics, true);
+ if (FLAG_IS_DEFAULT(UsePoly1305Intrinsics)) {
+ FLAG_SET_DEFAULT(UsePoly1305Intrinsics, true);
}
} else
#endif
- if (UsePolyIntrinsics) {
+ if (UsePoly1305Intrinsics) {
warning("Intrinsics for Poly1305 crypto hash functions not available on this CPU.");
- FLAG_SET_DEFAULT(UsePolyIntrinsics, false);
+ FLAG_SET_DEFAULT(UsePoly1305Intrinsics, false);
}
#ifdef _LP64
diff --git a/src/hotspot/cpu/x86/vmstorage_x86.hpp b/src/hotspot/cpu/x86/vmstorage_x86.hpp
new file mode 100644
index 00000000000..a6ad21b2179
--- /dev/null
+++ b/src/hotspot/cpu/x86/vmstorage_x86.hpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef CPU_X86_VMSTORAGE_X86_INLINE_HPP
+#define CPU_X86_VMSTORAGE_X86_INLINE_HPP
+
+#include
+
+#include "asm/register.hpp"
+#include "code/vmreg.inline.hpp"
+
+// keep in sync with jdk/internal/foreign/abi/x64/X86_64Architecture
+enum class StorageType : int8_t {
+ INTEGER = 0,
+ VECTOR = 1,
+ X87 = 2,
+ STACK = 3,
+ PLACEHOLDER = 4,
+// special locations used only by native code
+ FRAME_DATA = PLACEHOLDER + 1,
+ INVALID = -1
+};
+
+// need to define this before constructing VMStorage (below)
+constexpr inline bool VMStorage::is_reg(StorageType type) {
+ return type == StorageType::INTEGER || type == StorageType::VECTOR || type == StorageType::X87;
+}
+constexpr inline StorageType VMStorage::stack_type() { return StorageType::STACK; }
+constexpr inline StorageType VMStorage::placeholder_type() { return StorageType::PLACEHOLDER; }
+constexpr inline StorageType VMStorage::frame_data_type() { return StorageType::FRAME_DATA; }
+
+constexpr uint16_t REG64_MASK = 0b0000000000001111;
+constexpr uint16_t XMM_MASK = 0b0000000000000001;
+
+inline Register as_Register(VMStorage vms) {
+ assert(vms.type() == StorageType::INTEGER, "not the right type");
+ return ::as_Register(vms.index());
+}
+
+inline XMMRegister as_XMMRegister(VMStorage vms) {
+ assert(vms.type() == StorageType::VECTOR, "not the right type");
+ return ::as_XMMRegister(vms.index());
+}
+
+inline VMReg as_VMReg(VMStorage vms) {
+ switch (vms.type()) {
+ case StorageType::INTEGER: return as_Register(vms)->as_VMReg();
+ case StorageType::VECTOR: return as_XMMRegister(vms)->as_VMReg();
+ case StorageType::STACK: {
+ assert((vms.index() % VMRegImpl::stack_slot_size) == 0, "can not represent as VMReg");
+ return VMRegImpl::stack2reg(vms.index() / VMRegImpl::stack_slot_size);
+ }
+ default: ShouldNotReachHere(); return VMRegImpl::Bad();
+ }
+}
+
+constexpr inline VMStorage as_VMStorage(Register reg) {
+ return VMStorage::reg_storage(StorageType::INTEGER, REG64_MASK, reg->encoding());
+}
+
+constexpr inline VMStorage as_VMStorage(XMMRegister reg) {
+ return VMStorage::reg_storage(StorageType::VECTOR, XMM_MASK, reg->encoding());
+}
+
+inline VMStorage as_VMStorage(VMReg reg) {
+ if (reg->is_Register()) {
+ return as_VMStorage(reg->as_Register());
+ } else if (reg->is_XMMRegister()) {
+ return as_VMStorage(reg->as_XMMRegister());
+ } else if (reg->is_stack()) {
+ return VMStorage::stack_storage(reg);
+ } else if (!reg->is_valid()) {
+ return VMStorage::invalid();
+ }
+
+ ShouldNotReachHere();
+ return VMStorage::invalid();
+}
+
+#endif // CPU_X86_VMSTORAGE_X86_INLINE_HPP
\ No newline at end of file
diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad
index a6f2adabb28..80f0c0f4b49 100644
--- a/src/hotspot/cpu/x86/x86.ad
+++ b/src/hotspot/cpu/x86/x86.ad
@@ -1687,6 +1687,12 @@ const bool Matcher::match_rule_supported(int opcode) {
return false;
}
break;
+ case Op_VectorCastF2HF:
+ case Op_VectorCastHF2F:
+ if (!VM_Version::supports_f16c() && !VM_Version::supports_evex()) {
+ return false;
+ }
+ break;
}
return true; // Match rules are supported by default.
}
@@ -1844,8 +1850,6 @@ const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType
return false; // Implementation limitation
} else if (size_in_bits < 32) {
return false; // Implementation limitation
- } else if (size_in_bits == 512 && (VM_Version::supports_avx512bw() == false)) {
- return false; // Implementation limitation
}
break;
case Op_VectorLoadShuffle:
@@ -1901,6 +1905,14 @@ const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType
return false;
}
break;
+ case Op_VectorCastF2HF:
+ case Op_VectorCastHF2F:
+ if (!VM_Version::supports_f16c() &&
+ ((!VM_Version::supports_evex() ||
+ ((size_in_bits != 512) && !VM_Version::supports_avx512vl())))) {
+ return false;
+ }
+ break;
case Op_RoundVD:
if (!VM_Version::supports_avx512dq()) {
return false;
@@ -3673,6 +3685,26 @@ instruct convF2HF_mem_reg(memory mem, regF src, kReg ktmp, rRegI rtmp) %{
ins_pipe( pipe_slow );
%}
+instruct vconvF2HF(vec dst, vec src) %{
+ match(Set dst (VectorCastF2HF src));
+ format %{ "vector_conv_F2HF $dst $src" %}
+ ins_encode %{
+ int vlen_enc = vector_length_encoding(this, $src);
+ __ vcvtps2ph($dst$$XMMRegister, $src$$XMMRegister, 0x04, vlen_enc);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vconvF2HF_mem_reg(memory mem, vec src) %{
+ match(Set mem (StoreVector mem (VectorCastF2HF src)));
+ format %{ "vcvtps2ph $mem,$src" %}
+ ins_encode %{
+ int vlen_enc = vector_length_encoding(this, $src);
+ __ vcvtps2ph($mem$$Address, $src$$XMMRegister, 0x04, vlen_enc);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
instruct convHF2F_reg_reg(regF dst, rRegI src) %{
match(Set dst (ConvHF2F src));
format %{ "vcvtph2ps $dst,$src" %}
@@ -3683,6 +3715,27 @@ instruct convHF2F_reg_reg(regF dst, rRegI src) %{
ins_pipe( pipe_slow );
%}
+instruct vconvHF2F_reg_mem(vec dst, memory mem) %{
+ match(Set dst (VectorCastHF2F (LoadVector mem)));
+ format %{ "vcvtph2ps $dst,$mem" %}
+ ins_encode %{
+ int vlen_enc = vector_length_encoding(this);
+ __ vcvtph2ps($dst$$XMMRegister, $mem$$Address, vlen_enc);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vconvHF2F(vec dst, vec src) %{
+ match(Set dst (VectorCastHF2F src));
+ ins_cost(125);
+ format %{ "vector_conv_HF2F $dst,$src" %}
+ ins_encode %{
+ int vlen_enc = vector_length_encoding(this);
+ __ vcvtph2ps($dst$$XMMRegister, $src$$XMMRegister, vlen_enc);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
// ---------------------------------------- VectorReinterpret ------------------------------------
instruct reinterpret_mask(kReg dst) %{
predicate(n->bottom_type()->isa_vectmask() &&
@@ -7993,169 +8046,70 @@ instruct vabsnegD(vec dst, vec src) %{
//------------------------------------- VectorTest --------------------------------------------
#ifdef _LP64
-instruct vptest_alltrue_lt16(rRegI dst, legVec src1, legVec src2, legVec vtmp1, legVec vtmp2, rFlagsReg cr) %{
- predicate(!VM_Version::supports_avx512bwdq() &&
- Matcher::vector_length_in_bytes(n->in(1)) >= 4 &&
- Matcher::vector_length_in_bytes(n->in(1)) < 16 &&
- static_cast(n)->get_predicate() == BoolTest::overflow);
- match(Set dst (VectorTest src1 src2 ));
- effect(TEMP vtmp1, TEMP vtmp2, KILL cr);
- format %{ "vptest_alltrue_lt16 $dst,$src1, $src2\t! using $vtmp1, $vtmp2 and $cr as TEMP" %}
+instruct vptest_lt16(rFlagsRegU cr, legVec src1, legVec src2, legVec vtmp) %{
+ predicate(Matcher::vector_length_in_bytes(n->in(1)) < 16);
+ match(Set cr (VectorTest src1 src2));
+ effect(TEMP vtmp);
+ format %{ "vptest_lt16 $src1, $src2\t! using $vtmp as TEMP" %}
ins_encode %{
+ BasicType bt = Matcher::vector_element_basic_type(this, $src1);
int vlen = Matcher::vector_length_in_bytes(this, $src1);
- __ vectortest(BoolTest::overflow, vlen, $src1$$XMMRegister, $src2$$XMMRegister, $vtmp1$$XMMRegister, $vtmp2$$XMMRegister);
- __ setb(Assembler::carrySet, $dst$$Register);
- __ movzbl($dst$$Register, $dst$$Register);
+ __ vectortest(bt, $src1$$XMMRegister, $src2$$XMMRegister, $vtmp$$XMMRegister, vlen);
%}
ins_pipe( pipe_slow );
%}
-instruct vptest_alltrue_ge16(rRegI dst, legVec src1, legVec src2, rFlagsReg cr) %{
- predicate(!VM_Version::supports_avx512bwdq() &&
- Matcher::vector_length_in_bytes(n->in(1)) >= 16 &&
- Matcher::vector_length_in_bytes(n->in(1)) < 64 &&
- static_cast(n)->get_predicate() == BoolTest::overflow);
- match(Set dst (VectorTest src1 src2 ));
- effect(KILL cr);
- format %{ "vptest_alltrue_ge16 $dst,$src1, $src2\t! using $cr as TEMP" %}
+instruct vptest_ge16(rFlagsRegU cr, legVec src1, legVec src2) %{
+ predicate(Matcher::vector_length_in_bytes(n->in(1)) >= 16);
+ match(Set cr (VectorTest src1 src2));
+ format %{ "vptest_ge16 $src1, $src2\n\t" %}
ins_encode %{
+ BasicType bt = Matcher::vector_element_basic_type(this, $src1);
int vlen = Matcher::vector_length_in_bytes(this, $src1);
- __ vectortest(BoolTest::overflow, vlen, $src1$$XMMRegister, $src2$$XMMRegister, xnoreg, xnoreg, knoreg);
- __ setb(Assembler::carrySet, $dst$$Register);
- __ movzbl($dst$$Register, $dst$$Register);
+ __ vectortest(bt, $src1$$XMMRegister, $src2$$XMMRegister, xnoreg, vlen);
%}
ins_pipe( pipe_slow );
%}
-instruct vptest_alltrue_lt8_evex(rRegI dst, kReg src1, kReg src2, kReg kscratch, rFlagsReg cr) %{
- predicate(VM_Version::supports_avx512bwdq() &&
- static_cast(n)->get_predicate() == BoolTest::overflow &&
- n->in(1)->bottom_type()->isa_vectmask() &&
- Matcher::vector_length(n->in(1)) < 8);
- match(Set dst (VectorTest src1 src2));
- effect(KILL cr, TEMP kscratch);
- format %{ "vptest_alltrue_lt8_evex $dst,$src1,$src2\t! using $cr as TEMP" %}
- ins_encode %{
- const MachNode* mask1 = static_cast(this->in(this->operand_index($src1)));
- const MachNode* mask2 = static_cast(this->in(this->operand_index($src2)));
- assert(0 == Type::cmp(mask1->bottom_type(), mask2->bottom_type()), "");
- uint masklen = Matcher::vector_length(this, $src1);
- __ alltrue($dst$$Register, masklen, $src1$$KRegister, $src2$$KRegister, $kscratch$$KRegister);
- %}
- ins_pipe( pipe_slow );
-%}
-
-
-instruct vptest_alltrue_ge8_evex(rRegI dst, kReg src1, kReg src2, rFlagsReg cr) %{
- predicate(VM_Version::supports_avx512bwdq() &&
- static_cast(n)->get_predicate() == BoolTest::overflow &&
- n->in(1)->bottom_type()->isa_vectmask() &&
- Matcher::vector_length(n->in(1)) >= 8);
- match(Set dst (VectorTest src1 src2));
- effect(KILL cr);
- format %{ "vptest_alltrue_ge8_evex $dst,$src1,$src2\t! using $cr as TEMP" %}
+instruct ktest_alltrue_le8(rFlagsRegU cr, kReg src1, kReg src2, rRegI tmp) %{
+ predicate((Matcher::vector_length(n->in(1)) < 8 ||
+ (Matcher::vector_length(n->in(1)) == 8 && !VM_Version::supports_avx512dq())) &&
+ static_cast(n)->get_predicate() == BoolTest::overflow);
+ match(Set cr (VectorTest src1 src2));
+ effect(TEMP tmp);
+ format %{ "ktest_alltrue_le8 $src1, $src2\t! using $tmp as TEMP" %}
ins_encode %{
- const MachNode* mask1 = static_cast(this->in(this->operand_index($src1)));
- const MachNode* mask2 = static_cast(this->in(this->operand_index($src2)));
- assert(0 == Type::cmp(mask1->bottom_type(), mask2->bottom_type()), "");
uint masklen = Matcher::vector_length(this, $src1);
- __ alltrue($dst$$Register, masklen, $src1$$KRegister, $src2$$KRegister, knoreg);
+ __ kmovwl($tmp$$Register, $src1$$KRegister);
+ __ andl($tmp$$Register, (1 << masklen) - 1);
+ __ cmpl($tmp$$Register, (1 << masklen) - 1);
%}
ins_pipe( pipe_slow );
%}
-
-instruct vptest_anytrue_lt16(rRegI dst, legVec src1, legVec src2, legVec vtmp, rFlagsReg cr) %{
- predicate(!VM_Version::supports_avx512bwdq() &&
- Matcher::vector_length_in_bytes(n->in(1)) >= 4 &&
- Matcher::vector_length_in_bytes(n->in(1)) < 16 &&
+instruct ktest_anytrue_le8(rFlagsRegU cr, kReg src1, kReg src2, rRegI tmp) %{
+ predicate((Matcher::vector_length(n->in(1)) < 8 ||
+ (Matcher::vector_length(n->in(1)) == 8 && !VM_Version::supports_avx512dq())) &&
static_cast(n)->get_predicate() == BoolTest::ne);
- match(Set dst (VectorTest src1 src2 ));
- effect(TEMP vtmp, KILL cr);
- format %{ "vptest_anytrue_lt16 $dst,$src1,$src2\t! using $vtmp, $cr as TEMP" %}
- ins_encode %{
- int vlen = Matcher::vector_length_in_bytes(this, $src1);
- __ vectortest(BoolTest::ne, vlen, $src1$$XMMRegister, $src2$$XMMRegister, $vtmp$$XMMRegister);
- __ setb(Assembler::notZero, $dst$$Register);
- __ movzbl($dst$$Register, $dst$$Register);
- %}
- ins_pipe( pipe_slow );
-%}
-
-instruct vptest_anytrue_ge16(rRegI dst, legVec src1, legVec src2, rFlagsReg cr) %{
- predicate(!VM_Version::supports_avx512bwdq() &&
- Matcher::vector_length_in_bytes(n->in(1)) >= 16 &&
- Matcher::vector_length_in_bytes(n->in(1)) < 64 &&
- static_cast(n)->get_predicate() == BoolTest::ne);
- match(Set dst (VectorTest src1 src2 ));
- effect(KILL cr);
- format %{ "vptest_anytrue_ge16 $dst,$src1,$src2\t! using $cr as TEMP" %}
- ins_encode %{
- int vlen = Matcher::vector_length_in_bytes(this, $src1);
- __ vectortest(BoolTest::ne, vlen, $src1$$XMMRegister, $src2$$XMMRegister, xnoreg, xnoreg, knoreg);
- __ setb(Assembler::notZero, $dst$$Register);
- __ movzbl($dst$$Register, $dst$$Register);
- %}
- ins_pipe( pipe_slow );
-%}
-
-instruct vptest_anytrue_evex(rRegI dst, kReg src1, kReg src2, rFlagsReg cr) %{
- predicate(VM_Version::supports_avx512bwdq() &&
- static_cast(n)->get_predicate() == BoolTest::ne);
- match(Set dst (VectorTest src1 src2));
- effect(KILL cr);
- format %{ "vptest_anytrue_lt8_evex $dst,$src1,$src2\t! using $cr as TEMP" %}
- ins_encode %{
- const MachNode* mask1 = static_cast(this->in(this->operand_index($src1)));
- const MachNode* mask2 = static_cast(this->in(this->operand_index($src2)));
- assert(0 == Type::cmp(mask1->bottom_type(), mask2->bottom_type()), "");
- uint masklen = Matcher::vector_length(this, $src1);
- __ anytrue($dst$$Register, masklen, $src1$$KRegister, $src2$$KRegister);
- %}
- ins_pipe( pipe_slow );
-%}
-
-instruct cmpvptest_anytrue_lt16(rFlagsReg cr, legVec src1, legVec src2, immI_0 zero, legVec vtmp) %{
- predicate(!VM_Version::supports_avx512bwdq() &&
- Matcher::vector_length_in_bytes(n->in(1)->in(1)) >= 4 &&
- Matcher::vector_length_in_bytes(n->in(1)->in(1)) < 16 &&
- static_cast(n->in(1))->get_predicate() == BoolTest::ne);
- match(Set cr (CmpI (VectorTest src1 src2) zero));
- effect(TEMP vtmp);
- format %{ "cmpvptest_anytrue_lt16 $src1,$src2\t! using $vtmp as TEMP" %}
- ins_encode %{
- int vlen = Matcher::vector_length_in_bytes(this, $src1);
- __ vectortest(BoolTest::ne, vlen, $src1$$XMMRegister, $src2$$XMMRegister, $vtmp$$XMMRegister);
- %}
- ins_pipe( pipe_slow );
-%}
-
-instruct cmpvptest_anytrue_ge16(rFlagsReg cr, legVec src1, legVec src2, immI_0 zero) %{
- predicate(!VM_Version::supports_avx512bwdq() &&
- Matcher::vector_length_in_bytes(n->in(1)->in(1)) >= 16 &&
- Matcher::vector_length_in_bytes(n->in(1)->in(1)) < 64 &&
- static_cast(n->in(1))->get_predicate() == BoolTest::ne);
- match(Set cr (CmpI (VectorTest src1 src2) zero));
- format %{ "cmpvptest_anytrue_ge16 $src1,$src2\t!" %}
+ match(Set cr (VectorTest src1 src2));
+ effect(TEMP tmp);
+ format %{ "ktest_anytrue_le8 $src1, $src2\t! using $tmp as TEMP" %}
ins_encode %{
- int vlen = Matcher::vector_length_in_bytes(this, $src1);
- __ vectortest(BoolTest::ne, vlen, $src1$$XMMRegister, $src2$$XMMRegister, xnoreg, xnoreg, knoreg);
+ uint masklen = Matcher::vector_length(this, $src1);
+ __ kmovwl($tmp$$Register, $src1$$KRegister);
+ __ andl($tmp$$Register, (1 << masklen) - 1);
%}
ins_pipe( pipe_slow );
%}
-instruct cmpvptest_anytrue_evex(rFlagsReg cr, kReg src1, kReg src2, immI_0 zero) %{
- predicate(VM_Version::supports_avx512bwdq() &&
- static_cast(n->in(1))->get_predicate() == BoolTest::ne);
- match(Set cr (CmpI (VectorTest src1 src2) zero));
- format %{ "cmpvptest_anytrue_evex $src1,$src2\t!" %}
+instruct ktest_ge8(rFlagsRegU cr, kReg src1, kReg src2) %{
+ predicate(Matcher::vector_length(n->in(1)) >= 16 ||
+ (Matcher::vector_length(n->in(1)) == 8 && VM_Version::supports_avx512dq()));
+ match(Set cr (VectorTest src1 src2));
+ format %{ "ktest_ge8 $src1, $src2\n\t" %}
ins_encode %{
uint masklen = Matcher::vector_length(this, $src1);
- const MachNode* mask1 = static_cast(this->in(this->operand_index($src1)));
- const MachNode* mask2 = static_cast(this->in(this->operand_index($src2)));
- assert(0 == Type::cmp(mask1->bottom_type(), mask2->bottom_type()), "");
- masklen = masklen < 8 ? 8 : masklen;
- __ ktest(masklen, $src1$$KRegister, $src2$$KRegister);
+ __ kortest(masklen, $src1$$KRegister, $src1$$KRegister);
%}
ins_pipe( pipe_slow );
%}
@@ -8875,12 +8829,6 @@ instruct vpopcount_integral_reg_evex(vec dst, vec src) %{
int vlen_enc = vector_length_encoding(this, $src);
BasicType bt = Matcher::vector_element_basic_type(this, $src);
__ vector_popcount_integral_evex(bt, $dst$$XMMRegister, $src$$XMMRegister, k0, true, vlen_enc);
- // TODO: Once auto-vectorizer supports ConvL2I operation, PopCountVL
- // should be succeeded by its corresponding vector IR and following
- // special handling should be removed.
- if (opcode == Op_PopCountVL && Matcher::vector_element_basic_type(this) == T_INT) {
- __ evpmovqd($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc);
- }
%}
ins_pipe( pipe_slow );
%}
@@ -8911,18 +8859,6 @@ instruct vpopcount_avx_reg(vec dst, vec src, vec xtmp1, vec xtmp2, rRegP rtmp) %
BasicType bt = Matcher::vector_element_basic_type(this, $src);
__ vector_popcount_integral(bt, $dst$$XMMRegister, $src$$XMMRegister, $xtmp1$$XMMRegister,
$xtmp2$$XMMRegister, $rtmp$$Register, vlen_enc);
- // TODO: Once auto-vectorizer supports ConvL2I operation, PopCountVL
- // should be succeeded by its corresponding vector IR and following
- // special handling should be removed.
- if (opcode == Op_PopCountVL && Matcher::vector_element_basic_type(this) == T_INT) {
- if (VM_Version::supports_avx512vl()) {
- __ evpmovqd($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc);
- } else {
- assert(VM_Version::supports_avx2(), "");
- __ vpshufd($dst$$XMMRegister, $dst$$XMMRegister, 8, vlen_enc);
- __ vpermq($dst$$XMMRegister, $dst$$XMMRegister, 8, vlen_enc);
- }
- }
%}
ins_pipe( pipe_slow );
%}
@@ -8939,15 +8875,8 @@ instruct vcount_trailing_zeros_reg_evex(vec dst, vec src, vec xtmp, rRegP rtmp)
ins_encode %{
int vlen_enc = vector_length_encoding(this, $src);
BasicType bt = Matcher::vector_element_basic_type(this, $src);
- BasicType rbt = Matcher::vector_element_basic_type(this);
__ vector_count_trailing_zeros_evex(bt, $dst$$XMMRegister, $src$$XMMRegister, xnoreg,
xnoreg, xnoreg, $xtmp$$XMMRegister, k0, $rtmp$$Register, vlen_enc);
- // TODO: Once auto-vectorizer supports ConvL2I operation, CountTrailingZerosV
- // should be succeeded by its corresponding vector IR and following
- // special handling should be removed.
- if (bt == T_LONG && rbt == T_INT) {
- __ evpmovqd($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc);
- }
%}
ins_pipe( pipe_slow );
%}
@@ -8993,17 +8922,8 @@ instruct vcount_trailing_zeros_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, v
ins_encode %{
int vlen_enc = vector_length_encoding(this, $src);
BasicType bt = Matcher::vector_element_basic_type(this, $src);
- BasicType rbt = Matcher::vector_element_basic_type(this);
__ vector_count_trailing_zeros_avx(bt, $dst$$XMMRegister, $src$$XMMRegister, $xtmp1$$XMMRegister,
$xtmp2$$XMMRegister, $xtmp3$$XMMRegister, $rtmp$$Register, vlen_enc);
- // TODO: Once auto-vectorizer supports ConvL2I operation, PopCountVL
- // should be succeeded by its corresponding vector IR and following
- // special handling should be removed.
- if (bt == T_LONG && rbt == T_INT) {
- assert(VM_Version::supports_avx2(), "");
- __ vpshufd($dst$$XMMRegister, $dst$$XMMRegister, 8, vlen_enc);
- __ vpermq($dst$$XMMRegister, $dst$$XMMRegister, 8, vlen_enc);
- }
%}
ins_pipe( pipe_slow );
%}
@@ -9408,15 +9328,8 @@ instruct vcount_leading_zeros_IL_reg_evex(vec dst, vec src) %{
ins_encode %{
int vlen_enc = vector_length_encoding(this, $src);
BasicType bt = Matcher::vector_element_basic_type(this, $src);
- BasicType rbt = Matcher::vector_element_basic_type(this);
__ vector_count_leading_zeros_evex(bt, $dst$$XMMRegister, $src$$XMMRegister, xnoreg,
xnoreg, xnoreg, k0, noreg, true, vlen_enc);
- // TODO: Once auto-vectorizer supports ConvL2I operation, CountLeadingZerosV
- // should be succeeded by its corresponding vector IR and following
- // special handling should be removed.
- if (rbt == T_INT && bt == T_LONG) {
- __ evpmovqd($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc);
- }
%}
ins_pipe( pipe_slow );
%}
@@ -9491,15 +9404,8 @@ instruct vcount_leading_zeros_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, ve
ins_encode %{
int vlen_enc = vector_length_encoding(this, $src);
BasicType bt = Matcher::vector_element_basic_type(this, $src);
- BasicType rbt = Matcher::vector_element_basic_type(this);
__ vector_count_leading_zeros_avx(bt, $dst$$XMMRegister, $src$$XMMRegister, $xtmp1$$XMMRegister,
$xtmp2$$XMMRegister, $xtmp3$$XMMRegister, $rtmp$$Register, vlen_enc);
- // TODO: Once auto-vectorizer supports ConvL2I operation, CountLeadingZerosV
- // should be succeeded by its corresponding vector IR and following
- // special handling should be removed.
- if (rbt == T_INT && bt == T_LONG) {
- __ evpmovqd($dst$$XMMRegister, $dst$$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 017ce230ba4..979494e4cb1 100644
--- a/src/hotspot/cpu/x86/x86_32.ad
+++ b/src/hotspot/cpu/x86/x86_32.ad
@@ -708,7 +708,9 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
Label dummy_label;
Label* code_stub = &dummy_label;
if (!C->output()->in_scratch_emit_size()) {
- code_stub = &C->output()->safepoint_poll_table()->add_safepoint(__ offset());
+ C2SafepointPollStub* stub = new (C->comp_arena()) C2SafepointPollStub(__ offset());
+ C->output()->add_stub(stub);
+ code_stub = &stub->entry();
}
__ relocate(relocInfo::poll_return_type);
__ safepoint_poll(*code_stub, thread, true /* at_return */, true /* in_nmethod */);
diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad
index 995ed35de0c..16cd035ac79 100644
--- a/src/hotspot/cpu/x86/x86_64.ad
+++ b/src/hotspot/cpu/x86/x86_64.ad
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This code is free software; you can redistribute it and/or modify it
@@ -889,7 +889,7 @@ void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
}
if (C->stub_function() != NULL && BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) {
st->print("\n\t");
- st->print("cmpl [r15_thread + #disarmed_offset], #disarmed_value\t");
+ st->print("cmpl [r15_thread + #disarmed_guard_value_offset], #disarmed_guard_value\t");
st->print("\n\t");
st->print("je fast_entry\t");
st->print("\n\t");
@@ -1020,7 +1020,9 @@ void MachEpilogNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const
Label dummy_label;
Label* code_stub = &dummy_label;
if (!C->output()->in_scratch_emit_size()) {
- code_stub = &C->output()->safepoint_poll_table()->add_safepoint(__ offset());
+ C2SafepointPollStub* stub = new (C->comp_arena()) C2SafepointPollStub(__ offset());
+ C->output()->add_stub(stub);
+ code_stub = &stub->entry();
}
__ relocate(relocInfo::poll_return_type);
__ safepoint_poll(*code_stub, r15_thread, true /* at_return */, true /* in_nmethod */);
@@ -2164,13 +2166,19 @@ encode %{
// determine who we intended to call.
MacroAssembler _masm(&cbuf);
cbuf.set_insts_mark();
- $$$emit8$primary;
if (!_method) {
+ $$$emit8$primary;
emit_d32_reloc(cbuf, (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4),
runtime_call_Relocation::spec(),
RELOC_DISP32);
+ } else if (_method->intrinsic_id() == vmIntrinsicID::_ensureMaterializedForStackWalk) {
+ // The NOP here is purely to ensure that eliding a call to
+ // JVM_EnsureMaterializedForStackWalk doesn't change the code size.
+ __ addr_nop_5();
+ __ block_comment("call JVM_EnsureMaterializedForStackWalk (elided)");
} else {
+ $$$emit8$primary;
int method_index = resolved_method_index(cbuf);
RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index)
: static_call_Relocation::spec(method_index);
@@ -6072,6 +6080,7 @@ instruct storeL(memory mem, rRegL src)
// Store Pointer
instruct storeP(memory mem, any_RegP src)
%{
+ predicate(n->as_Store()->barrier_data() == 0);
match(Set mem (StoreP mem src));
ins_cost(125); // XXX
@@ -6084,7 +6093,7 @@ instruct storeP(memory mem, any_RegP src)
instruct storeImmP0(memory mem, immP0 zero)
%{
- predicate(UseCompressedOops && (CompressedOops::base() == NULL));
+ predicate(UseCompressedOops && (CompressedOops::base() == NULL) && n->as_Store()->barrier_data() == 0);
match(Set mem (StoreP mem zero));
ins_cost(125); // XXX
@@ -6098,6 +6107,7 @@ instruct storeImmP0(memory mem, immP0 zero)
// Store NULL Pointer, mark word, or other simple pointer constant.
instruct storeImmP(memory mem, immP31 src)
%{
+ predicate(n->as_Store()->barrier_data() == 0);
match(Set mem (StoreP mem src));
ins_cost(150); // XXX
diff --git a/src/hotspot/cpu/zero/continuationFreezeThaw_zero.inline.hpp b/src/hotspot/cpu/zero/continuationFreezeThaw_zero.inline.hpp
index 69d77500fa7..7de24a461c9 100644
--- a/src/hotspot/cpu/zero/continuationFreezeThaw_zero.inline.hpp
+++ b/src/hotspot/cpu/zero/continuationFreezeThaw_zero.inline.hpp
@@ -87,10 +87,6 @@ inline void ThawBase::patch_pd(frame& f, const frame& caller) {
Unimplemented();
}
-void ThawBase::patch_chunk_pd(intptr_t* sp) {
- Unimplemented();
-}
-
template
inline void Thaw::patch_caller_links(intptr_t* sp, intptr_t* bottom) {
Unimplemented();
diff --git a/src/hotspot/cpu/zero/downcallLinker_zero.cpp b/src/hotspot/cpu/zero/downcallLinker_zero.cpp
index 3fc43c5031e..3f1241970f2 100644
--- a/src/hotspot/cpu/zero/downcallLinker_zero.cpp
+++ b/src/hotspot/cpu/zero/downcallLinker_zero.cpp
@@ -28,9 +28,10 @@ RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature,
int num_args,
BasicType ret_bt,
const ABIDescriptor& abi,
- const GrowableArray& input_registers,
- const GrowableArray& output_registers,
- bool needs_return_buffer) {
+ const GrowableArray& input_registers,
+ const GrowableArray& output_registers,
+ bool needs_return_buffer,
+ int captured_state_mask) {
Unimplemented();
return nullptr;
}
diff --git a/src/hotspot/cpu/zero/foreignGlobals_zero.cpp b/src/hotspot/cpu/zero/foreignGlobals_zero.cpp
index 21f6e9fd464..7c35da7e3e0 100644
--- a/src/hotspot/cpu/zero/foreignGlobals_zero.cpp
+++ b/src/hotspot/cpu/zero/foreignGlobals_zero.cpp
@@ -33,24 +33,19 @@ const ABIDescriptor ForeignGlobals::parse_abi_descriptor(jobject jabi) {
return {};
}
-VMReg ForeignGlobals::vmstorage_to_vmreg(int type, int index) {
- Unimplemented();
- return VMRegImpl::Bad();
-}
-
-int RegSpiller::pd_reg_size(VMReg reg) {
+int RegSpiller::pd_reg_size(VMStorage reg) {
Unimplemented();
return -1;
}
-void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMReg reg) {
+void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMStorage reg) {
Unimplemented();
}
-void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMReg reg) {
+void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMStorage reg) {
Unimplemented();
}
-void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMReg tmp, int in_stk_bias, int out_stk_bias) const {
+void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMStorage tmp, int in_stk_bias, int out_stk_bias, const StubLocations& locs) const {
Unimplemented();
}
diff --git a/src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp b/src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp
index 1ac11ec3a4b..90f971a3152 100644
--- a/src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp
+++ b/src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp
@@ -30,15 +30,11 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
ShouldNotReachHere();
}
-void BarrierSetNMethod::arm(nmethod* nm, int value) {
+void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) {
ShouldNotReachHere();
}
-void BarrierSetNMethod::disarm(nmethod* nm) {
+int BarrierSetNMethod::guard_value(nmethod* nm) {
ShouldNotReachHere();
-}
-
-bool BarrierSetNMethod::is_armed(nmethod* nm) {
- ShouldNotReachHere();
- return false;
+ return -1;
}
diff --git a/src/hotspot/cpu/zero/stackChunkFrameStream_zero.inline.hpp b/src/hotspot/cpu/zero/stackChunkFrameStream_zero.inline.hpp
index 64eb4e00ced..d9f16caca1e 100644
--- a/src/hotspot/cpu/zero/stackChunkFrameStream_zero.inline.hpp
+++ b/src/hotspot/cpu/zero/stackChunkFrameStream_zero.inline.hpp
@@ -67,12 +67,6 @@ inline intptr_t* StackChunkFrameStream::unextended_sp_for_interprete
return NULL;
}
-template
-intptr_t* StackChunkFrameStream::next_sp_for_interpreter_frame() const {
- Unimplemented();
- return NULL;
-}
-
template
inline void StackChunkFrameStream::next_for_interpreter_frame() {
Unimplemented();
diff --git a/src/hotspot/cpu/zero/stubGenerator_zero.cpp b/src/hotspot/cpu/zero/stubGenerator_zero.cpp
index 80e55d9c8e4..4fe19588133 100644
--- a/src/hotspot/cpu/zero/stubGenerator_zero.cpp
+++ b/src/hotspot/cpu/zero/stubGenerator_zero.cpp
@@ -191,12 +191,9 @@ class StubGenerator: public StubCodeGenerator {
// atomic calls
StubRoutines::_atomic_xchg_entry = ShouldNotCallThisStub();
- StubRoutines::_atomic_xchg_long_entry = ShouldNotCallThisStub();
StubRoutines::_atomic_cmpxchg_entry = ShouldNotCallThisStub();
- StubRoutines::_atomic_cmpxchg_byte_entry = ShouldNotCallThisStub();
StubRoutines::_atomic_cmpxchg_long_entry = ShouldNotCallThisStub();
StubRoutines::_atomic_add_entry = ShouldNotCallThisStub();
- StubRoutines::_atomic_add_long_entry = ShouldNotCallThisStub();
StubRoutines::_fence_entry = ShouldNotCallThisStub();
}
diff --git a/src/hotspot/cpu/zero/vmstorage_zero.hpp b/src/hotspot/cpu/zero/vmstorage_zero.hpp
new file mode 100644
index 00000000000..7536a6227e9
--- /dev/null
+++ b/src/hotspot/cpu/zero/vmstorage_zero.hpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef CPU_ZERO_VMSTORAGE_ZERO_INLINE_HPP
+#define CPU_ZERO_VMSTORAGE_ZERO_INLINE_HPP
+
+#include
+
+#include "asm/register.hpp"
+
+enum class StorageType : int8_t {
+ STACK = 0,
+ PLACEHOLDER = 1,
+// special locations used only by native code
+ FRAME_DATA = PLACEHOLDER + 1,
+ INVALID = -1
+};
+
+// need to define this before constructing VMStorage (below)
+constexpr inline bool VMStorage::is_reg(StorageType type) {
+ return false;
+}
+constexpr inline StorageType VMStorage::stack_type() { return StorageType::STACK; }
+constexpr inline StorageType VMStorage::placeholder_type() { return StorageType::PLACEHOLDER; }
+constexpr inline StorageType VMStorage::frame_data_type() { return StorageType::FRAME_DATA; }
+
+inline VMStorage as_VMStorage(VMReg reg) {
+ ShouldNotReachHere();
+ return VMStorage::invalid();
+}
+
+
+#endif // CPU_ZERO_VMSTORAGE_ZERO_INLINE_HPP
\ No newline at end of file
diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp
index ff7eefa7f7d..f11ddabeacf 100644
--- a/src/hotspot/os/aix/os_aix.cpp
+++ b/src/hotspot/os/aix/os_aix.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2021 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -1872,7 +1872,7 @@ int os::numa_get_group_id_for_address(const void* address) {
return 0;
}
-bool os::get_page_info(char *start, page_info* info) {
+bool os::numa_get_group_ids_for_range(const void** addresses, int* lgrp_ids, size_t count) {
return false;
}
diff --git a/src/hotspot/os/bsd/attachListener_bsd.cpp b/src/hotspot/os/bsd/attachListener_bsd.cpp
index 7999210bc3e..779b439d16b 100644
--- a/src/hotspot/os/bsd/attachListener_bsd.cpp
+++ b/src/hotspot/os/bsd/attachListener_bsd.cpp
@@ -248,7 +248,7 @@ int BsdAttachListener::init() {
//
BsdAttachOperation* BsdAttachListener::read_request(int s) {
char ver_str[8];
- sprintf(ver_str, "%d", ATTACH_PROTOCOL_VER);
+ size_t ver_str_len = os::snprintf_checked(ver_str, sizeof(ver_str), "%d", ATTACH_PROTOCOL_VER);
// The request is a sequence of strings so we first figure out the
// expected count and the maximum possible length of the request.
@@ -288,11 +288,11 @@ BsdAttachOperation* BsdAttachListener::read_request(int s) {
// The first string is so check it now to
// check for protocol mismatch
if (str_count == 1) {
- if ((strlen(buf) != strlen(ver_str)) ||
+ if ((strlen(buf) != ver_str_len) ||
(atoi(buf) != ATTACH_PROTOCOL_VER)) {
char msg[32];
- sprintf(msg, "%d\n", ATTACH_ERROR_BADVERSION);
- write_fully(s, msg, strlen(msg));
+ int msg_len = os::snprintf_checked(msg, sizeof(msg), "%d\n", ATTACH_ERROR_BADVERSION);
+ write_fully(s, msg, msg_len);
return NULL;
}
}
@@ -411,8 +411,8 @@ void BsdAttachOperation::complete(jint result, bufferedStream* st) {
// write operation result
char msg[32];
- sprintf(msg, "%d\n", result);
- int rc = BsdAttachListener::write_fully(this->socket(), msg, strlen(msg));
+ int msg_len = os::snprintf_checked(msg, sizeof(msg), "%d\n", result);
+ int rc = BsdAttachListener::write_fully(this->socket(), msg, msg_len);
// write any result data
if (rc == 0) {
diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp
index a0cf536134e..439d1eee73c 100644
--- a/src/hotspot/os/bsd/os_bsd.cpp
+++ b/src/hotspot/os/bsd/os_bsd.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -320,7 +320,7 @@ void os::init_system_properties_values() {
#ifndef __APPLE__
- // Buffer that fits several sprintfs.
+ // Buffer that fits several snprintfs.
// Note that the space for the colon and the trailing null are provided
// by the nulls included by the sizeof operator.
const size_t bufsize =
@@ -376,17 +376,16 @@ void os::init_system_properties_values() {
const char *v_colon = ":";
if (v == NULL) { v = ""; v_colon = ""; }
// That's +1 for the colon and +1 for the trailing '\0'.
- char *ld_library_path = NEW_C_HEAP_ARRAY(char,
- strlen(v) + 1 +
- sizeof(SYS_EXT_DIR) + sizeof("/lib/") + strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH) + 1,
- mtInternal);
- sprintf(ld_library_path, "%s%s" SYS_EXT_DIR "/lib/%s:" DEFAULT_LIBPATH, v, v_colon, cpu_arch);
+ const size_t ld_library_path_size = strlen(v) + 1 + sizeof(SYS_EXT_DIR) +
+ sizeof("/lib/") + strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH) + 1;
+ char *ld_library_path = NEW_C_HEAP_ARRAY(char, ld_library_path_size, mtInternal);
+ os::snprintf_checked(ld_library_path, ld_library_path_size, "%s%s" SYS_EXT_DIR "/lib/%s:" DEFAULT_LIBPATH, v, v_colon, cpu_arch);
Arguments::set_library_path(ld_library_path);
FREE_C_HEAP_ARRAY(char, ld_library_path);
}
// Extensions directories.
- sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home());
+ os::snprintf_checked(buf, bufsize, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home());
Arguments::set_ext_dirs(buf);
FREE_C_HEAP_ARRAY(char, buf);
@@ -401,7 +400,7 @@ void os::init_system_properties_values() {
size_t system_ext_size = strlen(user_home_dir) + sizeof(SYS_EXTENSIONS_DIR) +
sizeof(SYS_EXTENSIONS_DIRS);
- // Buffer that fits several sprintfs.
+ // Buffer that fits several snprintfs.
// Note that the space for the colon and the trailing null are provided
// by the nulls included by the sizeof operator.
const size_t bufsize =
@@ -471,11 +470,9 @@ void os::init_system_properties_values() {
// could cause a change in behavior, but Apple's Java6 behavior
// can be achieved by putting "." at the beginning of the
// JAVA_LIBRARY_PATH environment variable.
- char *ld_library_path = NEW_C_HEAP_ARRAY(char,
- strlen(v) + 1 + strlen(l) + 1 +
- system_ext_size + 3,
- mtInternal);
- sprintf(ld_library_path, "%s%s%s%s%s" SYS_EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS ":.",
+ const size_t ld_library_path_size = strlen(v) + 1 + strlen(l) + 1 + system_ext_size + 3;
+ char *ld_library_path = NEW_C_HEAP_ARRAY(char, ld_library_path_size, mtInternal);
+ os::snprintf_checked(ld_library_path, ld_library_path_size, "%s%s%s%s%s" SYS_EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS ":.",
v, v_colon, l, l_colon, user_home_dir);
Arguments::set_library_path(ld_library_path);
FREE_C_HEAP_ARRAY(char, ld_library_path);
@@ -486,7 +483,7 @@ void os::init_system_properties_values() {
// Note that the space for the colon and the trailing null are provided
// by the nulls included by the sizeof operator (so actually one byte more
// than necessary is allocated).
- sprintf(buf, "%s" SYS_EXTENSIONS_DIR ":%s" EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS,
+ os::snprintf_checked(buf, bufsize, "%s" SYS_EXTENSIONS_DIR ":%s" EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS,
user_home_dir, Arguments::get_java_home());
Arguments::set_ext_dirs(buf);
@@ -1578,7 +1575,7 @@ int os::numa_get_group_id_for_address(const void* address) {
return 0;
}
-bool os::get_page_info(char *start, page_info* info) {
+bool os::numa_get_group_ids_for_range(const void** addresses, int* lgrp_ids, size_t count) {
return false;
}
diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
index 91456b3d0e1..991f25b7172 100644
--- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
+++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
@@ -78,71 +78,83 @@ class CgroupController: public CHeapObj {
PRAGMA_DIAG_PUSH
PRAGMA_FORMAT_NONLITERAL_IGNORED
+// Parses a subsystem's file, looking for a matching line.
+// If key is null, then the first line will be matched with scan_fmt.
+// If key isn't null, then each line will be matched, looking for something that matches "$key $scan_fmt".
+// The matching value will be assigned to returnval.
+// scan_fmt uses scanf() syntax.
+// Return value: 0 on match, OSCONTAINER_ERROR on error.
template int subsystem_file_line_contents(CgroupController* c,
const char *filename,
- const char *matchline,
+ const char *key,
const char *scan_fmt,
T returnval) {
- FILE *fp = NULL;
- char *p;
- char file[MAXPATHLEN+1];
- char buf[MAXPATHLEN+1];
- char discard[MAXPATHLEN+1];
- bool found_match = false;
+ if (c == nullptr) {
+ log_debug(os, container)("subsystem_file_line_contents: CgroupController* is nullptr");
+ return OSCONTAINER_ERROR;
+ }
+ if (c->subsystem_path() == nullptr) {
+ log_debug(os, container)("subsystem_file_line_contents: subsystem path is nullptr");
+ return OSCONTAINER_ERROR;
+ }
+
+ stringStream file_path;
+ file_path.print_raw(c->subsystem_path());
+ file_path.print_raw(filename);
- if (c == NULL) {
- log_debug(os, container)("subsystem_file_line_contents: CgroupController* is NULL");
+ if (file_path.size() > (MAXPATHLEN-1)) {
+ log_debug(os, container)("File path too long %s, %s", file_path.base(), filename);
return OSCONTAINER_ERROR;
}
- if (c->subsystem_path() == NULL) {
- log_debug(os, container)("subsystem_file_line_contents: subsystem path is NULL");
+ const char* absolute_path = file_path.freeze();
+ log_trace(os, container)("Path to %s is %s", filename, absolute_path);
+
+ FILE* fp = os::fopen(absolute_path, "r");
+ if (fp == nullptr) {
+ log_debug(os, container)("Open of file %s failed, %s", absolute_path, os::strerror(errno));
return OSCONTAINER_ERROR;
}
- strncpy(file, c->subsystem_path(), MAXPATHLEN);
- file[MAXPATHLEN-1] = '\0';
- int filelen = strlen(file);
- if ((filelen + strlen(filename)) > (MAXPATHLEN-1)) {
- log_debug(os, container)("File path too long %s, %s", file, filename);
+ const int buf_len = MAXPATHLEN+1;
+ char buf[buf_len];
+ char* line = fgets(buf, buf_len, fp);
+ if (line == nullptr) {
+ log_debug(os, container)("Empty file %s", absolute_path);
+ fclose(fp);
return OSCONTAINER_ERROR;
}
- strncat(file, filename, MAXPATHLEN-filelen);
- log_trace(os, container)("Path to %s is %s", filename, file);
- fp = os::fopen(file, "r");
- if (fp != NULL) {
- int err = 0;
- while ((p = fgets(buf, MAXPATHLEN, fp)) != NULL) {
- found_match = false;
- if (matchline == NULL) {
- // single-line file case
- int matched = sscanf(p, scan_fmt, returnval);
- found_match = (matched == 1);
- } else {
- // multi-line file case
- if (strstr(p, matchline) != NULL) {
- // discard matchline string prefix
- int matched = sscanf(p, scan_fmt, discard, returnval);
- found_match = (matched == 2);
- } else {
- continue; // substring not found
+
+ bool found_match = false;
+ if (key == nullptr) {
+ // File consists of a single line according to caller, with only a value
+ int matched = sscanf(line, scan_fmt, returnval);
+ found_match = matched == 1;
+ } else {
+ // File consists of multiple lines in a "key value"
+ // fashion, we have to find the key.
+ const int key_len = strlen(key);
+ for (; line != nullptr; line = fgets(buf, buf_len, fp)) {
+ char* key_substr = strstr(line, key);
+ char after_key = line[key_len];
+ if (key_substr == line
+ && isspace(after_key) != 0
+ && after_key != '\n') {
+ // Skip key, skip space
+ const char* value_substr = line + key_len + 1;
+ int matched = sscanf(value_substr, scan_fmt, returnval);
+ found_match = matched == 1;
+ if (found_match) {
+ break;
}
}
- if (found_match) {
- fclose(fp);
- return 0;
- } else {
- err = 1;
- log_debug(os, container)("Type %s not found in file %s", scan_fmt, file);
- }
}
- if (err == 0) {
- log_debug(os, container)("Empty file %s", file);
- }
- } else {
- log_debug(os, container)("Open of file %s failed, %s", file, os::strerror(errno));
}
- if (fp != NULL)
- fclose(fp);
+ fclose(fp);
+ if (found_match) {
+ return 0;
+ }
+ log_debug(os, container)("Type %s (key == %s) not found in file %s", scan_fmt,
+ (key == nullptr ? "null" : key), absolute_path);
return OSCONTAINER_ERROR;
}
PRAGMA_DIAG_POP
diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
index e62dcf4f759..cfa8f516e3e 100644
--- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
+++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
@@ -96,10 +96,8 @@ jlong CgroupV1Subsystem::read_memory_limit_in_bytes() {
log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited");
CgroupV1MemoryController* mem_controller = reinterpret_cast(_memory->controller());
if (mem_controller->is_hierarchical()) {
- const char* matchline = "hierarchical_memory_limit";
- const char* format = "%s " JULONG_FORMAT;
- GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", matchline,
- "Hierarchical Memory Limit is: " JULONG_FORMAT, format, hier_memlimit)
+ GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", "hierarchical_memory_limit",
+ "Hierarchical Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, hier_memlimit)
if (hier_memlimit >= os::Linux::physical_memory()) {
log_trace(os, container)("Hierarchical Memory Limit is: Unlimited");
} else {
@@ -123,9 +121,8 @@ jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() {
CgroupV1MemoryController* mem_controller = reinterpret_cast(_memory->controller());
if (mem_controller->is_hierarchical()) {
const char* matchline = "hierarchical_memsw_limit";
- const char* format = "%s " JULONG_FORMAT;
GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", matchline,
- "Hierarchical Memory and Swap Limit is : " JULONG_FORMAT, format, hier_memswlimit)
+ "Hierarchical Memory and Swap Limit is : " JULONG_FORMAT, JULONG_FORMAT, hier_memswlimit)
if (hier_memswlimit >= host_total_memsw) {
log_trace(os, container)("Hierarchical Memory and Swap Limit is: Unlimited");
} else {
@@ -133,7 +130,7 @@ jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() {
if (swappiness == 0) {
const char* matchmemline = "hierarchical_memory_limit";
GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", matchmemline,
- "Hierarchical Memory Limit is : " JULONG_FORMAT, format, hier_memlimit)
+ "Hierarchical Memory Limit is : " JULONG_FORMAT, JULONG_FORMAT, hier_memlimit)
log_trace(os, container)("Memory and Swap Limit has been reset to " JULONG_FORMAT " because swappiness is 0", hier_memlimit);
return (jlong)hier_memlimit;
}
@@ -286,10 +283,7 @@ int CgroupV1Subsystem::cpu_shares() {
char* CgroupV1Subsystem::pids_max_val() {
GET_CONTAINER_INFO_CPTR(cptr, _pids, "/pids.max",
- "Maximum number of tasks is: %s", "%s %*d", pidsmax, 1024);
- if (pidsmax == NULL) {
- return NULL;
- }
+ "Maximum number of tasks is: %s", "%1023s", pidsmax, 1024);
return os::strdup(pidsmax);
}
diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
index 25ab8f55f38..190b12438f6 100644
--- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
+++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
@@ -92,27 +92,18 @@ int CgroupV2Subsystem::cpu_quota() {
char * CgroupV2Subsystem::cpu_cpuset_cpus() {
GET_CONTAINER_INFO_CPTR(cptr, _unified, "/cpuset.cpus",
"cpuset.cpus is: %s", "%1023s", cpus, 1024);
- if (cpus == NULL) {
- return NULL;
- }
return os::strdup(cpus);
}
char* CgroupV2Subsystem::cpu_quota_val() {
GET_CONTAINER_INFO_CPTR(cptr, _unified, "/cpu.max",
- "Raw value for CPU quota is: %s", "%s %*d", quota, 1024);
- if (quota == NULL) {
- return NULL;
- }
+ "Raw value for CPU quota is: %s", "%1023s %*d", quota, 1024);
return os::strdup(quota);
}
char * CgroupV2Subsystem::cpu_cpuset_memory_nodes() {
GET_CONTAINER_INFO_CPTR(cptr, _unified, "/cpuset.mems",
"cpuset.mems is: %s", "%1023s", mems, 1024);
- if (mems == NULL) {
- return NULL;
- }
return os::strdup(mems);
}
@@ -150,10 +141,7 @@ jlong CgroupV2Subsystem::memory_max_usage_in_bytes() {
char* CgroupV2Subsystem::mem_soft_limit_val() {
GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.low",
- "Memory Soft Limit is: %s", "%s", mem_soft_limit_str, 1024);
- if (mem_soft_limit_str == NULL) {
- return NULL;
- }
+ "Memory Soft Limit is: %s", "%1023s", mem_soft_limit_str, 1024);
return os::strdup(mem_soft_limit_str);
}
@@ -175,20 +163,14 @@ jlong CgroupV2Subsystem::memory_and_swap_limit_in_bytes() {
char* CgroupV2Subsystem::mem_swp_limit_val() {
GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.swap.max",
- "Memory and Swap Limit is: %s", "%s", mem_swp_limit_str, 1024);
- if (mem_swp_limit_str == NULL) {
- return NULL;
- }
+ "Memory and Swap Limit is: %s", "%1023s", mem_swp_limit_str, 1024);
return os::strdup(mem_swp_limit_str);
}
// memory.swap.current : total amount of swap currently used by the cgroup and its descendants
char* CgroupV2Subsystem::mem_swp_current_val() {
GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.swap.current",
- "Swap currently used is: %s", "%s", mem_swp_current_str, 1024);
- if (mem_swp_current_str == NULL) {
- return NULL;
- }
+ "Swap currently used is: %s", "%1023s", mem_swp_current_str, 1024);
return os::strdup(mem_swp_current_str);
}
@@ -215,10 +197,7 @@ jlong CgroupV2Subsystem::read_memory_limit_in_bytes() {
char* CgroupV2Subsystem::mem_limit_val() {
GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.max",
- "Raw value for memory limit is: %s", "%s", mem_limit_str, 1024);
- if (mem_limit_str == NULL) {
- return NULL;
- }
+ "Raw value for memory limit is: %s", "%1023s", mem_limit_str, 1024);
return os::strdup(mem_limit_str);
}
@@ -244,10 +223,7 @@ char* CgroupV2Controller::construct_path(char* mount_path, char *cgroup_path) {
char* CgroupV2Subsystem::pids_max_val() {
GET_CONTAINER_INFO_CPTR(cptr, _unified, "/pids.max",
- "Maximum number of tasks is: %s", "%s %*d", pidsmax, 1024);
- if (pidsmax == NULL) {
- return NULL;
- }
+ "Maximum number of tasks is: %s", "%1023s", pidsmax, 1024);
return os::strdup(pidsmax);
}
diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp
index 7d9636d250a..0d261adf93c 100644
--- a/src/hotspot/os/linux/os_linux.cpp
+++ b/src/hotspot/os/linux/os_linux.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2022 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -2777,6 +2777,11 @@ int os::numa_get_group_id_for_address(const void* address) {
return id;
}
+bool os::numa_get_group_ids_for_range(const void** addresses, int* lgrp_ids, size_t count) {
+ void** pages = const_cast(addresses);
+ return os::Linux::numa_move_pages(0, count, pages, NULL, lgrp_ids, 0) == 0;
+}
+
int os::Linux::get_existing_num_nodes() {
int node;
int highest_node_number = Linux::numa_max_node();
@@ -2807,10 +2812,6 @@ size_t os::numa_get_leaf_groups(int *ids, size_t size) {
return i;
}
-bool os::get_page_info(char *start, page_info* info) {
- return false;
-}
-
char *os::scan_pages(char *start, char* end, page_info* page_expected,
page_info* page_found) {
return end;
diff --git a/src/hotspot/os/posix/mutex_posix.hpp b/src/hotspot/os/posix/mutex_posix.hpp
index 869ac7de553..7acd741973f 100644
--- a/src/hotspot/os/posix/mutex_posix.hpp
+++ b/src/hotspot/os/posix/mutex_posix.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -133,7 +133,7 @@ class PlatformMonitor : public PlatformMutex {
NONCOPYABLE(PlatformMonitor);
public:
- int wait(jlong millis);
+ int wait(uint64_t millis);
void notify();
void notify_all();
};
diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp
index ef0f77157d4..7a85a2ccb86 100644
--- a/src/hotspot/os/posix/os_posix.cpp
+++ b/src/hotspot/os/posix/os_posix.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1869,17 +1869,17 @@ PlatformMonitor::~PlatformMonitor() {
#endif // PLATFORM_MONITOR_IMPL_INDIRECT
// Must already be locked
-int PlatformMonitor::wait(jlong millis) {
- assert(millis >= 0, "negative timeout");
+int PlatformMonitor::wait(uint64_t millis) {
if (millis > 0) {
struct timespec abst;
// We have to watch for overflow when converting millis to nanos,
// but if millis is that large then we will end up limiting to
- // MAX_SECS anyway, so just do that here.
+ // MAX_SECS anyway, so just do that here. This also handles values
+ // larger than int64_t max.
if (millis / MILLIUNITS > MAX_SECS) {
- millis = jlong(MAX_SECS) * MILLIUNITS;
+ millis = uint64_t(MAX_SECS) * MILLIUNITS;
}
- to_abstime(&abst, millis_to_nanos(millis), false, false);
+ to_abstime(&abst, millis_to_nanos(int64_t(millis)), false, false);
int ret = OS_TIMEOUT;
int status = pthread_cond_timedwait(cond(), mutex(), &abst);
diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp
index c4cdb4c74f5..598955cbdfb 100644
--- a/src/hotspot/os/posix/perfMemory_posix.cpp
+++ b/src/hotspot/os/posix/perfMemory_posix.cpp
@@ -1205,7 +1205,10 @@ static void mmap_attach_shared(int vmid, char** addr, size_t* sizep, TRAPS) {
FREE_C_HEAP_ARRAY(char, dirname);
FREE_C_HEAP_ARRAY(char, filename);
- if (fd == OS_ERR || HAS_PENDING_EXCEPTION) {
+ if (HAS_PENDING_EXCEPTION) {
+ assert(fd == OS_ERR, "open_sharedmem_file always return OS_ERR on exceptions");
+ }
+ if (fd == OS_ERR) {
return;
}
diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp
index 1c634130be0..464e0a483be 100644
--- a/src/hotspot/os/posix/signals_posix.cpp
+++ b/src/hotspot/os/posix/signals_posix.cpp
@@ -639,7 +639,7 @@ int JVM_HANDLE_XXX_SIGNAL(int sig, siginfo_t* info,
// Call platform dependent signal handler.
if (!signal_was_handled) {
- JavaThread* const jt = (t != NULL && t->is_Java_thread()) ? (JavaThread*) t : NULL;
+ JavaThread* const jt = (t != NULL && t->is_Java_thread()) ? JavaThread::cast(t) : NULL;
signal_was_handled = PosixSignals::pd_hotspot_signal_handler(sig, info, uc, jt);
}
diff --git a/src/hotspot/os/windows/mutex_windows.hpp b/src/hotspot/os/windows/mutex_windows.hpp
index 6785d3102ac..5235308bb06 100644
--- a/src/hotspot/os/windows/mutex_windows.hpp
+++ b/src/hotspot/os/windows/mutex_windows.hpp
@@ -56,7 +56,7 @@ class PlatformMonitor : public PlatformMutex {
public:
PlatformMonitor();
~PlatformMonitor();
- int wait(jlong millis);
+ int wait(uint64_t millis);
void notify();
void notify_all();
};
diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp
index 3262a9ddc8b..a027587f5f7 100644
--- a/src/hotspot/os/windows/os_windows.cpp
+++ b/src/hotspot/os/windows/os_windows.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -510,8 +510,10 @@ struct tm* os::gmtime_pd(const time_t* clock, struct tm* res) {
JNIEXPORT
LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo);
-// Thread start routine for all newly created threads
-static unsigned __stdcall thread_native_entry(Thread* thread) {
+// Thread start routine for all newly created threads.
+// Called with the associated Thread* as the argument.
+unsigned __stdcall os::win32::thread_native_entry(void* t) {
+ Thread* thread = static_cast(t);
thread->record_stack_base_and_size();
thread->initialize_thread_current();
@@ -744,7 +746,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type,
thread_handle =
(HANDLE)_beginthreadex(NULL,
(unsigned)stack_size,
- (unsigned (__stdcall *)(void*)) thread_native_entry,
+ &os::win32::thread_native_entry,
thread,
initflag,
&thread_id);
@@ -1886,6 +1888,10 @@ void os::get_summary_cpu_info(char* buf, size_t buflen) {
status = RegQueryValueEx(key, "ProcessorNameString", NULL, NULL, (byte*)buf, &size);
if (status != ERROR_SUCCESS) {
strncpy(buf, "## __CPU__", buflen);
+ } else {
+ if (size < buflen) {
+ buf[size] = '\0';
+ }
}
RegCloseKey(key);
} else {
@@ -3721,7 +3727,7 @@ int os::numa_get_group_id_for_address(const void* address) {
return 0;
}
-bool os::get_page_info(char *start, page_info* info) {
+bool os::numa_get_group_ids_for_range(const void** addresses, int* lgrp_ids, size_t count) {
return false;
}
@@ -5356,11 +5362,14 @@ void Parker::unpark() {
// Platform Monitor implementation
// Must already be locked
-int PlatformMonitor::wait(jlong millis) {
- assert(millis >= 0, "negative timeout");
+int PlatformMonitor::wait(uint64_t millis) {
int ret = OS_TIMEOUT;
+ // The timeout parameter for SleepConditionVariableCS is a DWORD
+ if (millis > UINT_MAX) {
+ millis = UINT_MAX;
+ }
int status = SleepConditionVariableCS(&_cond, &_mutex,
- millis == 0 ? INFINITE : millis);
+ millis == 0 ? INFINITE : (DWORD)millis);
if (status != 0) {
ret = OS_OK;
}
diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp
index 94d7c3c5e2d..197797078d7 100644
--- a/src/hotspot/os/windows/os_windows.hpp
+++ b/src/hotspot/os/windows/os_windows.hpp
@@ -36,7 +36,6 @@ typedef void (*signal_handler_t)(int);
class os::win32 {
friend class os;
- friend unsigned __stdcall thread_native_entry(Thread*);
protected:
static int _processor_type;
@@ -70,6 +69,10 @@ class os::win32 {
static HINSTANCE load_Windows_dll(const char* name, char *ebuf, int ebuflen);
private:
+ // The handler passed to _beginthreadex().
+ // Called with the associated Thread* as the argument.
+ static unsigned __stdcall thread_native_entry(void*);
+
enum Ept { EPT_THREAD, EPT_PROCESS, EPT_PROCESS_DIE };
// Wrapper around _endthreadex(), exit() and _exit()
static int exit_process_or_thread(Ept what, int exit_code);
diff --git a/src/hotspot/os_cpu/bsd_aarch64/javaThread_bsd_aarch64.cpp b/src/hotspot/os_cpu/bsd_aarch64/javaThread_bsd_aarch64.cpp
index 10352994df6..38a5547a553 100644
--- a/src/hotspot/os_cpu/bsd_aarch64/javaThread_bsd_aarch64.cpp
+++ b/src/hotspot/os_cpu/bsd_aarch64/javaThread_bsd_aarch64.cpp
@@ -50,13 +50,10 @@ bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext,
}
bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) {
- assert(this->is_Java_thread(), "must be JavaThread");
- JavaThread* jt = (JavaThread *)this;
-
// If we have a last_Java_frame, then we should use it even if
// isInJava == true. It should be more reliable than ucontext info.
- if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) {
- *fr_addr = jt->pd_last_frame();
+ if (has_last_Java_frame() && frame_anchor()->walkable()) {
+ *fr_addr = pd_last_frame();
return true;
}
@@ -75,11 +72,11 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava)
}
frame ret_frame(ret_sp, ret_fp, addr);
- if (!ret_frame.safe_for_sender(jt)) {
+ if (!ret_frame.safe_for_sender(this)) {
#if COMPILER2_OR_JVMCI
// C2 and JVMCI use ebp as a general register see if NULL fp helps
frame ret_frame2(ret_sp, NULL, addr);
- if (!ret_frame2.safe_for_sender(jt)) {
+ if (!ret_frame2.safe_for_sender(this)) {
// nothing else to try if the frame isn't good
return false;
}
@@ -98,4 +95,3 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava)
}
void JavaThread::cache_global_variables() { }
-
diff --git a/src/hotspot/os_cpu/windows_aarch64/javaThread_windows_aarch64.cpp b/src/hotspot/os_cpu/windows_aarch64/javaThread_windows_aarch64.cpp
index 6af1fee4f8b..8e97fa6b5c1 100644
--- a/src/hotspot/os_cpu/windows_aarch64/javaThread_windows_aarch64.cpp
+++ b/src/hotspot/os_cpu/windows_aarch64/javaThread_windows_aarch64.cpp
@@ -49,15 +49,10 @@ bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext,
}
bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) {
-
- assert(this->is_Java_thread(), "must be JavaThread");
-
- JavaThread* jt = (JavaThread *)this;
-
// If we have a last_Java_frame, then we should use it even if
// isInJava == true. It should be more reliable than CONTEXT info.
- if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) {
- *fr_addr = jt->pd_last_frame();
+ if (has_last_Java_frame() && frame_anchor()->walkable()) {
+ *fr_addr = pd_last_frame();
return true;
}
@@ -71,11 +66,11 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava)
return false;
}
- if (!ret_frame.safe_for_sender(jt)) {
+ if (!ret_frame.safe_for_sender(this)) {
#if COMPILER2_OR_JVMCI
// C2 and JVMCI use ebp as a general register see if NULL fp helps
frame ret_frame2(ret_frame.sp(), NULL, ret_frame.pc());
- if (!ret_frame2.safe_for_sender(jt)) {
+ if (!ret_frame2.safe_for_sender(this)) {
// nothing else to try if the frame isn't good
return false;
}
@@ -88,7 +83,6 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava)
*fr_addr = ret_frame;
return true;
}
-
// nothing else to try
return false;
}
diff --git a/src/hotspot/share/adlc/adlc.hpp b/src/hotspot/share/adlc/adlc.hpp
index 555029fdbb6..8812066bafa 100644
--- a/src/hotspot/share/adlc/adlc.hpp
+++ b/src/hotspot/share/adlc/adlc.hpp
@@ -100,4 +100,8 @@ typedef unsigned int uintptr_t;
// it everywhere it needs to be available.
extern ArchDesc* globalAD;
+// Performs snprintf and asserts the result is non-negative (so there was not
+// an encoding error) and that the output was not truncated.
+extern int snprintf_checked(char* buf, size_t len, const char* fmt, ...);
+
#endif // SHARE_ADLC_ADLC_HPP
diff --git a/src/hotspot/share/adlc/adlparse.cpp b/src/hotspot/share/adlc/adlparse.cpp
index adf5b731589..8190f82a050 100644
--- a/src/hotspot/share/adlc/adlparse.cpp
+++ b/src/hotspot/share/adlc/adlparse.cpp
@@ -211,8 +211,9 @@ void ADLParser::instr_parse(void) {
return;
}
assert(match_rules_cnt < 100," too many match rule clones");
- char* buf = (char*) AdlAllocateHeap(strlen(instr->_ident) + 4);
- sprintf(buf, "%s_%d", instr->_ident, match_rules_cnt++);
+ const size_t buf_size = strlen(instr->_ident) + 4;
+ char* buf = (char*) AdlAllocateHeap(buf_size);
+ snprintf_checked(buf, buf_size, "%s_%d", instr->_ident, match_rules_cnt++);
rule->_result = buf;
// Check for commutative operations with tree operands.
matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt);
@@ -2876,8 +2877,9 @@ void ADLParser::ins_encode_parse_block(InstructForm& inst) {
// Create a new encoding name based on the name of the instruction
// definition, which should be unique.
const char* prefix = "__ins_encode_";
- char* ec_name = (char*) AdlAllocateHeap(strlen(inst._ident) + strlen(prefix) + 1);
- sprintf(ec_name, "%s%s", prefix, inst._ident);
+ const size_t ec_name_size = strlen(inst._ident) + strlen(prefix) + 1;
+ char* ec_name = (char*) AdlAllocateHeap(ec_name_size);
+ snprintf_checked(ec_name, ec_name_size, "%s%s", prefix, inst._ident);
assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist");
EncClass* encoding = _AD._encode->add_EncClass(ec_name);
@@ -3347,8 +3349,9 @@ void ADLParser::constant_parse(InstructForm& inst) {
// Create a new encoding name based on the name of the instruction
// definition, which should be unique.
const char* prefix = "__constant_";
- char* ec_name = (char*) AdlAllocateHeap(strlen(inst._ident) + strlen(prefix) + 1);
- sprintf(ec_name, "%s%s", prefix, inst._ident);
+ const size_t ec_name_size = strlen(inst._ident) + strlen(prefix) + 1;
+ char* ec_name = (char*) AdlAllocateHeap(ec_name_size);
+ snprintf_checked(ec_name, ec_name_size, "%s%s", prefix, inst._ident);
assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist");
EncClass* encoding = _AD._encode->add_EncClass(ec_name);
@@ -4667,8 +4670,9 @@ char *ADLParser::get_ident_or_literal_constant(const char* description) {
// Grab a constant expression.
param = get_paren_expr(description);
if (param[0] != '(') {
- char* buf = (char*) AdlAllocateHeap(strlen(param) + 3);
- sprintf(buf, "(%s)", param);
+ const size_t buf_size = strlen(param) + 3;
+ char* buf = (char*) AdlAllocateHeap(buf_size);
+ snprintf_checked(buf, buf_size, "(%s)", param);
param = buf;
}
assert(is_literal_constant(param),
@@ -5275,8 +5279,9 @@ void ADLParser::next_line() {
char* ADLParser::get_line_string(int linenum) {
const char* file = _AD._ADL_file._name;
int line = linenum ? linenum : this->linenum();
- char* location = (char *)AdlAllocateHeap(strlen(file) + 100);
- sprintf(location, "\n#line %d \"%s\"\n", line, file);
+ const size_t location_size = strlen(file) + 100;
+ char* location = (char *)AdlAllocateHeap(location_size);
+ snprintf_checked(location, location_size, "\n#line %d \"%s\"\n", line, file);
return location;
}
diff --git a/src/hotspot/share/adlc/archDesc.cpp b/src/hotspot/share/adlc/archDesc.cpp
index a437dd29c75..890b266d58d 100644
--- a/src/hotspot/share/adlc/archDesc.cpp
+++ b/src/hotspot/share/adlc/archDesc.cpp
@@ -815,7 +815,7 @@ static const char *getRegMask(const char *reg_class_name) {
const char *mask = "_mask";
int length = (int)strlen(rc_name) + (int)strlen(mask) + 5;
char *regMask = new char[length];
- sprintf(regMask,"%s%s()", rc_name, mask);
+ snprintf_checked(regMask, length, "%s%s()", rc_name, mask);
delete[] rc_name;
return regMask;
}
@@ -908,7 +908,7 @@ char *ArchDesc::stack_or_reg_mask(OperandForm &opForm) {
const char *stack_or = "STACK_OR_";
int length = (int)strlen(stack_or) + (int)strlen(reg_mask_name) + 1;
char *result = new char[length];
- sprintf(result,"%s%s", stack_or, reg_mask_name);
+ snprintf_checked(result, length, "%s%s", stack_or, reg_mask_name);
return result;
}
diff --git a/src/hotspot/share/adlc/dfa.cpp b/src/hotspot/share/adlc/dfa.cpp
index 36cba614878..e3a92ec1e5b 100644
--- a/src/hotspot/share/adlc/dfa.cpp
+++ b/src/hotspot/share/adlc/dfa.cpp
@@ -212,13 +212,13 @@ Expr *ArchDesc::calc_cost(FILE *fp, const char *spaces, MatchList &mList, Produc
Expr *c = new Expr("0");
if (mList._lchild) { // If left child, add it in
const char* lchild_to_upper = ArchDesc::getMachOperEnum(mList._lchild);
- sprintf(Expr::buffer(), "_kids[0]->_cost[%s]", lchild_to_upper);
+ snprintf_checked(Expr::buffer(), STRING_BUFFER_LENGTH, "_kids[0]->_cost[%s]", lchild_to_upper);
c->add(Expr::buffer());
delete[] lchild_to_upper;
}
if (mList._rchild) { // If right child, add it in
const char* rchild_to_upper = ArchDesc::getMachOperEnum(mList._rchild);
- sprintf(Expr::buffer(), "_kids[1]->_cost[%s]", rchild_to_upper);
+ snprintf_checked(Expr::buffer(), STRING_BUFFER_LENGTH, "_kids[1]->_cost[%s]", rchild_to_upper);
c->add(Expr::buffer());
delete[] rchild_to_upper;
}
@@ -757,7 +757,7 @@ const char *Expr::compute_expr(const Expr *c1, const Expr *c2) {
snprintf(string_buffer, STRING_BUFFER_LENGTH, "%s", c2->_expr);
}
else {
- sprintf( string_buffer, "0");
+ snprintf_checked(string_buffer, STRING_BUFFER_LENGTH, "0");
}
string_buffer[STRING_BUFFER_LENGTH - 1] = '\0';
char *cost = strdup(string_buffer);
diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp
index d09c6a5ca92..d6d13478339 100644
--- a/src/hotspot/share/adlc/formssel.cpp
+++ b/src/hotspot/share/adlc/formssel.cpp
@@ -25,6 +25,8 @@
// FORMS.CPP - Definitions for ADL Parser Forms Classes
#include "adlc.hpp"
+#define remaining_buflen(buffer, position) (sizeof(buffer) - ((position) - (buffer)))
+
//==============================Instructions===================================
//------------------------------InstructForm-----------------------------------
InstructForm::InstructForm(const char *id, bool ideal_only)
@@ -1533,7 +1535,7 @@ Predicate *InstructForm::build_predicate() {
s += strlen(s);
}
// Add predicate to working buffer
- sprintf(s,"/*%s*/(",(char*)i._key);
+ snprintf_checked(s, remaining_buflen(buf, s), "/*%s*/(",(char*)i._key);
s += strlen(s);
mnode->build_instr_pred(s,(char*)i._key, 0, path_bitmask, 0);
s += strlen(s);
@@ -3472,7 +3474,7 @@ void MatchNode::build_internalop( ) {
_rChild->_internalop : _rChild->_opType) : "";
len += (int)strlen(lstr) + (int)strlen(rstr);
subtree = (char *)AdlAllocateHeap(len);
- sprintf(subtree,"_%s_%s_%s", _opType, lstr, rstr);
+ snprintf_checked(subtree, len, "_%s_%s_%s", _opType, lstr, rstr);
// Hash the subtree string in _internalOps; if a name exists, use it
iop = (char *)_AD._internalOps[subtree];
// Else create a unique name, and add it to the hash table
@@ -3919,8 +3921,9 @@ void MatchRule::matchrule_swap_commutative_op(const char* instr_ident, int count
MatchRule* clone = new MatchRule(_AD, this);
// Swap operands of commutative operation
((MatchNode*)clone)->swap_commutative_op(true, count);
- char* buf = (char*) AdlAllocateHeap(strlen(instr_ident) + 4);
- sprintf(buf, "%s_%d", instr_ident, match_rules_cnt++);
+ const size_t buf_size = strlen(instr_ident) + 4;
+ char* buf = (char*) AdlAllocateHeap(buf_size);
+ snprintf_checked(buf, buf_size, "%s_%d", instr_ident, match_rules_cnt++);
clone->_result = buf;
clone->_next = this->_next;
@@ -4223,7 +4226,7 @@ bool MatchRule::is_vector() const {
"VectorTest", "VectorLoadMask", "VectorStoreMask", "VectorBlend", "VectorInsert",
"VectorRearrange","VectorLoadShuffle", "VectorLoadConst",
"VectorCastB2X", "VectorCastS2X", "VectorCastI2X",
- "VectorCastL2X", "VectorCastF2X", "VectorCastD2X",
+ "VectorCastL2X", "VectorCastF2X", "VectorCastD2X", "VectorCastF2HF", "VectorCastHF2F",
"VectorUCastB2X", "VectorUCastS2X", "VectorUCastI2X",
"VectorMaskWrapper","VectorMaskCmp","VectorReinterpret","LoadVectorMasked","StoreVectorMasked",
"FmaVD","FmaVF","PopCountVI","PopCountVL","PopulateIndex","VectorLongToMask",
diff --git a/src/hotspot/share/adlc/main.cpp b/src/hotspot/share/adlc/main.cpp
index 5016c540f11..dce3f2309f8 100644
--- a/src/hotspot/share/adlc/main.cpp
+++ b/src/hotspot/share/adlc/main.cpp
@@ -466,7 +466,7 @@ static char *base_plus_suffix(const char* base, const char *suffix)
int len = (int)strlen(base) + (int)strlen(suffix) + 1;
char* fname = new char[len];
- sprintf(fname,"%s%s",base,suffix);
+ snprintf_checked(fname,len,"%s%s",base,suffix);
return fname;
}
diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp
index 264012b8f15..93b32b73cbd 100644
--- a/src/hotspot/share/adlc/output_c.cpp
+++ b/src/hotspot/share/adlc/output_c.cpp
@@ -26,6 +26,8 @@
#include "adlc.hpp"
+#define remaining_buflen(buffer, position) (sizeof(buffer) - (position - buffer))
+
// Utilities to characterize effect statements
static bool is_def(int usedef) {
switch(usedef) {
@@ -35,6 +37,16 @@ static bool is_def(int usedef) {
return false;
}
+int snprintf_checked(char* buf, size_t len, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int result = vsnprintf(buf, len, fmt, args);
+ va_end(args);
+ assert(result >= 0, "snprintf error");
+ assert(static_cast(result) < len, "snprintf truncated");
+ return result;
+}
+
// Define an array containing the machine register names, strings.
static void defineRegNames(FILE *fp, RegisterForm *registers) {
if (registers) {
@@ -197,7 +209,8 @@ static int pipeline_reads_initializer(FILE *fp_cpp, NameList &pipeline_reads, Pi
return -1;
}
- char *operand_stages = new char [templen];
+ const size_t operand_stages_size = templen;
+ char *operand_stages = new char [operand_stages_size];
operand_stages[0] = 0;
int i = 0;
templen = 0;
@@ -211,7 +224,7 @@ static int pipeline_reads_initializer(FILE *fp_cpp, NameList &pipeline_reads, Pi
while ( (paramname = pipeclass->_parameters.iter()) != NULL ) {
const PipeClassOperandForm *tmppipeopnd =
(const PipeClassOperandForm *)pipeclass->_localUsage[paramname];
- templen += sprintf(&operand_stages[templen], " stage_%s%c\n",
+ templen += snprintf_checked(&operand_stages[templen], operand_stages_size - templen, " stage_%s%c\n",
tmppipeopnd ? tmppipeopnd->_stage : "undefined",
(++i < paramcount ? ',' : ' ') );
}
@@ -278,6 +291,7 @@ static int pipeline_res_stages_initializer(
int templen = 1 + commentlen + pipeline->_rescount * (max_stage + 14);
// Allocate space for the resource list
+ const size_t resource_stages_size = templen;
char * resource_stages = new char [templen];
templen = 0;
@@ -285,7 +299,7 @@ static int pipeline_res_stages_initializer(
const char * const resname =
res_stages[i] == 0 ? "undefined" : pipeline->_stages.name(res_stages[i]-1);
- templen += sprintf(&resource_stages[templen], " stage_%s%-*s // %s\n",
+ templen += snprintf_checked(&resource_stages[templen], resource_stages_size - templen, " stage_%s%-*s // %s\n",
resname, max_stage - (int)strlen(resname) + 1,
(i < pipeline->_rescount-1) ? "," : "",
pipeline->_reslist.name(i));
@@ -344,7 +358,7 @@ static int pipeline_res_cycles_initializer(
for (i = 0; i < pipeline->_rescount; i++) {
if (max_cycles < res_cycles[i])
max_cycles = res_cycles[i];
- templen = sprintf(temp, "%d", res_cycles[i]);
+ templen = snprintf_checked(temp, sizeof(temp), "%d", res_cycles[i]);
if (cyclelen < templen)
cyclelen = templen;
commentlen += (int)strlen(pipeline->_reslist.name(i));
@@ -353,12 +367,13 @@ static int pipeline_res_cycles_initializer(
templen = 1 + commentlen + (cyclelen + 8) * pipeline->_rescount;
// Allocate space for the resource list
- char * resource_cycles = new char [templen];
+ const size_t resource_cycles_size = templen;
+ char * resource_cycles = new char [resource_cycles_size];
templen = 0;
for (i = 0; i < pipeline->_rescount; i++) {
- templen += sprintf(&resource_cycles[templen], " %*d%c // %s\n",
+ templen += snprintf_checked(&resource_cycles[templen], resource_cycles_size - templen, " %*d%c // %s\n",
cyclelen, res_cycles[i], (i < pipeline->_rescount-1) ? ',' : ' ', pipeline->_reslist.name(i));
}
@@ -431,7 +446,8 @@ static int pipeline_res_mask_initializer(
(cyclemasksize * 12) + masklen + (cycledigit * 2) + 30) * element_count;
// Allocate space for the resource list
- char * resource_mask = new char [templen];
+ const size_t resource_mask_size = templen;
+ char * resource_mask = new char [resource_mask_size];
char * last_comma = NULL;
templen = 0;
@@ -456,7 +472,7 @@ static int pipeline_res_mask_initializer(
}
int formatlen =
- sprintf(&resource_mask[templen], " %s(0x%0*x, %*d, %*d, %s %s(",
+ snprintf_checked(&resource_mask[templen], resource_mask_size - templen, " %s(0x%0*x, %*d, %*d, %s %s(",
pipeline_use_element,
masklen, used_mask,
cycledigit, lb, cycledigit, ub,
@@ -496,7 +512,7 @@ static int pipeline_res_mask_initializer(
for (j = cyclemasksize-1; j >= 0; j--) {
formatlen =
- sprintf(&resource_mask[templen], "0x%08x%s", res_mask[j], j > 0 ? ", " : "");
+ snprintf_checked(&resource_mask[templen], resource_mask_size - templen, "0x%08x%s", res_mask[j], j > 0 ? ", " : "");
templen += formatlen;
}
@@ -527,9 +543,8 @@ static int pipeline_res_mask_initializer(
// "0x012345678, 0x012345678, 4294967295"
char* args = new char [36 + 1];
- int printed = sprintf(args, "0x%x, 0x%x, %u",
- resources_used, resources_used_exclusively, element_count);
- assert(printed <= 36, "overflow");
+ snprintf_checked(args, 36 + 1, "0x%x, 0x%x, %u",
+ resources_used, resources_used_exclusively, element_count);
pipeline_res_args.addName(args);
}
@@ -1066,9 +1081,9 @@ static void build_instruction_index_mapping( FILE *fp, FormDict &globals, PeepMa
InstructForm *inst = globals[inst_name]->is_instruction();
if( inst != NULL ) {
char inst_prefix[] = "instXXXX_";
- sprintf(inst_prefix, "inst%d_", inst_position);
+ snprintf_checked(inst_prefix, sizeof(inst_prefix), "inst%d_", inst_position);
char receiver[] = "instXXXX->";
- sprintf(receiver, "inst%d->", inst_position);
+ snprintf_checked(receiver, sizeof(receiver), "inst%d->", inst_position);
inst->index_temps( fp, globals, inst_prefix, receiver );
}
}
@@ -1162,7 +1177,7 @@ static void check_peepconstraints(FILE *fp, FormDict &globals, PeepMatch *pmatch
char left_reg_index[] = ",inst4294967295_idx4294967295";
if( left_op_index != 0 ) {
// Must have index into operands
- sprintf(left_reg_index,",inst%u_idx%u", (unsigned)left_index, (unsigned)left_op_index);
+ snprintf_checked(left_reg_index, sizeof(left_reg_index), ",inst%u_idx%u", (unsigned)left_index, (unsigned)left_op_index);
} else {
strcpy(left_reg_index, "");
}
@@ -1174,7 +1189,7 @@ static void check_peepconstraints(FILE *fp, FormDict &globals, PeepMatch *pmatch
char right_reg_index[] = ",inst4294967295_idx4294967295";
if( right_op_index != 0 ) {
// Must have index into operands
- sprintf(right_reg_index,",inst%u_idx%u", (unsigned)right_index, (unsigned)right_op_index);
+ snprintf_checked(right_reg_index, sizeof(right_reg_index), ",inst%u_idx%u", (unsigned)right_index, (unsigned)right_op_index);
} else {
strcpy(right_reg_index, "");
}
@@ -2563,19 +2578,19 @@ void ArchDesc::define_postalloc_expand(FILE *fp, InstructForm &inst) {
const char* arg_name = ins_encode->rep_var_name(inst, param_no);
int idx = inst.operand_position_format(arg_name);
if (strcmp(arg_name, "constanttablebase") == 0) {
- ib += sprintf(ib, " unsigned idx_%-5s = mach_constant_base_node_input(); \t// %s, \t%s\n",
+ ib += snprintf_checked(ib, remaining_buflen(idxbuf, ib), " unsigned idx_%-5s = mach_constant_base_node_input(); \t// %s, \t%s\n",
name, type, arg_name);
- nb += sprintf(nb, " Node *n_%-7s = lookup(idx_%s);\n", name, name);
+ nb += snprintf_checked(nb, remaining_buflen(nbuf, nb), " Node *n_%-7s = lookup(idx_%s);\n", name, name);
// There is no operand for the constanttablebase.
} else if (inst.is_noninput_operand(idx)) {
globalAD->syntax_err(inst._linenum,
"In %s: you can not pass the non-input %s to a postalloc expand encoding.\n",
inst._ident, arg_name);
} else {
- ib += sprintf(ib, " unsigned idx_%-5s = idx%d; \t// %s, \t%s\n",
+ ib += snprintf_checked(ib, remaining_buflen(idxbuf, ib), " unsigned idx_%-5s = idx%d; \t// %s, \t%s\n",
name, idx, type, arg_name);
- nb += sprintf(nb, " Node *n_%-7s = lookup(idx_%s);\n", name, name);
- ob += sprintf(ob, " %sOper *op_%s = (%sOper *)opnd_array(%d);\n", type, name, type, idx);
+ nb += snprintf_checked(nb, remaining_buflen(nbuf, nb), " Node *n_%-7s = lookup(idx_%s);\n", name, name);
+ ob += snprintf_checked(ob, remaining_buflen(opbuf, ob), " %sOper *op_%s = (%sOper *)opnd_array(%d);\n", type, name, type, idx);
}
param_no++;
}
diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp
index 485fa53face..f9ffd169e38 100644
--- a/src/hotspot/share/asm/codeBuffer.cpp
+++ b/src/hotspot/share/asm/codeBuffer.cpp
@@ -348,8 +348,8 @@ void CodeSection::relocate(address at, RelocationHolder const& spec, int format)
// each carrying the largest possible offset, to advance the locs_point.
while (offset >= relocInfo::offset_limit()) {
assert(end < locs_limit(), "adjust previous paragraph of code");
- *end++ = filler_relocInfo();
- offset -= filler_relocInfo().addr_offset();
+ *end++ = relocInfo::filler_info();
+ offset -= relocInfo::filler_info().addr_offset();
}
// If it's a simple reloc with no data, we'll just write (rtype | offset).
@@ -634,7 +634,7 @@ csize_t CodeBuffer::copy_relocations_to(address buf, csize_t buf_limit, bool onl
code_point_so_far < new_code_point;
code_point_so_far += jump) {
jump = new_code_point - code_point_so_far;
- relocInfo filler = filler_relocInfo();
+ relocInfo filler = relocInfo::filler_info();
if (jump >= filler.addr_offset()) {
jump = filler.addr_offset();
} else { // else shrink the filler to fit
diff --git a/src/hotspot/share/c1/c1_Compiler.cpp b/src/hotspot/share/c1/c1_Compiler.cpp
index ef741e82943..819ee6adeb9 100644
--- a/src/hotspot/share/c1/c1_Compiler.cpp
+++ b/src/hotspot/share/c1/c1_Compiler.cpp
@@ -154,7 +154,7 @@ bool Compiler::is_intrinsic_supported(const methodHandle& method) {
case vmIntrinsics::_getModifiers:
case vmIntrinsics::_currentCarrierThread:
case vmIntrinsics::_currentThread:
- case vmIntrinsics::_extentLocalCache:
+ case vmIntrinsics::_scopedValueCache:
case vmIntrinsics::_dabs:
case vmIntrinsics::_dsqrt:
case vmIntrinsics::_dsqrt_strict:
diff --git a/src/hotspot/share/c1/c1_Defs.hpp b/src/hotspot/share/c1/c1_Defs.hpp
index 183509e3b26..4d3763e07ba 100644
--- a/src/hotspot/share/c1/c1_Defs.hpp
+++ b/src/hotspot/share/c1/c1_Defs.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -56,4 +56,9 @@ enum {
float_saved_as_double = pd_float_saved_as_double
};
+// true if LIR requires src1 and dst to match in binary LIR ops
+enum {
+ two_operand_lir_form = pd_two_operand_lir_form
+};
+
#endif // SHARE_C1_C1_DEFS_HPP
diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp
index d07274f785f..5b903192c9e 100644
--- a/src/hotspot/share/c1/c1_LIR.cpp
+++ b/src/hotspot/share/c1/c1_LIR.cpp
@@ -194,7 +194,7 @@ void LIR_Op2::verify() const {
"can't produce oops from arith");
}
- if (TwoOperandLIRForm) {
+ if (two_operand_lir_form) {
#ifdef ASSERT
bool threeOperandForm = false;
diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp
index f6f0a6ac28b..a40c7b19b6d 100644
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp
@@ -491,7 +491,7 @@ void LIRGenerator::arithmetic_op(Bytecodes::Code code, LIR_Opr result, LIR_Opr l
LIR_Opr left_op = left;
LIR_Opr right_op = right;
- if (TwoOperandLIRForm && left_op != result_op) {
+ if (two_operand_lir_form && left_op != result_op) {
assert(right_op != result_op, "malformed");
__ move(left_op, result_op);
left_op = result_op;
@@ -563,7 +563,7 @@ void LIRGenerator::arithmetic_op_fpu(Bytecodes::Code code, LIR_Opr result, LIR_O
void LIRGenerator::shift_op(Bytecodes::Code code, LIR_Opr result_op, LIR_Opr value, LIR_Opr count, LIR_Opr tmp) {
- if (TwoOperandLIRForm && value != result_op
+ if (two_operand_lir_form && value != result_op
// Only 32bit right shifts require two operand form on S390.
S390_ONLY(&& (code == Bytecodes::_ishr || code == Bytecodes::_iushr))) {
assert(count != result_op, "malformed");
@@ -585,7 +585,7 @@ void LIRGenerator::shift_op(Bytecodes::Code code, LIR_Opr result_op, LIR_Opr val
void LIRGenerator::logic_op (Bytecodes::Code code, LIR_Opr result_op, LIR_Opr left_op, LIR_Opr right_op) {
- if (TwoOperandLIRForm && left_op != result_op) {
+ if (two_operand_lir_form && left_op != result_op) {
assert(right_op != result_op, "malformed");
__ move(left_op, result_op);
left_op = result_op;
@@ -1428,8 +1428,8 @@ void LIRGenerator::do_getObjectSize(Intrinsic* x) {
__ branch_destination(L_done->label());
}
-void LIRGenerator::do_extentLocalCache(Intrinsic* x) {
- do_JavaThreadField(x, JavaThread::extentLocalCache_offset());
+void LIRGenerator::do_scopedValueCache(Intrinsic* x) {
+ do_JavaThreadField(x, JavaThread::scopedValueCache_offset());
}
// Example: Thread.currentCarrierThread()
@@ -2948,7 +2948,7 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
case vmIntrinsics::_getObjectSize: do_getObjectSize(x); break;
case vmIntrinsics::_currentCarrierThread: do_currentCarrierThread(x); break;
case vmIntrinsics::_currentThread: do_vthread(x); break;
- case vmIntrinsics::_extentLocalCache: do_extentLocalCache(x); break;
+ case vmIntrinsics::_scopedValueCache: do_scopedValueCache(x); break;
case vmIntrinsics::_dlog: // fall through
case vmIntrinsics::_dlog10: // fall through
@@ -3547,7 +3547,7 @@ void LIRGenerator::do_MemBar(MemBar* x) {
LIR_Opr LIRGenerator::mask_boolean(LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info) {
LIR_Opr value_fixed = rlock_byte(T_BYTE);
- if (TwoOperandLIRForm) {
+ if (two_operand_lir_form) {
__ move(value, value_fixed);
__ logical_and(value_fixed, LIR_OprFact::intConst(1), value_fixed);
} else {
diff --git a/src/hotspot/share/c1/c1_LIRGenerator.hpp b/src/hotspot/share/c1/c1_LIRGenerator.hpp
index aedba60e973..7f4b25e89f1 100644
--- a/src/hotspot/share/c1/c1_LIRGenerator.hpp
+++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp
@@ -257,7 +257,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
void do_getClass(Intrinsic* x);
void do_getObjectSize(Intrinsic* x);
void do_currentCarrierThread(Intrinsic* x);
- void do_extentLocalCache(Intrinsic* x);
+ void do_scopedValueCache(Intrinsic* x);
void do_vthread(Intrinsic* x);
void do_JavaThreadField(Intrinsic* x, ByteSize offset);
void do_FmaIntrinsic(Intrinsic* x);
diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp
index 9e02d9f323d..4efb95fff80 100644
--- a/src/hotspot/share/c1/c1_Runtime1.cpp
+++ b/src/hotspot/share/c1/c1_Runtime1.cpp
@@ -688,7 +688,7 @@ JRT_ENTRY(void, Runtime1::throw_range_check_exception(JavaThread* current, int i
const int len = 35;
assert(len < strlen("Index %d out of bounds for length %d"), "Must allocate more space for message.");
char message[2 * jintAsStringSize + len];
- sprintf(message, "Index %d out of bounds for length %d", index, a->length());
+ os::snprintf_checked(message, sizeof(message), "Index %d out of bounds for length %d", index, a->length());
SharedRuntime::throw_and_post_jvmti_exception(current, vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message);
JRT_END
@@ -700,7 +700,7 @@ JRT_ENTRY(void, Runtime1::throw_index_exception(JavaThread* current, int index))
}
#endif
char message[16];
- sprintf(message, "%d", index);
+ os::snprintf_checked(message, sizeof(message), "%d", index);
SharedRuntime::throw_and_post_jvmti_exception(current, vmSymbols::java_lang_IndexOutOfBoundsException(), message);
JRT_END
diff --git a/src/hotspot/share/c1/c1_globals.hpp b/src/hotspot/share/c1/c1_globals.hpp
index 7f425680b47..1c22cf16cfe 100644
--- a/src/hotspot/share/c1/c1_globals.hpp
+++ b/src/hotspot/share/c1/c1_globals.hpp
@@ -203,9 +203,6 @@
develop_pd(bool, CSEArrayLength, \
"Create separate nodes for length in array accesses") \
\
- develop_pd(bool, TwoOperandLIRForm, \
- "true if LIR requires src1 and dst to match in binary LIR ops") \
- \
develop(intx, TraceLinearScanLevel, 0, \
"Debug levels for the linear scan allocator") \
range(0, 4) \
diff --git a/src/hotspot/share/cds/archiveHeapLoader.cpp b/src/hotspot/share/cds/archiveHeapLoader.cpp
index aa84ce15407..ce5eb2b6e75 100644
--- a/src/hotspot/share/cds/archiveHeapLoader.cpp
+++ b/src/hotspot/share/cds/archiveHeapLoader.cpp
@@ -24,7 +24,6 @@
#include "precompiled.hpp"
#include "cds/archiveHeapLoader.inline.hpp"
-#include "cds/filemap.hpp"
#include "cds/heapShared.hpp"
#include "cds/metaspaceShared.hpp"
#include "classfile/classLoaderDataShared.hpp"
@@ -114,12 +113,35 @@ class PatchCompressedEmbeddedPointers: public BitMapClosure {
narrowOop* p = _start + offset;
narrowOop v = *p;
assert(!CompressedOops::is_null(v), "null oops should have been filtered out at dump time");
- oop o = ArchiveHeapLoader::decode_from_archive(v);
+ oop o = ArchiveHeapLoader::decode_from_mapped_archive(v);
RawAccess::oop_store(p, o);
return true;
}
};
+class PatchCompressedEmbeddedPointersQuick: public BitMapClosure {
+ narrowOop* _start;
+ uint32_t _delta;
+
+ public:
+ PatchCompressedEmbeddedPointersQuick(narrowOop* start, uint32_t delta) : _start(start), _delta(delta) {}
+
+ bool do_bit(size_t offset) {
+ narrowOop* p = _start + offset;
+ narrowOop v = *p;
+ assert(!CompressedOops::is_null(v), "null oops should have been filtered out at dump time");
+ narrowOop new_v = CompressedOops::narrow_oop_cast(CompressedOops::narrow_oop_value(v) + _delta);
+ assert(!CompressedOops::is_null(new_v), "should never relocate to narrowOop(0)");
+#ifdef ASSERT
+ oop o1 = ArchiveHeapLoader::decode_from_mapped_archive(v);
+ oop o2 = CompressedOops::decode_not_null(new_v);
+ assert(o1 == o2, "quick delta must work");
+#endif
+ RawAccess::oop_store(p, new_v);
+ return true;
+ }
+};
+
class PatchUncompressedEmbeddedPointers: public BitMapClosure {
oop* _start;
@@ -136,9 +158,38 @@ class PatchUncompressedEmbeddedPointers: public BitMapClosure {
}
};
+void ArchiveHeapLoader::patch_compressed_embedded_pointers(BitMapView bm,
+ FileMapInfo* info,
+ FileMapRegion* map_region,
+ MemRegion region) {
+ narrowOop dt_encoded_bottom = info->encoded_heap_region_dumptime_address(map_region);
+ narrowOop rt_encoded_bottom = CompressedOops::encode_not_null(cast_to_oop(region.start()));
+ log_info(cds)("patching heap embedded pointers: narrowOop 0x%8x -> 0x%8x",
+ (uint)dt_encoded_bottom, (uint)rt_encoded_bottom);
+
+ // Optimization: if dumptime shift is the same as runtime shift, we can perform a
+ // quick conversion from "dumptime narrowOop" -> "runtime narrowOop".
+ if (_narrow_oop_shift == CompressedOops::shift()) {
+ uint32_t quick_delta = (uint32_t)rt_encoded_bottom - (uint32_t)dt_encoded_bottom;
+ log_info(cds)("CDS heap data relocation quick delta = 0x%x", quick_delta);
+ if (quick_delta == 0) {
+ log_info(cds)("CDS heap data relocation unnecessary, quick_delta = 0");
+ } else {
+ PatchCompressedEmbeddedPointersQuick patcher((narrowOop*)region.start(), quick_delta);
+ bm.iterate(&patcher);
+ }
+ } else {
+ log_info(cds)("CDS heap data quick relocation not possible");
+ PatchCompressedEmbeddedPointers patcher((narrowOop*)region.start());
+ bm.iterate(&patcher);
+ }
+}
+
// Patch all the non-null pointers that are embedded in the archived heap objects
// in this (mapped) region
-void ArchiveHeapLoader::patch_embedded_pointers(MemRegion region, address oopmap,
+void ArchiveHeapLoader::patch_embedded_pointers(FileMapInfo* info,
+ FileMapRegion* map_region,
+ MemRegion region, address oopmap,
size_t oopmap_size_in_bits) {
BitMapView bm((BitMap::bm_word_t*)oopmap, oopmap_size_in_bits);
@@ -149,8 +200,7 @@ void ArchiveHeapLoader::patch_embedded_pointers(MemRegion region, address oopmap
#endif
if (UseCompressedOops) {
- PatchCompressedEmbeddedPointers patcher((narrowOop*)region.start());
- bm.iterate(&patcher);
+ patch_compressed_embedded_pointers(bm, info, map_region, region);
} else {
PatchUncompressedEmbeddedPointers patcher((oop*)region.start());
bm.iterate(&patcher);
diff --git a/src/hotspot/share/cds/archiveHeapLoader.hpp b/src/hotspot/share/cds/archiveHeapLoader.hpp
index 97e0edf6314..754893cb4fa 100644
--- a/src/hotspot/share/cds/archiveHeapLoader.hpp
+++ b/src/hotspot/share/cds/archiveHeapLoader.hpp
@@ -25,12 +25,14 @@
#ifndef SHARE_CDS_ARCHIVEHEAPLOADER_HPP
#define SHARE_CDS_ARCHIVEHEAPLOADER_HPP
+#include "cds/filemap.hpp"
#include "gc/shared/gc_globals.hpp"
#include "memory/allocation.hpp"
#include "memory/allStatic.hpp"
#include "memory/memRegion.hpp"
#include "oops/oopsHierarchy.hpp"
#include "runtime/globals.hpp"
+#include "utilities/bitMap.hpp"
#include "utilities/macros.hpp"
class FileMapInfo;
@@ -103,8 +105,18 @@ class ArchiveHeapLoader : AllStatic {
// function instead.
inline static oop decode_from_archive(narrowOop v) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
- static void patch_embedded_pointers(MemRegion region, address oopmap,
- size_t oopmap_in_bits) NOT_CDS_JAVA_HEAP_RETURN;
+ // More efficient version, but works only when ArchiveHeap is mapped.
+ inline static oop decode_from_mapped_archive(narrowOop v) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
+
+ static void patch_compressed_embedded_pointers(BitMapView bm,
+ FileMapInfo* info,
+ FileMapRegion* map_region,
+ MemRegion region) NOT_CDS_JAVA_HEAP_RETURN;
+
+ static void patch_embedded_pointers(FileMapInfo* info,
+ FileMapRegion* map_region,
+ MemRegion region, address oopmap,
+ size_t oopmap_size_in_bits) NOT_CDS_JAVA_HEAP_RETURN;
static void fixup_regions() NOT_CDS_JAVA_HEAP_RETURN;
@@ -159,6 +171,9 @@ class ArchiveHeapLoader : AllStatic {
return (_loaded_heap_bottom <= o && o < _loaded_heap_top);
}
+ template
+ inline static oop decode_from_archive_impl(narrowOop v) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
+
public:
static bool load_heap_regions(FileMapInfo* mapinfo);
diff --git a/src/hotspot/share/cds/archiveHeapLoader.inline.hpp b/src/hotspot/share/cds/archiveHeapLoader.inline.hpp
index 34ac6e15a1a..6f344ddf526 100644
--- a/src/hotspot/share/cds/archiveHeapLoader.inline.hpp
+++ b/src/hotspot/share/cds/archiveHeapLoader.inline.hpp
@@ -32,11 +32,14 @@
#if INCLUDE_CDS_JAVA_HEAP
-inline oop ArchiveHeapLoader::decode_from_archive(narrowOop v) {
+template
+inline oop ArchiveHeapLoader::decode_from_archive_impl(narrowOop v) {
assert(!CompressedOops::is_null(v), "narrow oop value can never be zero");
assert(_narrow_oop_base_initialized, "relocation information must have been initialized");
uintptr_t p = ((uintptr_t)_narrow_oop_base) + ((uintptr_t)v << _narrow_oop_shift);
- if (p >= _dumptime_base_0) {
+ if (IS_MAPPED) {
+ assert(_dumptime_base_0 == UINTPTR_MAX, "must be");
+ } else if (p >= _dumptime_base_0) {
assert(p < _dumptime_top, "must be");
if (p >= _dumptime_base_3) {
p += _runtime_offset_3;
@@ -54,6 +57,14 @@ inline oop ArchiveHeapLoader::decode_from_archive(narrowOop v) {
return result;
}
+inline oop ArchiveHeapLoader::decode_from_archive(narrowOop v) {
+ return decode_from_archive_impl(v);
+}
+
+inline oop ArchiveHeapLoader::decode_from_mapped_archive(narrowOop v) {
+ return decode_from_archive_impl(v);
+}
+
#endif
#endif // SHARE_CDS_ARCHIVEHEAPLOADER_INLINE_HPP
diff --git a/src/hotspot/share/cds/cdsHeapVerifier.cpp b/src/hotspot/share/cds/cdsHeapVerifier.cpp
index 710c87069b0..c02caced364 100644
--- a/src/hotspot/share/cds/cdsHeapVerifier.cpp
+++ b/src/hotspot/share/cds/cdsHeapVerifier.cpp
@@ -236,7 +236,7 @@ inline bool CDSHeapVerifier::do_entry(oop& orig_obj, HeapShared::CachedOopInfo&
ls.print("Value: ");
orig_obj->print_on(&ls);
ls.print_cr("--- trace begin ---");
- trace_to_root(orig_obj, NULL, &value);
+ trace_to_root(&ls, orig_obj, NULL, &value);
ls.print_cr("--- trace end ---");
ls.cr();
_problems ++;
@@ -248,54 +248,62 @@ inline bool CDSHeapVerifier::do_entry(oop& orig_obj, HeapShared::CachedOopInfo&
class CDSHeapVerifier::TraceFields : public FieldClosure {
oop _orig_obj;
oop _orig_field;
- LogStream* _ls;
+ outputStream* _st;
public:
- TraceFields(oop orig_obj, oop orig_field, LogStream* ls)
- : _orig_obj(orig_obj), _orig_field(orig_field), _ls(ls) {}
+ TraceFields(oop orig_obj, oop orig_field, outputStream* st)
+ : _orig_obj(orig_obj), _orig_field(orig_field), _st(st) {}
void do_field(fieldDescriptor* fd) {
if (fd->field_type() == T_OBJECT || fd->field_type() == T_ARRAY) {
oop obj_field = _orig_obj->obj_field(fd->offset());
if (obj_field == _orig_field) {
- _ls->print("::%s (offset = %d)", fd->name()->as_C_string(), fd->offset());
+ _st->print("::%s (offset = %d)", fd->name()->as_C_string(), fd->offset());
}
}
}
};
-// Hint: to exercise this function, uncomment out one of the ADD_EXCL lines above.
-int CDSHeapVerifier::trace_to_root(oop orig_obj, oop orig_field, HeapShared::CachedOopInfo* p) {
+// Call this function (from gdb, etc) if you want to know why an object is archived.
+void CDSHeapVerifier::trace_to_root(outputStream* st, oop orig_obj) {
+ HeapShared::CachedOopInfo* info = HeapShared::archived_object_cache()->get(orig_obj);
+ if (info != NULL) {
+ trace_to_root(st, orig_obj, NULL, info);
+ } else {
+ st->print_cr("Not an archived object??");
+ }
+}
+
+int CDSHeapVerifier::trace_to_root(outputStream* st, oop orig_obj, oop orig_field, HeapShared::CachedOopInfo* info) {
int level = 0;
- LogStream ls(Log(cds, heap)::warning());
- if (p->_referrer != NULL) {
- HeapShared::CachedOopInfo* ref = HeapShared::archived_object_cache()->get(p->_referrer);
+ if (info->_referrer != NULL) {
+ HeapShared::CachedOopInfo* ref = HeapShared::archived_object_cache()->get(info->_referrer);
assert(ref != NULL, "sanity");
- level = trace_to_root(p->_referrer, orig_obj, ref) + 1;
+ level = trace_to_root(st, info->_referrer, orig_obj, ref) + 1;
} else if (java_lang_String::is_instance(orig_obj)) {
- ls.print_cr("[%2d] (shared string table)", level++);
+ st->print_cr("[%2d] (shared string table)", level++);
}
Klass* k = orig_obj->klass();
ResourceMark rm;
- ls.print("[%2d] ", level);
- orig_obj->print_address_on(&ls);
- ls.print(" %s", k->internal_name());
+ st->print("[%2d] ", level);
+ orig_obj->print_address_on(st);
+ st->print(" %s", k->internal_name());
if (orig_field != NULL) {
if (k->is_instance_klass()) {
- TraceFields clo(orig_obj, orig_field, &ls);;
+ TraceFields clo(orig_obj, orig_field, st);
InstanceKlass::cast(k)->do_nonstatic_fields(&clo);
} else {
assert(orig_obj->is_objArray(), "must be");
objArrayOop array = (objArrayOop)orig_obj;
for (int i = 0; i < array->length(); i++) {
if (array->obj_at(i) == orig_field) {
- ls.print(" @[%d]", i);
+ st->print(" @[%d]", i);
break;
}
}
}
}
- ls.cr();
+ st->cr();
return level;
}
diff --git a/src/hotspot/share/cds/cdsHeapVerifier.hpp b/src/hotspot/share/cds/cdsHeapVerifier.hpp
index 6bc8c7ddd87..947308e24e8 100644
--- a/src/hotspot/share/cds/cdsHeapVerifier.hpp
+++ b/src/hotspot/share/cds/cdsHeapVerifier.hpp
@@ -69,7 +69,7 @@ class CDSHeapVerifier : public KlassClosure {
}
return NULL;
}
- int trace_to_root(oop orig_obj, oop orig_field, HeapShared::CachedOopInfo* p);
+ static int trace_to_root(outputStream* st, oop orig_obj, oop orig_field, HeapShared::CachedOopInfo* p);
CDSHeapVerifier();
~CDSHeapVerifier();
@@ -83,6 +83,8 @@ class CDSHeapVerifier : public KlassClosure {
inline bool do_entry(oop& orig_obj, HeapShared::CachedOopInfo& value);
static void verify() NOT_DEBUG_RETURN;
+
+ static void trace_to_root(outputStream* st, oop orig_obj);
};
#endif // INCLUDE_CDS_JAVA_HEAP
diff --git a/src/hotspot/share/cds/cdsProtectionDomain.cpp b/src/hotspot/share/cds/cdsProtectionDomain.cpp
index 7f8c25d9ae5..6992fd0d5dc 100644
--- a/src/hotspot/share/cds/cdsProtectionDomain.cpp
+++ b/src/hotspot/share/cds/cdsProtectionDomain.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "cds/cdsProtectionDomain.hpp"
#include "classfile/classLoader.hpp"
+#include "classfile/classLoaderData.inline.hpp"
#include "classfile/classLoaderExt.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/moduleEntry.hpp"
@@ -125,7 +126,7 @@ PackageEntry* CDSProtectionDomain::get_package_entry_from_class(InstanceKlass* i
}
TempNewSymbol pkg_name = ClassLoader::package_from_class_name(ik->name());
if (pkg_name != NULL) {
- pkg_entry = SystemDictionaryShared::class_loader_data(class_loader)->packages()->lookup_only(pkg_name);
+ pkg_entry = ClassLoaderData::class_loader_data(class_loader())->packages()->lookup_only(pkg_name);
} else {
pkg_entry = NULL;
}
@@ -292,7 +293,7 @@ void CDSProtectionDomain::atomic_set_array_index(OopHandle array, int index, oop
// The important thing here is that all threads pick up the same result.
// It doesn't matter which racing thread wins, as long as only one
// result is used by all threads, and all future queries.
- ((objArrayOop)array.resolve())->atomic_compare_exchange_oop(index, o, NULL);
+ ((objArrayOop)array.resolve())->replace_if_null(index, o);
}
oop CDSProtectionDomain::shared_protection_domain(int index) {
diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp
index e08917aa30b..6c792c0fd2b 100644
--- a/src/hotspot/share/cds/filemap.cpp
+++ b/src/hotspot/share/cds/filemap.cpp
@@ -169,7 +169,7 @@ template static void get_header_version(char (&header_version) [N]) {
strncpy(header_version, vm_version, JVM_IDENT_MAX-9);
// Append the hash code as eight hex digits.
- sprintf(&header_version[JVM_IDENT_MAX-9], "%08x", hash);
+ os::snprintf_checked(&header_version[JVM_IDENT_MAX-9], 9, "%08x", hash);
header_version[JVM_IDENT_MAX-1] = 0; // Null terminate.
}
@@ -880,11 +880,13 @@ unsigned int FileMapInfo::longest_common_app_classpath_prefix_len(int num_paths,
if (rp_array->at(i)[pos] != '\0' && rp_array->at(i)[pos] == rp_array->at(0)[pos]) {
continue;
}
-
// search backward for the pos before the file separator char
- while (pos > 0 && rp_array->at(0)[--pos] != *os::file_separator());
- // return the file separator char position
- return pos + 1;
+ while (pos > 0) {
+ if (rp_array->at(0)[--pos] == *os::file_separator()) {
+ return pos + 1;
+ }
+ }
+ return 0;
}
}
return 0;
@@ -1022,8 +1024,12 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) {
// java -Xshare:auto -cp /x/y/Foo.jar:/x/y/b/Bar.jar ...
unsigned int dumptime_prefix_len = header()->common_app_classpath_prefix_size();
unsigned int runtime_prefix_len = longest_common_app_classpath_prefix_len(shared_app_paths_len, rp_array);
- mismatch = check_paths(j, shared_app_paths_len, rp_array,
- dumptime_prefix_len, runtime_prefix_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,
+ dumptime_prefix_len, runtime_prefix_len);
+ }
if (mismatch) {
return classpath_failure("[APP classpath mismatch, actual: -Djava.class.path=", appcp);
}
@@ -2060,6 +2066,20 @@ size_t FileMapInfo::read_bytes(void* buffer, size_t count) {
return count;
}
+// Get the total size in bytes of a read only region
+size_t FileMapInfo::readonly_total() {
+ size_t total = 0;
+ if (current_info() != nullptr) {
+ FileMapRegion* r = FileMapInfo::current_info()->region_at(MetaspaceShared::ro);
+ if (r->read_only()) total += r->used();
+ }
+ if (dynamic_info() != nullptr) {
+ FileMapRegion* r = FileMapInfo::dynamic_info()->region_at(MetaspaceShared::ro);
+ if (r->read_only()) total += r->used();
+ }
+ return total;
+}
+
static MemRegion *closed_heap_regions = NULL;
static MemRegion *open_heap_regions = NULL;
static int num_closed_heap_regions = 0;
@@ -2433,6 +2453,13 @@ void FileMapInfo::patch_heap_embedded_pointers() {
MetaspaceShared::first_open_heap_region);
}
+narrowOop FileMapInfo::encoded_heap_region_dumptime_address(FileMapRegion* r) {
+ assert(UseSharedSpaces, "runtime only");
+ assert(UseCompressedOops, "sanity");
+ r->assert_is_heap_region();
+ return CompressedOops::narrow_oop_cast(r->mapping_offset() >> narrow_oop_shift());
+}
+
void FileMapInfo::patch_heap_embedded_pointers(MemRegion* regions, int num_regions,
int first_region_idx) {
char* bitmap_base = map_bitmap_region();
@@ -2440,24 +2467,9 @@ void FileMapInfo::patch_heap_embedded_pointers(MemRegion* regions, int num_regio
for (int i=0; imapping_offset() >> narrow_oop_shift());
- narrowOop rt_encoded_bottom = CompressedOops::encode_not_null(cast_to_oop(regions[i].start()));
- log_info(cds)("patching heap embedded pointers for %s: narrowOop 0x%8x -> 0x%8x",
- region_name(region_idx), (uint)dt_encoded_bottom, (uint)rt_encoded_bottom);
- // TODO JDK-8269736: if we have the same narrow_oop_shift between dumptime and runtime,
- // Each embedded pointer P can be updated by:
- // P += (rt_encoded_bottom - dt_encoded_bottom)
- //
- // TODO:
- // if (dt_encoded_bottom == rt_encoded_bottom && narrow_oop_shift() == CompressedOops::shift()) {
- // //nothing to do
- // return;
- // }
- }
+
ArchiveHeapLoader::patch_embedded_pointers(
- regions[i],
+ this, r, regions[i],
(address)(region_at(MetaspaceShared::bm)->mapped_base()) + r->oopmap_offset(),
r->oopmap_size_in_bits());
}
diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp
index a67274d532a..541b8fd603a 100644
--- a/src/hotspot/share/cds/filemap.hpp
+++ b/src/hotspot/share/cds/filemap.hpp
@@ -460,6 +460,7 @@ class FileMapInfo : public CHeapObj {
void write_bytes(const void* buffer, size_t count);
void write_bytes_aligned(const void* buffer, size_t count);
size_t read_bytes(void* buffer, size_t count);
+ static size_t readonly_total();
MapArchiveResult map_regions(int regions[], int num_regions, char* mapped_base_address, ReservedSpace rs);
void unmap_regions(int regions[], int num_regions);
void map_or_load_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
@@ -592,6 +593,7 @@ class FileMapInfo : public CHeapObj {
address heap_region_dumptime_address(FileMapRegion* r) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
address heap_region_requested_address(FileMapRegion* r) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
address heap_region_mapped_address(FileMapRegion* r) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
+ narrowOop encoded_heap_region_dumptime_address(FileMapRegion* r);
private:
diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp
index 6a37a50f127..0f5cee30939 100644
--- a/src/hotspot/share/cds/heapShared.cpp
+++ b/src/hotspot/share/cds/heapShared.cpp
@@ -30,9 +30,8 @@
#include "cds/heapShared.hpp"
#include "cds/metaspaceShared.hpp"
#include "classfile/classLoaderData.hpp"
-#include "classfile/classLoaderDataShared.hpp"
#include "classfile/javaClasses.inline.hpp"
-#include "classfile/moduleEntry.hpp"
+#include "classfile/modules.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
@@ -84,6 +83,11 @@ bool HeapShared::_disable_writing = false;
DumpedInternedStrings *HeapShared::_dumped_interned_strings = NULL;
GrowableArrayCHeap* HeapShared::_native_pointers = NULL;
+size_t HeapShared::_alloc_count[HeapShared::ALLOC_STAT_SLOTS];
+size_t HeapShared::_alloc_size[HeapShared::ALLOC_STAT_SLOTS];
+size_t HeapShared::_total_obj_count;
+size_t HeapShared::_total_obj_size;
+
#ifndef PRODUCT
#define ARCHIVE_TEST_FIELD_NAME "archivedObjects"
static Array* _archived_ArchiveHeapTestClass = NULL;
@@ -301,6 +305,7 @@ oop HeapShared::archive_object(oop obj) {
oop archived_oop = cast_to_oop(G1CollectedHeap::heap()->archive_mem_allocate(len));
if (archived_oop != NULL) {
+ count_allocation(len);
Copy::aligned_disjoint_words(cast_from_oop(obj), cast_from_oop(archived_oop), len);
// Reinitialize markword to remove age/marking/locking/etc.
//
@@ -548,7 +553,7 @@ void HeapShared::copy_open_objects(GrowableArray* open_regions) {
archive_object_subgraphs(fmg_open_archive_subgraph_entry_fields,
false /* is_closed_archive */,
true /* is_full_module_graph */);
- ClassLoaderDataShared::init_archived_oops();
+ Modules::verify_archived_modules();
}
copy_roots();
@@ -586,6 +591,7 @@ void HeapShared::copy_roots() {
roots()->obj_at_put(i, _pending_roots->at(i));
}
log_info(cds)("archived obj roots[%d] = " SIZE_FORMAT " words, klass = %p, obj = %p", length, size, k, mem);
+ count_allocation(roots()->size());
}
//
@@ -831,6 +837,9 @@ void HeapShared::write_subgraph_info_table() {
_archived_ArchiveHeapTestClass = array;
}
#endif
+ if (log_is_enabled(Info, cds, heap)) {
+ print_stats();
+ }
}
void HeapShared::serialize_root(SerializeClosure* soc) {
@@ -1179,25 +1188,6 @@ void HeapShared::check_closed_region_object(InstanceKlass* k) {
}
}
-void HeapShared::check_module_oop(oop orig_module_obj) {
- assert(DumpSharedSpaces, "must be");
- assert(java_lang_Module::is_instance(orig_module_obj), "must be");
- ModuleEntry* orig_module_ent = java_lang_Module::module_entry_raw(orig_module_obj);
- if (orig_module_ent == NULL) {
- // These special Module objects are created in Java code. They are not
- // defined via Modules::define_module(), so they don't have a ModuleEntry:
- // java.lang.Module::ALL_UNNAMED_MODULE
- // java.lang.Module::EVERYONE_MODULE
- // jdk.internal.loader.ClassLoaders$BootClassLoader::unnamedModule
- assert(java_lang_Module::name(orig_module_obj) == NULL, "must be unnamed");
- log_info(cds, heap)("Module oop with No ModuleEntry* @[" PTR_FORMAT "]", p2i(orig_module_obj));
- } else {
- ClassLoaderData* loader_data = orig_module_ent->loader_data();
- assert(loader_data->is_builtin_class_loader_data(), "must be");
- }
-}
-
-
// (1) If orig_obj has not been archived yet, archive it.
// (2) If orig_obj has not been seen yet (since start_recording_subgraph() was called),
// trace all objects that are reachable from it, and make sure these objects are archived.
@@ -1266,9 +1256,10 @@ oop HeapShared::archive_reachable_objects_from(int level,
}
if (java_lang_Module::is_instance(orig_obj)) {
- check_module_oop(orig_obj);
+ if (Modules::check_module_oop(orig_obj)) {
+ Modules::update_oops_in_archived_module(orig_obj, append_root(archived_obj));
+ }
java_lang_Module::set_module_entry(archived_obj, NULL);
- java_lang_Module::set_loader(archived_obj, NULL);
} else if (java_lang_ClassLoader::is_instance(orig_obj)) {
// class_data will be restored explicitly at run time.
guarantee(orig_obj == SystemDictionary::java_platform_loader() ||
@@ -1858,4 +1849,49 @@ ResourceBitMap HeapShared::calculate_ptrmap(MemRegion region) {
}
}
+void HeapShared::count_allocation(size_t size) {
+ _total_obj_count ++;
+ _total_obj_size += size;
+ for (int i = 0; i < ALLOC_STAT_SLOTS; i++) {
+ if (size <= (size_t(1) << i)) {
+ _alloc_count[i] ++;
+ _alloc_size[i] += size;
+ return;
+ }
+ }
+}
+
+static double avg_size(size_t size, size_t count) {
+ double avg = 0;
+ if (count > 0) {
+ avg = double(size * HeapWordSize) / double(count);
+ }
+ return avg;
+}
+
+void HeapShared::print_stats() {
+ size_t huge_count = _total_obj_count;
+ size_t huge_size = _total_obj_size;
+
+ for (int i = 0; i < ALLOC_STAT_SLOTS; i++) {
+ size_t byte_size_limit = (size_t(1) << i) * HeapWordSize;
+ size_t count = _alloc_count[i];
+ size_t size = _alloc_size[i];
+ log_info(cds, heap)(SIZE_FORMAT_W(8) " objects are <= " SIZE_FORMAT_W(-6)
+ " bytes (total " SIZE_FORMAT_W(8) " bytes, avg %8.1f bytes)",
+ count, byte_size_limit, size * HeapWordSize, avg_size(size, count));
+ huge_count -= count;
+ huge_size -= size;
+ }
+
+ log_info(cds, heap)(SIZE_FORMAT_W(8) " huge objects (total " SIZE_FORMAT_W(8) " bytes"
+ ", avg %8.1f bytes)",
+ huge_count, huge_size * HeapWordSize,
+ avg_size(huge_size, huge_count));
+ log_info(cds, heap)(SIZE_FORMAT_W(8) " total objects (total " SIZE_FORMAT_W(8) " bytes"
+ ", avg %8.1f bytes)",
+ _total_obj_count, _total_obj_size * HeapWordSize,
+ avg_size(_total_obj_size, _total_obj_count));
+}
+
#endif // INCLUDE_CDS_JAVA_HEAP
diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp
index 9990ab825b3..c77009e5107 100644
--- a/src/hotspot/share/cds/heapShared.hpp
+++ b/src/hotspot/share/cds/heapShared.hpp
@@ -162,6 +162,15 @@ class HeapShared: AllStatic {
static DumpedInternedStrings *_dumped_interned_strings;
static GrowableArrayCHeap* _native_pointers;
+ // statistics
+ constexpr static int ALLOC_STAT_SLOTS = 16;
+ static size_t _alloc_count[ALLOC_STAT_SLOTS];
+ static size_t _alloc_size[ALLOC_STAT_SLOTS];
+ static size_t _total_obj_count;
+ static size_t _total_obj_size; // in HeapWords
+
+ static void count_allocation(size_t size);
+ static void print_stats();
public:
static unsigned oop_hash(oop const& p);
static unsigned string_oop_hash(oop const& string) {
@@ -292,7 +301,6 @@ class HeapShared: AllStatic {
static bool has_been_seen_during_subgraph_recording(oop obj);
static void set_has_been_seen_during_subgraph_recording(oop obj);
- static void check_module_oop(oop orig_module_obj);
static void copy_roots();
static void resolve_classes_for_subgraphs(JavaThread* current, ArchivableStaticFieldInfo fields[]);
diff --git a/src/hotspot/share/ci/ciArrayKlass.cpp b/src/hotspot/share/ci/ciArrayKlass.cpp
index e4d66f247a4..c9cf6cf85e3 100644
--- a/src/hotspot/share/ci/ciArrayKlass.cpp
+++ b/src/hotspot/share/ci/ciArrayKlass.cpp
@@ -26,7 +26,8 @@
#include "ci/ciArrayKlass.hpp"
#include "ci/ciObjArrayKlass.hpp"
#include "ci/ciTypeArrayKlass.hpp"
-#include "ci/ciUtilities.hpp"
+#include "ci/ciUtilities.inline.hpp"
+#include "memory/universe.hpp"
// ciArrayKlass
//
@@ -103,3 +104,4 @@ ciArrayKlass* ciArrayKlass::make(ciType* element_type) {
return ciObjArrayKlass::make(element_type->as_klass());
}
}
+
diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp
index 814b6049710..b1884563cc9 100644
--- a/src/hotspot/share/ci/ciEnv.cpp
+++ b/src/hotspot/share/ci/ciEnv.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -692,7 +692,7 @@ ciConstant ciEnv::unbox_primitive_value(ciObject* cibox, BasicType expected_bt)
//
ciConstant ciEnv::get_resolved_constant(const constantPoolHandle& cpool, int obj_index) {
assert(obj_index >= 0, "");
- oop obj = cpool->resolved_references()->obj_at(obj_index);
+ oop obj = cpool->resolved_reference_at(obj_index);
if (obj == NULL) {
// Unresolved constant. It is resolved when the corresponding slot contains a non-null reference.
// Null constant is represented as a sentinel (non-null) value.
@@ -1226,7 +1226,7 @@ int ciEnv::comp_level() {
// ------------------------------------------------------------------
// ciEnv::compile_id
-uint ciEnv::compile_id() {
+int ciEnv::compile_id() {
if (task() == NULL) return 0;
return task()->compile_id();
}
diff --git a/src/hotspot/share/ci/ciEnv.hpp b/src/hotspot/share/ci/ciEnv.hpp
index 48947f99b23..21b442b6e05 100644
--- a/src/hotspot/share/ci/ciEnv.hpp
+++ b/src/hotspot/share/ci/ciEnv.hpp
@@ -366,7 +366,7 @@ class ciEnv : StackObj {
// Handy forwards to the task:
int comp_level(); // task()->comp_level()
- uint compile_id(); // task()->compile_id()
+ int compile_id(); // task()->compile_id()
// Register the result of a compilation.
void register_method(ciMethod* target,
diff --git a/src/hotspot/share/ci/ciField.cpp b/src/hotspot/share/ci/ciField.cpp
index 485db1b2748..24bf59dcb91 100644
--- a/src/hotspot/share/ci/ciField.cpp
+++ b/src/hotspot/share/ci/ciField.cpp
@@ -225,7 +225,7 @@ static bool trust_final_non_static_fields(ciInstanceKlass* holder) {
// Even if general trusting is disabled, trust system-built closures in these packages.
if (holder->is_in_package("java/lang/invoke") || holder->is_in_package("sun/invoke") ||
holder->is_in_package("java/lang/reflect") || holder->is_in_package("jdk/internal/reflect") ||
- holder->is_in_package("jdk/internal/foreign") || holder->is_in_package("java/lang/foreign") ||
+ holder->is_in_package("jdk/internal/foreign/layout") || holder->is_in_package("jdk/internal/foreign") ||
holder->is_in_package("jdk/internal/vm/vector") || holder->is_in_package("jdk/incubator/vector") ||
holder->is_in_package("java/lang"))
return true;
diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp
index 584e7d0b1ef..b9aa07a0b0b 100644
--- a/src/hotspot/share/ci/ciInstanceKlass.cpp
+++ b/src/hotspot/share/ci/ciInstanceKlass.cpp
@@ -69,6 +69,7 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
_nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields:
_has_injected_fields = -1;
_implementor = NULL; // we will fill these lazily
+ _transitive_interfaces = NULL;
// Ensure that the metadata wrapped by the ciMetadata is kept alive by GC.
// This is primarily useful for metadata which is considered as weak roots
@@ -729,6 +730,32 @@ void ciInstanceKlass::dump_replay_instanceKlass(outputStream* out, InstanceKlass
}
}
+GrowableArray* ciInstanceKlass::transitive_interfaces() const{
+ if (_transitive_interfaces == NULL) {
+ const_cast(this)->compute_transitive_interfaces();
+ }
+ return _transitive_interfaces;
+}
+
+void ciInstanceKlass::compute_transitive_interfaces() {
+ GUARDED_VM_ENTRY(
+ InstanceKlass* ik = get_instanceKlass();
+ Array