diff --git a/.github/actions/do-build/action.yml b/.github/actions/do-build/action.yml index 3deb7f4b8f8..79eddf8c70f 100644 --- a/.github/actions/do-build/action.yml +++ b/.github/actions/do-build/action.yml @@ -66,7 +66,7 @@ runs: shell: bash - name: 'Upload build logs' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: failure-logs-${{ inputs.platform }}${{ inputs.debug-suffix }} path: failure-logs @@ -74,7 +74,7 @@ runs: # This is the best way I found to abort the job with an error message - name: 'Notify about build failures' - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: core.setFailed('Build failed. See summary for details.') if: steps.check.outputs.failure == 'true' diff --git a/.github/actions/get-bootjdk/action.yml b/.github/actions/get-bootjdk/action.yml index 1e569dd47c5..25ee1d8dfa0 100644 --- a/.github/actions/get-bootjdk/action.yml +++ b/.github/actions/get-bootjdk/action.yml @@ -65,7 +65,7 @@ runs: - name: 'Check cache for BootJDK' id: get-cached-bootjdk - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: bootjdk/jdk key: boot-jdk-${{ inputs.platform }}-${{ steps.sha256.outputs.value }} diff --git a/.github/actions/get-bundles/action.yml b/.github/actions/get-bundles/action.yml index 956e1520cfb..0e52320a350 100644 --- a/.github/actions/get-bundles/action.yml +++ b/.github/actions/get-bundles/action.yml @@ -48,14 +48,14 @@ runs: steps: - name: 'Download bundles artifact' id: download-bundles - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }} path: bundles continue-on-error: true - name: 'Download bundles artifact (retry)' - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }} path: bundles diff --git a/.github/actions/get-jtreg/action.yml b/.github/actions/get-jtreg/action.yml index 3f5786b22d3..faedcc18807 100644 --- a/.github/actions/get-jtreg/action.yml +++ b/.github/actions/get-jtreg/action.yml @@ -1,5 +1,5 @@ # -# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ runs: - name: 'Check cache for JTReg' id: get-cached-jtreg - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: jtreg/installed key: jtreg-${{ steps.version.outputs.value }} @@ -56,8 +56,14 @@ runs: - name: 'Build JTReg' run: | + # If runner architecture is x64 set JAVA_HOME_17_X64 otherwise set to JAVA_HOME_17_arm64 + if [[ '${{ runner.arch }}' == 'X64' ]]; then + JDK="$JAVA_HOME_17_X64" + else + JDK="$JAVA_HOME_17_arm64" + fi # Build JTReg and move files to the proper locations - bash make/build.sh --jdk "$JAVA_HOME_17_X64" + bash make/build.sh --jdk "$JDK" mkdir ../installed mv build/images/jtreg/* ../installed working-directory: jtreg/src diff --git a/.github/actions/get-msys2/action.yml b/.github/actions/get-msys2/action.yml index d36957e3b37..82022a6e233 100644 --- a/.github/actions/get-msys2/action.yml +++ b/.github/actions/get-msys2/action.yml @@ -30,8 +30,7 @@ runs: using: composite steps: - name: 'Install MSYS2' - # use a specific release of msys2/setup-msys2 to prevent jtreg build failures on newer release - uses: msys2/setup-msys2@7efe20baefed56359985e327d329042cde2434ff + uses: msys2/setup-msys2@v2.22.0 with: install: 'autoconf tar unzip zip make' path-type: minimal diff --git a/.github/actions/upload-bundles/action.yml b/.github/actions/upload-bundles/action.yml index 6e36278eea4..a3ab7b47414 100644 --- a/.github/actions/upload-bundles/action.yml +++ b/.github/actions/upload-bundles/action.yml @@ -70,7 +70,7 @@ runs: shell: bash - name: 'Upload bundles artifact' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }} path: bundles diff --git a/.github/scripts/gen-test-summary.sh b/.github/scripts/gen-test-summary.sh index d016cb38649..a612bed5527 100644 --- a/.github/scripts/gen-test-summary.sh +++ b/.github/scripts/gen-test-summary.sh @@ -42,6 +42,7 @@ error_count=$(echo $errors | wc -w || true) if [[ "$failures" = "" && "$errors" = "" ]]; then # We know something went wrong, but not what + echo 'failure=true' >> $GITHUB_OUTPUT echo 'error-message=Unspecified test suite failure. Please see log for job for details.' >> $GITHUB_OUTPUT exit 0 fi diff --git a/.github/workflows/build-cross-compile.yml b/.github/workflows/build-cross-compile.yml index 77620640f13..dbc6a11ea66 100644 --- a/.github/workflows/build-cross-compile.yml +++ b/.github/workflows/build-cross-compile.yml @@ -120,7 +120,7 @@ jobs: - name: 'Check cache for sysroot' id: get-cached-sysroot - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: sysroot key: sysroot-${{ matrix.debian-arch }}-${{ hashFiles('./.github/workflows/build-cross-compile.yml') }} diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 3022e07b6ee..90bb6af044f 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -1,5 +1,5 @@ # -# Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,9 @@ on: platform: required: true type: string + runs-on: + required: true + type: string extra-conf-options: required: false type: string @@ -55,7 +58,7 @@ on: jobs: build-macos: name: build - runs-on: macos-13 + runs-on: ${{ inputs.runs-on }} strategy: fail-fast: false @@ -74,7 +77,7 @@ jobs: id: bootjdk uses: ./.github/actions/get-bootjdk with: - platform: macos-x64 + platform: ${{ inputs.platform }} - name: 'Get JTReg' id: jtreg @@ -87,7 +90,7 @@ jobs: - name: 'Install toolchain and dependencies' run: | # Run Homebrew installation and xcode-select - brew install make + brew install autoconf make sudo xcode-select --switch /Applications/Xcode_${{ inputs.xcode-toolset-version }}.app/Contents/Developer # This will make GNU make available as 'make' and not only as 'gmake' echo '/usr/local/opt/make/libexec/gnubin' >> $GITHUB_PATH diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0dba04e41b7..f985425f0e8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,5 +1,5 @@ # -# Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -235,6 +235,7 @@ jobs: uses: ./.github/workflows/build-macos.yml with: platform: macos-x64 + runs-on: 'macos-13' xcode-toolset-version: '14.3.1' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} @@ -246,8 +247,8 @@ jobs: uses: ./.github/workflows/build-macos.yml with: platform: macos-aarch64 + runs-on: 'macos-14' xcode-toolset-version: '14.3.1' - extra-conf-options: '--openjdk-target=aarch64-apple-darwin' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} if: needs.select.outputs.macos-aarch64 == 'true' @@ -328,6 +329,16 @@ jobs: bootjdk-platform: macos-x64 runs-on: macos-13 + test-macos-aarch64: + name: macos-aarch64 + needs: + - build-macos-aarch64 + uses: ./.github/workflows/test.yml + with: + platform: macos-aarch64 + bootjdk-platform: macos-aarch64 + runs-on: macos-14 + test-windows-x64: name: windows-x64 needs: @@ -365,7 +376,7 @@ jobs: # Hack to get hold of the api environment variables that are only defined for actions - name: 'Get API configuration' id: api - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: 'return { url: process.env["ACTIONS_RUNTIME_URL"], token: process.env["ACTIONS_RUNTIME_TOKEN"] }' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b3590166264..a8885866c12 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -63,6 +63,7 @@ jobs: - 'hs/tier1 compiler part 1' - 'hs/tier1 compiler part 2' - 'hs/tier1 compiler part 3' + - 'hs/tier1 compiler not-xcomp' - 'hs/tier1 gc' - 'hs/tier1 runtime' - 'hs/tier1 serviceability' @@ -90,13 +91,17 @@ jobs: debug-suffix: -debug - test-name: 'hs/tier1 compiler part 2' - test-suite: 'test/hotspot/jtreg/:tier1_compiler_2 test/hotspot/jtreg/:tier1_compiler_not_xcomp' + test-suite: 'test/hotspot/jtreg/:tier1_compiler_2' debug-suffix: -debug - test-name: 'hs/tier1 compiler part 3' test-suite: 'test/hotspot/jtreg/:tier1_compiler_3' debug-suffix: -debug + - test-name: 'hs/tier1 compiler not-xcomp' + test-suite: 'test/hotspot/jtreg/:tier1_compiler_not_xcomp' + debug-suffix: -debug + - test-name: 'hs/tier1 gc' test-suite: 'test/hotspot/jtreg/:tier1_gc' debug-suffix: -debug @@ -206,7 +211,7 @@ jobs: if: always() - name: 'Upload test results' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: results name: ${{ steps.package.outputs.artifact-name }} @@ -214,7 +219,7 @@ jobs: # This is the best way I found to abort the job with an error message - name: 'Notify about test failures' - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: core.setFailed('${{ steps.run-tests.outputs.error-message }}') if: steps.run-tests.outputs.failure == 'true' diff --git a/.jcheck/conf b/.jcheck/conf index 18228df5dfe..b374bde90a5 100644 --- a/.jcheck/conf +++ b/.jcheck/conf @@ -15,7 +15,7 @@ version=0 domain=openjdk.org [checks "whitespace"] -files=.*\.cpp|.*\.hpp|.*\.c|.*\.h|.*\.java|.*\.cc|.*\.hh|.*\.m|.*\.mm|.*\.md|.*\.gmk|.*\.m4|.*\.ac|Makefile +files=.*\.cpp|.*\.hpp|.*\.c|.*\.h|.*\.java|.*\.cc|.*\.hh|.*\.m|.*\.mm|.*\.md|.*\.properties|.*\.gmk|.*\.m4|.*\.ac|Makefile ignore-tabs=.*\.gmk|Makefile [checks "merge"] diff --git a/doc/building.html b/doc/building.html index 7fd530e9dbc..8a0acada254 100644 --- a/doc/building.html +++ b/doc/building.html @@ -92,6 +92,8 @@

Building the JDK

  • Autoconf
  • GNU Make
  • GNU Bash
  • +
  • Graphviz +and Pandoc
  • Running Configure @@ -524,7 +526,7 @@

    Linux

    The basic tooling is provided as part of the core operating system, but you will most likely need to install developer packages.

    For apt-based distributions (Debian, Ubuntu, etc), try this:

    -
    sudo apt-get install build-essential
    +
    sudo apt-get install build-essential autoconf

    For rpm-based distributions (Fedora, Red Hat, etc), try this:

    sudo yum groupinstall "Development Tools"

    For Alpine Linux, aside from basic tooling, install the GNU versions @@ -862,6 +864,13 @@

    GNU Bash

    href="https://www.gnu.org/software/bash">GNU Bash. No other shells are supported.

    At least version 3.2 of GNU Bash must be used.

    +

    Graphviz and Pandoc

    +

    In order to build the full docs (see the +--enable-full-docs configure option) Graphviz and Pandoc are required. Any recent versions +should work. For reference, and subject to change, Oracle builds use +Graphviz 9.0.0 and Pandoc 2.19.2.

    Running Configure

    To build the JDK, you need a "configuration", which consists of a directory where to store the build output, coupled with information @@ -2157,15 +2166,26 @@

    Using Multiple configure from there, e.g. mkdir build/<name> && cd build/<name> && bash ../../configure.

    Then you can build that configuration using -make CONF_NAME=<name> or -make CONF=<pattern>, where -<pattern> is a substring matching one or several -configurations, e.g. CONF=debug. The special empty pattern -(CONF=) will match all available configuration, so -make CONF= hotspot will build the hotspot -target for all configurations. Alternatively, you can execute -make in the configuration directory, e.g. -cd build/<name> && make.

    +make CONF=<selector>, where +<selector> is interpreted as follows:

    + +

    A more specialized version, CONF_NAME=<name> also +exists, which will only match if the given <name> +exactly matches a single configuration.

    +

    Alternatively, you can execute make in the configuration +directory, e.g. cd build/<name> && make.

    +

    make CONF_NAME=<name> or

    Handling Reconfigurations

    If you update the repository and part of the configure script has changed, the build system will force you to re-run diff --git a/doc/building.md b/doc/building.md index de410439446..ed8a0669355 100644 --- a/doc/building.md +++ b/doc/building.md @@ -349,7 +349,7 @@ will most likely need to install developer packages. For apt-based distributions (Debian, Ubuntu, etc), try this: ``` -sudo apt-get install build-essential +sudo apt-get install build-essential autoconf ``` For rpm-based distributions (Fedora, Red Hat, etc), try this: @@ -685,6 +685,14 @@ shells are supported. At least version 3.2 of GNU Bash must be used. +### Graphviz and Pandoc + +In order to build the full docs (see the `--enable-full-docs` +configure option) [Graphviz](https://www.graphviz.org) and +[Pandoc](https://pandoc.org) are required. Any recent versions should +work. For reference, and subject to change, Oracle builds use Graphviz +9.0.0 and Pandoc 2.19.2. + ## Running Configure To build the JDK, you need a "configuration", which consists of a directory @@ -1944,12 +1952,25 @@ configuration with the name ``. Alternatively, you can create a directory under `build` and run `configure` from there, e.g. `mkdir build/ && cd build/ && bash ../../configure`. -Then you can build that configuration using `make CONF_NAME=` or `make -CONF=`, where `` is a substring matching one or several -configurations, e.g. `CONF=debug`. The special empty pattern (`CONF=`) will -match *all* available configuration, so `make CONF= hotspot` will build the -`hotspot` target for all configurations. Alternatively, you can execute `make` -in the configuration directory, e.g. `cd build/ && make`. +Then you can build that configuration using `make CONF=`, where +`` is interpreted as follows: + +* If `` exacly matches the name of a configuration, this and only + this configuration will be selected. +* If `` matches (i.e. is a substring of) the names of several + configurations, then all these configurations will be selected. +* If `` is empty (i.e. `CONF=`), then all configurations will be + selected. +* If `` begins with `!`, then all configurations **not** matching the + string following `!` will be selected. + +A more specialized version, `CONF_NAME=` also exists, which will only +match if the given `` exactly matches a single configuration. + +Alternatively, you can execute `make` in the configuration directory, e.g. `cd +build/ && make`. + +`make CONF_NAME=` or ### Handling Reconfigurations diff --git a/make/Docs.gmk b/make/Docs.gmk index 5f9ec99fcae..d0c01f0283d 100644 --- a/make/Docs.gmk +++ b/make/Docs.gmk @@ -139,11 +139,6 @@ ifeq ($(IS_DRAFT), true) endif DRAFT_TEXT := This specification is not final and is subject to change. \ Use is subject to license terms. - - # Workaround stylesheet bug - HEADER_STYLE := style="margin-top: 9px;" -else - HEADER_STYLE := style="margin-top: 14px;" endif # $1 - Relative prefix to COPYRIGHT_URL @@ -339,7 +334,7 @@ define SetupApiDocsGenerationBody $1_DOC_TITLE := $$($1_LONG_NAME)
    Version $$(VERSION_SPECIFICATION) API \ Specification $1_WINDOW_TITLE := $$(subst &,&,$$($1_SHORT_NAME))$$(DRAFT_MARKER_TITLE) - $1_HEADER_TITLE :=

    $$($1_SHORT_NAME) \ + $1_HEADER_TITLE :=
    $$($1_SHORT_NAME) \ $$(DRAFT_MARKER_STR)
    ifneq ($$($1_OTHER_VERSIONS), ) $1_JAVADOC_BOTTOM := $$(call JAVADOC_BOTTOM, Other versions.) @@ -647,7 +642,7 @@ ifeq ($(ENABLE_PANDOC), true) GLOBAL_SPECS_DEFAULT_CSS_FILE := $(DOCS_OUTPUTDIR)/resources/jdk-default.css # Unset the following to suppress the link to the tool guides NAV_LINK_GUIDES := --nav-link-guides - HEADER_RIGHT_SIDE_INFO := $(subst &,&,$(JDK_SHORT_NAME))$(DRAFT_MARKER_STR) + HEADER_RIGHT_SIDE_INFO := $(subst &,&,$(JDK_SHORT_NAME))$(DRAFT_MARKER_STR) $(foreach m, $(ALL_MODULES), \ $(eval SPECS_$m := $(call FindModuleSpecsDirs, $m)) \ diff --git a/make/Global.gmk b/make/Global.gmk index e5e76b475b9..1df6c5fb6bc 100644 --- a/make/Global.gmk +++ b/make/Global.gmk @@ -87,10 +87,9 @@ help: $(info $(_) # (gensrc, java, copy, libs, launchers, gendata)) $(info ) $(info Make control variables) - $(info $(_) CONF= # Build all configurations (note, assignment is empty)) - $(info $(_) CONF= # Build the configuration(s) with a name matching) - $(info $(_) # ) - $(info $(_) CONF_NAME= # Build the configuration with exactly the ) + $(info $(_) CONF= # Select which configuration(s) to build) + $(info $(_) CONF= # Select all configurations (note, assignment is empty)) + $(info $(_) CONF_NAME= # Select the configuration with the name ) $(info $(_) SPEC= # Build the configuration given by the spec file) $(info $(_) LOG= # Change the log level from warn to ) $(info $(_) # Available log levels are:) diff --git a/make/InitSupport.gmk b/make/InitSupport.gmk index 31c80e2f726..9ea01d375ce 100644 --- a/make/InitSupport.gmk +++ b/make/InitSupport.gmk @@ -202,8 +202,14 @@ ifeq ($(HAS_SPEC),) matching_confs := $$(strip $$(all_confs)) else # Otherwise select those that contain the given CONF string - matching_confs := $$(strip $$(foreach var, $$(all_confs), \ - $$(if $$(findstring $$(CONF), $$(var)), $$(var)))) + ifeq ($$(patsubst !%,,$$(CONF)),) + # A CONF starting with ! means we should negate the search term + matching_confs := $$(strip $$(foreach var, $$(all_confs), \ + $$(if $$(findstring $$(subst !,,$$(CONF)), $$(var)), ,$$(var)))) + else + matching_confs := $$(strip $$(foreach var, $$(all_confs), \ + $$(if $$(findstring $$(CONF), $$(var)), $$(var)))) + endif ifneq ($$(filter $$(CONF), $$(matching_confs)), ) # If we found an exact match, use that matching_confs := $$(CONF) diff --git a/make/Main.gmk b/make/Main.gmk index 5534a68f13b..b0b7565c138 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -969,20 +969,28 @@ else jdk.jdeps-gendata: java - # The ct.sym generation uses all the moduleinfos as input - jdk.compiler-gendata: $(GENSRC_MODULEINFO_TARGETS) $(JAVA_TARGETS) - # jdk.compiler-gendata needs the BUILD_JDK. If the BUILD_JDK was supplied - # externally, no extra prerequisites are needed. + # jdk.compiler gendata generates ct.sym, which requires all generated + # java source and compiled classes present. + jdk.compiler-gendata: $(JAVA_TARGETS) + + # jdk.javadoc gendata generates element-list, which requires all java sources + # but not compiled classes. + jdk.javadoc-gendata: $(GENSRC_TARGETS) + + # ct.sym and element-list generation also needs the BUILD_JDK. If the + # BUILD_JDK was supplied externally, no extra prerequisites are needed. ifeq ($(CREATE_BUILDJDK), true) ifneq ($(CREATING_BUILDJDK), true) # When cross compiling and an external BUILD_JDK wasn't supplied, it's # produced by the create-buildjdk target. jdk.compiler-gendata: create-buildjdk + jdk.javadoc-gendata: create-buildjdk endif else ifeq ($(EXTERNAL_BUILDJDK), false) # When not cross compiling, the BUILD_JDK is the interim jdk image, and # the javac launcher is needed. jdk.compiler-gendata: jdk.compiler-launchers + jdk.javadoc-gendata: jdk.compiler-launchers endif # Declare dependencies between jmod targets. diff --git a/make/autoconf/basic.m4 b/make/autoconf/basic.m4 index 5a1fbc07952..91d7a550108 100644 --- a/make/autoconf/basic.m4 +++ b/make/autoconf/basic.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -123,6 +123,22 @@ AC_DEFUN_ONCE([BASIC_SETUP_BUILD_ENV], ] ) AC_SUBST(BUILD_ENV) + + if test "x$LOCALE" != x; then + # Check if we actually have C.UTF-8; if so, use it + if $LOCALE -a | $GREP -q -E "^C\.(utf8|UTF-8)$"; then + LOCALE_USED=C.UTF-8 + else + AC_MSG_WARN([C.UTF-8 locale not found, using C locale]) + LOCALE_USED=C + fi + else + AC_MSG_WARN([locale command not not found, using C locale]) + LOCALE_USED=C + fi + + export LC_ALL=$LOCALE_USED + AC_SUBST(LOCALE_USED) ]) ############################################################################### diff --git a/make/autoconf/basic_tools.m4 b/make/autoconf/basic_tools.m4 index f9ecbab7ac0..0c084561f2e 100644 --- a/make/autoconf/basic_tools.m4 +++ b/make/autoconf/basic_tools.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_FUNDAMENTAL_TOOLS], UTIL_REQUIRE_SPECIAL(SED, [AC_PROG_SED]) # Tools only needed on some platforms + UTIL_LOOKUP_PROGS(LOCALE, locale) UTIL_LOOKUP_PROGS(PATHTOOL, cygpath wslpath) UTIL_LOOKUP_PROGS(CMD, cmd.exe, $PATH:/cygdrive/c/windows/system32:/mnt/c/windows/system32:/c/windows/system32) ]) diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index df44f7a2d59..e95f32f4f7d 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -117,6 +117,11 @@ AC_DEFUN([FLAGS_SETUP_DEBUG_SYMBOLS], FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${DEBUG_PREFIX_CFLAGS}], IF_FALSE: [ DEBUG_PREFIX_CFLAGS= + ], + IF_TRUE: [ + # Add debug prefix map gcc system include paths, as they cause + # non-deterministic debug paths depending on gcc path location. + DEBUG_PREFIX_MAP_GCC_INCLUDE_PATHS ] ) fi @@ -158,6 +163,55 @@ AC_DEFUN([FLAGS_SETUP_DEBUG_SYMBOLS], AC_SUBST(ASFLAGS_DEBUG_SYMBOLS) ]) +# gcc will embed the full system include paths in the debug info +# resulting in non-deterministic debug symbol files and thus +# non-reproducible native libraries if gcc includes are located +# in different paths. +# Add -fdebug-prefix-map'ings for root and gcc include paths, +# pointing to a common set of folders so that the binaries are deterministic: +# root include : /usr/include +# gcc include : /usr/local/gcc_include +# g++ include : /usr/local/gxx_include +AC_DEFUN([DEBUG_PREFIX_MAP_GCC_INCLUDE_PATHS], +[ + # Determine gcc system include paths. + # Assume default roots to start with: + GCC_ROOT_INCLUDE="/usr/include" + + # Determine is sysroot or devkit specified? + if test "x$SYSROOT" != "x"; then + GCC_ROOT_INCLUDE="${SYSROOT%/}/usr/include" + fi + + # Add root include mapping => /usr/include + GCC_INCLUDE_DEBUG_MAP_FLAGS="-fdebug-prefix-map=${GCC_ROOT_INCLUDE}/=/usr/include/" + + # Add gcc system include mapping => /usr/local/gcc_include + # Find location of stddef.h using build C compiler + GCC_SYSTEM_INCLUDE=`$ECHO "#include " | \ + $CC $CFLAGS -v -E - 2>&1 | \ + $GREP stddef | $TAIL -1 | $TR -s " " | $CUT -d'"' -f2` + if test "x$GCC_SYSTEM_INCLUDE" != "x"; then + GCC_SYSTEM_INCLUDE=`$DIRNAME $GCC_SYSTEM_INCLUDE` + GCC_INCLUDE_DEBUG_MAP_FLAGS="$GCC_INCLUDE_DEBUG_MAP_FLAGS \ + -fdebug-prefix-map=${GCC_SYSTEM_INCLUDE}/=/usr/local/gcc_include/" + fi + + # Add g++ system include mapping => /usr/local/gxx_include + # Find location of cstddef using build C++ compiler + GXX_SYSTEM_INCLUDE=`$ECHO "#include " | \ + $CXX $CXXFLAGS -v -E -x c++ - 2>&1 | \ + $GREP cstddef | $TAIL -1 | $TR -s " " | $CUT -d'"' -f2` + if test "x$GXX_SYSTEM_INCLUDE" != "x"; then + GXX_SYSTEM_INCLUDE=`$DIRNAME $GXX_SYSTEM_INCLUDE` + GCC_INCLUDE_DEBUG_MAP_FLAGS="$GCC_INCLUDE_DEBUG_MAP_FLAGS \ + -fdebug-prefix-map=${GXX_SYSTEM_INCLUDE}/=/usr/local/gxx_include/" + fi + + # Add to debug prefix cflags + DEBUG_PREFIX_CFLAGS="$DEBUG_PREFIX_CFLAGS $GCC_INCLUDE_DEBUG_MAP_FLAGS" +]) + AC_DEFUN([FLAGS_SETUP_WARNINGS], [ # Set default value. @@ -425,13 +479,14 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], [ #### OS DEFINES, these should be independent on toolchain if test "x$OPENJDK_TARGET_OS" = xlinux; then - CFLAGS_OS_DEF_JVM="-DLINUX" - CFLAGS_OS_DEF_JDK="-D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE" + CFLAGS_OS_DEF_JVM="-DLINUX -D_FILE_OFFSET_BITS=64" + CFLAGS_OS_DEF_JDK="-D_GNU_SOURCE -D_REENTRANT -D_FILE_OFFSET_BITS=64" elif test "x$OPENJDK_TARGET_OS" = xmacosx; then CFLAGS_OS_DEF_JVM="-D_ALLBSD_SOURCE -D_DARWIN_C_SOURCE -D_XOPEN_SOURCE" CFLAGS_OS_DEF_JDK="-D_ALLBSD_SOURCE -D_DARWIN_UNLIMITED_SELECT" elif test "x$OPENJDK_TARGET_OS" = xaix; then - CFLAGS_OS_DEF_JVM="-DAIX" + CFLAGS_OS_DEF_JVM="-DAIX -D_LARGE_FILES" + CFLAGS_OS_DEF_JDK="-D_LARGE_FILES" elif test "x$OPENJDK_TARGET_OS" = xbsd; then CFLAGS_OS_DEF_JDK="-D_ALLBSD_SOURCE" elif test "x$OPENJDK_TARGET_OS" = xwindows; then @@ -489,7 +544,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], ALWAYS_DEFINES_JVM="-D_GNU_SOURCE" elif test "x$TOOLCHAIN_TYPE" = xxlc; then ALWAYS_DEFINES_JVM="-D_REENTRANT" - ALWAYS_DEFINES_JDK="-D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE -DSTDC" + ALWAYS_DEFINES_JDK="-D_GNU_SOURCE -D_REENTRANT -DSTDC" elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then # Access APIs for Windows 8 and above # see https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt?view=msvc-170 diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template index fc9fbb3b912..325e8a0eaca 100644 --- a/make/autoconf/spec.gmk.template +++ b/make/autoconf/spec.gmk.template @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -56,8 +56,8 @@ COMMA := , # What make to use for main processing, after bootstrapping top-level Makefile. MAKE := @MAKE@ -# Make sure all shell commands are executed with the C locale -export LC_ALL := C +# Make sure all shell commands are executed with a proper locale +export LC_ALL := @LOCALE_USED@ # Make sure we override any local CLASSPATH variable export CLASSPATH := @CLASSPATH@ diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf index 05c6db9b032..77daeb8c6e1 100644 --- a/make/conf/github-actions.conf +++ b/make/conf/github-actions.conf @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -29,13 +29,17 @@ GTEST_VERSION=1.14.0 JTREG_VERSION=7.3.1+1 LINUX_X64_BOOT_JDK_EXT=tar.gz -LINUX_X64_BOOT_JDK_URL=https://github.com/SAP/SapMachine/releases/download/sapmachine-21.0.1/sapmachine-jdk-21.0.1_linux-x64_bin.tar.gz -LINUX_X64_BOOT_JDK_SHA256=450426abc41695696c49c02df437882e6763344522c70a46ae6b0b682ba370ff +LINUX_X64_BOOT_JDK_URL=https://github.com/SAP/SapMachine/releases/download/sapmachine-21.0.2/sapmachine-jdk-21.0.2_linux-x64_bin.tar.gz +LINUX_X64_BOOT_JDK_SHA256=3123189ec5b99eed78de0328e2fd49d7c13cc7d4524c341f1fe8fbd5165be31f MACOS_X64_BOOT_JDK_EXT=tar.gz -MACOS_X64_BOOT_JDK_URL=https://github.com/SAP/SapMachine/releases/download/sapmachine-21.0.1/sapmachine-jdk-21.0.1_macos-x64_bin.tar.gz -MACOS_X64_BOOT_JDK_SHA256=498bdb5635be4b784ccfe12f83dc4c83f6a5fb2f37666a4fec408a2fd4083afa +MACOS_X64_BOOT_JDK_URL=https://github.com/SAP/SapMachine/releases/download/sapmachine-21.0.2/sapmachine-jdk-21.0.2_macos-x64_bin.tar.gz +MACOS_X64_BOOT_JDK_SHA256=826fb6c8c5b4c24a1150ad3e393114a8be9072b9f9a65bc10ec8343971eb48fc + +MACOS_AARCH64_BOOT_JDK_EXT=tar.gz +MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk21/fd2272bbf8e04c3dbaee13770090416c/35/GPL/openjdk-21_macos-aarch64_bin.tar.gz +MACOS_AARCH64_BOOT_JDK_SHA256=f12e1e0a2dffc847951598f597c8ee60fb0913932f24b2b09c62cfd2f0f4dfb9 WINDOWS_X64_BOOT_JDK_EXT=zip -WINDOWS_X64_BOOT_JDK_URL=https://github.com/SAP/SapMachine/releases/download/sapmachine-21.0.1/sapmachine-jdk-21.0.1_windows-x64_bin.zip -WINDOWS_X64_BOOT_JDK_SHA256=d200fc7b4e5c13293caf992aef3207dd627917353c3f189901e4d95fe23bdea5 +WINDOWS_X64_BOOT_JDK_URL=https://github.com/SAP/SapMachine/releases/download/sapmachine-21.0.2/sapmachine-jdk-21.0.2_windows-x64_bin.zip +WINDOWS_X64_BOOT_JDK_SHA256=8b2bc8007381240728ca50a23f020a3603ca84314308df707d4b3eff5b3bcfd5 diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index d8bca355121..af164624877 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -441,7 +441,7 @@ var getJibProfilesProfiles = function (input, common, data) { "macosx-x64": { target_os: "macosx", target_cpu: "x64", - dependencies: ["devkit", "gtest", "pandoc"], + dependencies: ["devkit", "gtest", "graphviz", "pandoc"], configure_args: concat(common.configure_args_64bit, "--with-zlib=system", "--with-macosx-version-max=11.00.00", "--enable-compatible-cds-alignment", @@ -453,7 +453,7 @@ var getJibProfilesProfiles = function (input, common, data) { "macosx-aarch64": { target_os: "macosx", target_cpu: "aarch64", - dependencies: ["devkit", "gtest", "pandoc"], + dependencies: ["devkit", "gtest", "graphviz", "pandoc"], configure_args: concat(common.configure_args_64bit, "--with-macosx-version-max=11.00.00"), }, @@ -486,7 +486,7 @@ var getJibProfilesProfiles = function (input, common, data) { "linux-aarch64": { target_os: "linux", target_cpu: "aarch64", - dependencies: ["devkit", "gtest", "build_devkit", "pandoc"], + dependencies: ["devkit", "gtest", "build_devkit", "graphviz", "pandoc"], configure_args: [ "--with-zlib=system", "--disable-dtrace", @@ -1181,12 +1181,6 @@ var getJibProfilesDependencies = function (input, common) { revision: (input.build_cpu == "x64" ? "Xcode11.3.1-MacOSX10.15+1.2" : devkit_platform_revisions[devkit_platform]) }, - cups: { - organization: common.organization, - ext: "tar.gz", - revision: "1.0118+1.0" - }, - jtreg: { server: "jpg", product: "jtreg", @@ -1237,7 +1231,7 @@ var getJibProfilesDependencies = function (input, common) { graphviz: { organization: common.organization, ext: "tar.gz", - revision: "2.38.0-1+1.1", + revision: "9.0.0+1.0", module: "graphviz-" + input.target_platform, configure_args: "DOT=" + input.get("graphviz", "install_path") + "/dot", environment_path: input.get("graphviz", "install_path") diff --git a/make/devkit/createGraphvizBundle.sh b/make/devkit/createGraphvizBundle.sh index 290e68c382c..1b890838761 100644 --- a/make/devkit/createGraphvizBundle.sh +++ b/make/devkit/createGraphvizBundle.sh @@ -1,6 +1,6 @@ -#!/bin/bash -e +#!/bin/bash # -# Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -26,38 +26,106 @@ # Create a bundle in the current directory, containing what's needed to run # the 'dot' program from the graphviz suite by the OpenJDK build. -TMPDIR=`mktemp -d -t graphvizbundle-XXXX` -trap "rm -rf \"$TMPDIR\"" EXIT - -ORIG_DIR=`pwd` -cd "$TMPDIR" -GRAPHVIZ_VERSION=2.38.0-1 -PACKAGE_VERSION=1.1 -TARGET_PLATFORM=linux_x64 -BUNDLE_NAME=graphviz-$TARGET_PLATFORM-$GRAPHVIZ_VERSION+$PACKAGE_VERSION.tar.gz -wget http://www.graphviz.org/pub/graphviz/stable/redhat/el6/x86_64/os/graphviz-$GRAPHVIZ_VERSION.el6.x86_64.rpm -wget http://www.graphviz.org/pub/graphviz/stable/redhat/el6/x86_64/os/graphviz-libs-$GRAPHVIZ_VERSION.el6.x86_64.rpm -wget http://www.graphviz.org/pub/graphviz/stable/redhat/el6/x86_64/os/graphviz-plugins-core-$GRAPHVIZ_VERSION.el6.x86_64.rpm -wget http://www.graphviz.org/pub/graphviz/stable/redhat/el6/x86_64/os/graphviz-plugins-x-$GRAPHVIZ_VERSION.el6.x86_64.rpm -wget http://public-yum.oracle.com/repo/OracleLinux/OL6/latest/x86_64/getPackage/libtool-ltdl-2.2.6-15.5.el6.x86_64.rpm - -mkdir graphviz -cd graphviz -for rpm in ../*.rpm; do - rpm2cpio $rpm | cpio --extract --make-directories -done - -cat > dot << EOF +set -eux + +mydir="$(cd -- $(dirname ${BASH_SOURCE[0]}) && pwd)" +me="${mydir}/$(basename ${BASH_SOURCE[0]})" + +EXPAT_VERSION="2.6.0" +EXPAT_URL="https://github.com/libexpat/libexpat/releases/download/R_${EXPAT_VERSION//./_}/expat-${EXPAT_VERSION}.tar.gz" +EXPAT_SHA256="a13447b9aa67d7c860783fdf6820f33ebdea996900d6d8bbc50a628f55f099f7" + +GRAPHVIZ_VERSION="9.0.0" +GRAPHVIZ_URL="https://gitlab.com/api/v4/projects/4207231/packages/generic/graphviz-releases/${GRAPHVIZ_VERSION}/graphviz-${GRAPHVIZ_VERSION}.tar.xz" +GRAPHVIZ_SHA256="6c9afda06a732af7658c2619ee713d2545818c3ff19b7b8fd48effcd06d57bf6" + +uname_s="$(uname -s)" +case ${uname_s} in + Linux) + bundle_os="linux" + shacmd="sha256sum --strict --check -" + lib_path_var="LD_LIBRARY_PATH" + ;; + Darwin) + bundle_os="macosx" + shacmd="shasum -a 256 --strict --check -" + lib_path_var="DYLD_LIBRARY_PATH" + ;; + *) + echo "Unknown OS: ${uname_s}" + exit 1 + ;; +esac +uname_m="$(uname -m)" +case ${uname_m} in + aarch64|arm64) + bundle_cpu="aarch64" + ;; + x86_64) + bundle_cpu="x64" + ;; +esac +bundle_platform="${bundle_os}_${bundle_cpu}" + +build_dir="${mydir}/../../build/graphviz" +download_dir="${build_dir}/download" +install_dir="${build_dir}/result/graphviz-${bundle_platform}-${GRAPHVIZ_VERSION}" +bundle_file="${install_dir}.tar.gz" + +expat_dir="${build_dir}/expat" +expat_src_dir="${expat_dir}/src" + +graphviz_dir="${build_dir}/graphviz" +graphviz_src_dir="${graphviz_dir}/src" +graphviz_doc_dir="${install_dir}/doc" + +mkdir -p "${build_dir}" +cd "${build_dir}" + +download_and_unpack() { + local url="$1" + local sha256="$2" + local file="$3" + local dir="$4" + + mkdir -p "$(dirname "${file}")" + if [ ! -f "${file}" ]; then + curl -L -o "${file}" "${url}" + fi + echo "${sha256} ${file}" | ${shacmd} + if [ ! -d "${dir}" ]; then + mkdir -p "${dir}" + tar --extract --file "${file}" --directory "${dir}" --strip-components 1 + fi +} + +download_and_unpack "${EXPAT_URL}" "${EXPAT_SHA256}" "${download_dir}/expat.tar.gz" "${expat_src_dir}" +download_and_unpack "${GRAPHVIZ_URL}" "${GRAPHVIZ_SHA256}" "${download_dir}/graphviz.tar.gz" "${graphviz_src_dir}" + +( + cd "${expat_src_dir}" + ./configure --prefix="${install_dir}" + make -j install +) + +( + cd "${graphviz_src_dir}" + ./configure --prefix="${install_dir}" EXPAT_CFLAGS="-I${install_dir}/include" EXPAT_LIBS="-L${install_dir}/lib -lexpat" + make -j install +) + +cat > "${install_dir}/dot" << EOF #!/bin/bash # Get an absolute path to this script -this_script_dir=\`dirname \$0\` -this_script_dir=\`cd \$this_script_dir > /dev/null && pwd\` -export LD_LIBRARY_PATH="\$this_script_dir/usr/lib64:\$LD_LIBRARY_PATH" -exec \$this_script_dir/usr/bin/dot "\$@" +this_script_dir="\$(dirname \$0)" +this_script_dir="\$(cd \${this_script_dir} > /dev/null && pwd)" +export ${lib_path_var}="\${this_script_dir}/lib:\${this_script_dir}/lib/graphviz" +exec "\${this_script_dir}/bin/dot" "\$@" EOF -chmod +x dot -export LD_LIBRARY_PATH="$TMPDIR/graphviz/usr/lib64:$LD_LIBRARY_PATH" +chmod +x "${install_dir}/dot" # create config file -./dot -c -tar -cvzf ../$BUNDLE_NAME * -cp ../$BUNDLE_NAME "$ORIG_DIR" +"${install_dir}/dot" -c + +cp "${me}" "${install_dir}" + +tar --create --gzip --file "${bundle_file}" -C "${install_dir}" . diff --git a/make/hotspot/gensrc/GensrcAdlc.gmk b/make/hotspot/gensrc/GensrcAdlc.gmk index 0898d91e1c2..bb356476847 100644 --- a/make/hotspot/gensrc/GensrcAdlc.gmk +++ b/make/hotspot/gensrc/GensrcAdlc.gmk @@ -51,7 +51,7 @@ ifeq ($(call check-jvm-feature, compiler2), true) endif # Set the C++ standard - ADLC_CFLAGS += $(ADLC_LANGSTD_CXXFLAG) + ADLC_CFLAGS += $(ADLC_LANGSTD_CXXFLAGS) # NOTE: The old build didn't set -DASSERT for windows but it doesn't seem to # hurt. diff --git a/make/hotspot/lib/JvmOverrideFiles.gmk b/make/hotspot/lib/JvmOverrideFiles.gmk index b50d6f8bb36..ffb98b9bb9a 100644 --- a/make/hotspot/lib/JvmOverrideFiles.gmk +++ b/make/hotspot/lib/JvmOverrideFiles.gmk @@ -48,9 +48,6 @@ ifneq ($(FDLIBM_CFLAGS), ) endif ifeq ($(call isTargetOs, linux), true) - BUILD_LIBJVM_ostream.cpp_CXXFLAGS := -D_FILE_OFFSET_BITS=64 - BUILD_LIBJVM_logFileOutput.cpp_CXXFLAGS := -D_FILE_OFFSET_BITS=64 - BUILD_LIBJVM_sharedRuntimeTrig.cpp_CXXFLAGS := -DNO_PCH $(FDLIBM_CFLAGS) $(LIBJVM_FDLIBM_COPY_OPT_FLAG) BUILD_LIBJVM_sharedRuntimeTrans.cpp_CXXFLAGS := -DNO_PCH $(FDLIBM_CFLAGS) $(LIBJVM_FDLIBM_COPY_OPT_FLAG) diff --git a/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java b/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java index d24aee5eee8..921eaeee764 100644 --- a/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java +++ b/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.net.InetAddress; +import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; import java.time.LocalDateTime; import java.time.ZoneId; @@ -132,6 +133,8 @@ public static void main(String ... args) throws Throwable { String oldDate = String.format("%s%n", DateFormat.getDateInstance(DateFormat.DEFAULT, Locale.ROOT) .format(new Date())); + StandardCharsets.US_ASCII.encode(""); + StandardCharsets.UTF_8.encode(""); // A selection of trivial and common reflection operations var instance = HelloClasslist.class.getConstructor().newInstance(); diff --git a/make/modules/java.base/Java.gmk b/make/modules/java.base/Java.gmk index 8621ff945cc..5820c280fe9 100644 --- a/make/modules/java.base/Java.gmk +++ b/make/modules/java.base/Java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,11 @@ # questions. # -DISABLED_WARNINGS_java += this-escape restricted +# The base module should be built with all warnings enabled. When a +# new warning is added to javac, it can be temporarily added to the +# disabled warnings list. +# +# DISABLED_WARNINGS_java += DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' @@ -37,7 +41,8 @@ EXCLUDE_FILES += \ EXCLUDES += java/lang/doc-files \ java/lang/classfile/snippet-files \ - java/lang/classfile/components/snippet-files + java/lang/classfile/components/snippet-files \ + java/lang/foreign/snippet-files # Exclude BreakIterator classes that are just used in compile process to generate # data files and shouldn't go in the product diff --git a/make/modules/java.compiler/Java.gmk b/make/modules/java.compiler/Java.gmk index e2d5ac264b8..04f31a9bc66 100644 --- a/make/modules/java.compiler/Java.gmk +++ b/make/modules/java.compiler/Java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,10 @@ # questions. # +# To the extent technically possible, this module should be built with +# -Werror and all lint warnings enabled. In particular, +# DISABLED_WARNINGS_java should not be augmented. + DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk index 4d5ff751981..e274005e607 100644 --- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk +++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk @@ -449,7 +449,6 @@ else LIBFREETYPE_LIBS := -lfreetype endif - # gcc_ftobjs.c := maybe-uninitialized required for GCC 7 builds. $(eval $(call SetupJdkLibrary, BUILD_LIBFREETYPE, \ NAME := freetype, \ OPTIMIZATION := HIGHEST, \ @@ -458,7 +457,6 @@ else EXTRA_HEADER_DIRS := $(BUILD_LIBFREETYPE_HEADER_DIRS), \ DISABLED_WARNINGS_microsoft := 4267 4244 4996, \ DISABLED_WARNINGS_gcc := dangling-pointer stringop-overflow, \ - DISABLED_WARNINGS_gcc_ftobjs.c := maybe-uninitialized, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ )) diff --git a/make/modules/jdk.compiler/Java.gmk b/make/modules/jdk.compiler/Java.gmk index 7e6793fc637..a2dd4f60fa6 100644 --- a/make/modules/jdk.compiler/Java.gmk +++ b/make/modules/jdk.compiler/Java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,10 @@ # questions. # +# To the extent technically possible, this module should be built with +# -Werror and all lint warnings enabled. In particular, +# DISABLED_WARNINGS_java should not be augmented. + DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:-com.sun.tools.*,-jdk.internal.*,sun.tools.serialver.resources.*' JAVAC_FLAGS += -XDstringConcat=inline diff --git a/make/modules/jdk.hotspot.agent/Lib.gmk b/make/modules/jdk.hotspot.agent/Lib.gmk index d21c969c188..ebdbfecd461 100644 --- a/make/modules/jdk.hotspot.agent/Lib.gmk +++ b/make/modules/jdk.hotspot.agent/Lib.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -27,10 +27,7 @@ include LibCommon.gmk ################################################################################ -ifeq ($(call isTargetOs, linux), true) - SA_CFLAGS := -D_FILE_OFFSET_BITS=64 - -else ifeq ($(call isTargetOs, macosx), true) +ifeq ($(call isTargetOs, macosx), true) SA_CFLAGS := -D_GNU_SOURCE -mno-omit-leaf-frame-pointer \ -mstack-alignment=16 -fPIC LIBSA_EXTRA_SRC := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.hotspot.agent diff --git a/make/modules/jdk.javadoc/Java.gmk b/make/modules/jdk.javadoc/Java.gmk index 3035864ecba..a8b1f2c1173 100644 --- a/make/modules/jdk.javadoc/Java.gmk +++ b/make/modules/jdk.javadoc/Java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,8 @@ # questions. # -DISABLED_WARNINGS_java += this-escape +# To the extent technically possible, this module should be built with +# -Werror and all lint warnings enabled. In particular, +# DISABLED_WARNINGS_java should not be augmented. COPY += .xml .css .svg .js .js.template .png .txt diff --git a/make/test/BuildMicrobenchmark.gmk b/make/test/BuildMicrobenchmark.gmk index 628f3855728..ba502a56128 100644 --- a/make/test/BuildMicrobenchmark.gmk +++ b/make/test/BuildMicrobenchmark.gmk @@ -107,6 +107,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \ --add-exports java.base/sun.invoke.util=ALL-UNNAMED \ --add-exports java.base/sun.security.util=ALL-UNNAMED \ --enable-preview \ + -XDsuppressNotes \ -processor org.openjdk.jmh.generators.BenchmarkProcessor, \ JAVA_FLAGS := \ --add-exports java.base/jdk.internal.vm=ALL-UNNAMED \ diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index f637648b227..501d9df08c1 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -1237,7 +1237,7 @@ source %{ // r27 is not allocatable when compressed oops is on and heapbase is not // zero, compressed klass pointers doesn't use r27 after JDK-8234794 - if (UseCompressedOops && (CompressedOops::ptrs_base() != NULL)) { + if (UseCompressedOops && (CompressedOops::ptrs_base() != nullptr)) { _NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg())); _NO_SPECIAL_REG_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg())); _NO_SPECIAL_PTR_REG_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg())); @@ -1581,7 +1581,7 @@ bool needs_releasing_store(const Node *n) { // assert n->is_Store(); StoreNode *st = n->as_Store(); - return st->trailing_membar() != NULL; + return st->trailing_membar() != nullptr; } // predicate controlling translation of CAS @@ -1593,9 +1593,9 @@ bool needs_acquiring_load_exclusive(const Node *n) assert(is_CAS(n->Opcode(), true), "expecting a compare and swap"); LoadStoreNode* ldst = n->as_LoadStore(); if (is_CAS(n->Opcode(), false)) { - assert(ldst->trailing_membar() != NULL, "expected trailing membar"); + assert(ldst->trailing_membar() != nullptr, "expected trailing membar"); } else { - return ldst->trailing_membar() != NULL; + return ldst->trailing_membar() != nullptr; } // so we can just return true here @@ -1734,7 +1734,7 @@ void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const { st->print("mov rscratch1, #%d\n\t", framesize - 2 * wordSize); st->print("sub sp, sp, rscratch1"); } - if (C->stub_function() == NULL && BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) { + if (C->stub_function() == nullptr && BarrierSet::barrier_set()->barrier_set_nmethod() != nullptr) { st->print("\n\t"); st->print("ldr rscratch1, [guard]\n\t"); st->print("dmb ishld\n\t"); @@ -1783,9 +1783,9 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { __ build_frame(framesize); - if (C->stub_function() == NULL) { + if (C->stub_function() == nullptr) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); - if (BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) { + if (BarrierSet::barrier_set()->barrier_set_nmethod() != nullptr) { // Dummy labels for just measuring the code size Label dummy_slow_path; Label dummy_continuation; @@ -2153,12 +2153,12 @@ void MachSpillCopyNode::format(PhaseRegAlloc *ra_, outputStream *st) const { if (!ra_) st->print("N%d = SpillCopy(N%d)", _idx, in(1)->_idx); else - implementation(NULL, ra_, false, st); + implementation(nullptr, ra_, false, st); } #endif void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - implementation(&cbuf, ra_, false, NULL); + implementation(&cbuf, ra_, false, nullptr); } uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { @@ -2205,14 +2205,14 @@ void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const { st->print_cr("# MachUEPNode"); if (UseCompressedClassPointers) { - st->print_cr("\tldrw rscratch1, j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - if (CompressedKlassPointers::shift() != 0) { - st->print_cr("\tdecode_klass_not_null rscratch1, rscratch1"); - } + st->print_cr("\tldrw rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + st->print_cr("\tldrw r10, [rscratch2 + CompiledICData::speculated_klass_offset()]\t# compressed klass"); + st->print_cr("\tcmpw rscratch1, r10"); } else { - st->print_cr("\tldr rscratch1, j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + st->print_cr("\tldr rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + st->print_cr("\tldr r10, [rscratch2 + CompiledICData::speculated_klass_offset()]\t# compressed klass"); + st->print_cr("\tcmp rscratch1, r10"); } - st->print_cr("\tcmp r0, rscratch1\t # Inline cache check"); st->print_cr("\tbne, SharedRuntime::_ic_miss_stub"); } #endif @@ -2221,14 +2221,7 @@ void MachUEPNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const { // This is the unverified entry point. C2_MacroAssembler _masm(&cbuf); - - __ cmp_klass(j_rarg0, rscratch2, rscratch1); - Label skip; - // TODO - // can we avoid this skip and still use a reloc? - __ br(Assembler::EQ, skip); - __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); - __ bind(skip); + __ ic_check(InteriorEntryAlignment); } uint MachUEPNode::size(PhaseRegAlloc* ra_) const @@ -2249,7 +2242,7 @@ int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) // That's why we must use the macroassembler to generate a handler. C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_exception_handler()); - if (base == NULL) { + if (base == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return 0; // CodeBuffer::expand failed } @@ -2267,7 +2260,7 @@ int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) // That's why we must use the macroassembler to generate a handler. C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_deopt_handler()); - if (base == NULL) { + if (base == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return 0; // CodeBuffer::expand failed } @@ -2377,7 +2370,7 @@ int Matcher::min_vector_size(const BasicType bt) { return MIN2(size, max_size); } -int Matcher::superword_max_vector_size(const BasicType bt) { +int Matcher::max_vector_size_auto_vectorization(const BasicType bt) { return Matcher::max_vector_size(bt); } @@ -2410,7 +2403,7 @@ MachOper* Matcher::pd_specialize_generic_vector_operand(MachOper* generic_opnd, case Op_VecX: return new vecXOper(); } ShouldNotReachHere(); - return NULL; + return nullptr; } bool Matcher::is_reg2reg_move(MachNode* m) { @@ -2582,8 +2575,8 @@ Assembler::Condition to_assembler_cond(BoolTest::mask cond) { } // Binary src (Replicate con) -bool is_valid_sve_arith_imm_pattern(Node* n, Node* m) { - if (n == NULL || m == NULL) { +static bool is_valid_sve_arith_imm_pattern(Node* n, Node* m) { + if (n == nullptr || m == nullptr) { return false; } @@ -2623,8 +2616,8 @@ bool is_valid_sve_arith_imm_pattern(Node* n, Node* m) { // (XorV src (Replicate m1)) // (XorVMask src (MaskAll m1)) -bool is_vector_bitwise_not_pattern(Node* n, Node* m) { - if (n != NULL && m != NULL) { +static bool is_vector_bitwise_not_pattern(Node* n, Node* m) { + if (n != nullptr && m != nullptr) { return (n->Opcode() == Op_XorV || n->Opcode() == Op_XorVMask) && VectorNode::is_all_ones_vector(m); } @@ -3430,7 +3423,7 @@ encode %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); address con = (address)$src$$constant; - if (con == NULL || con == (address)1) { + if (con == nullptr || con == (address)1) { ShouldNotReachHere(); } else { relocInfo::relocType rtype = $src->constant_reloc(); @@ -3473,7 +3466,7 @@ encode %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); address con = (address)$src$$constant; - if (con == NULL) { + if (con == nullptr) { ShouldNotReachHere(); } else { relocInfo::relocType rtype = $src->constant_reloc(); @@ -3492,7 +3485,7 @@ encode %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); address con = (address)$src$$constant; - if (con == NULL) { + if (con == nullptr) { ShouldNotReachHere(); } else { relocInfo::relocType rtype = $src->constant_reloc(); @@ -3675,7 +3668,7 @@ encode %{ Label miss; C2_MacroAssembler _masm(&cbuf); __ check_klass_subtype_slow_path(sub_reg, super_reg, temp_reg, result_reg, - NULL, &miss, + nullptr, &miss, /*set_cond_codes:*/ true); if ($primary) { __ mov(result_reg, zr); @@ -3691,7 +3684,7 @@ encode %{ if (!_method) { // A call to a runtime wrapper, e.g. new, new_typeArray_Java, uncommon_trap. call = __ trampoline_call(Address(addr, relocInfo::runtime_call_type)); - if (call == NULL) { + if (call == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -3705,7 +3698,7 @@ encode %{ RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) : static_call_Relocation::spec(method_index); call = __ trampoline_call(Address(addr, rspec)); - if (call == NULL) { + if (call == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -3715,8 +3708,8 @@ encode %{ cbuf.shared_stub_to_interp_for(_method, call - cbuf.insts_begin()); } else { // Emit stub for static call - address stub = CompiledStaticCall::emit_to_interp_stub(cbuf, call); - if (stub == NULL) { + address stub = CompiledDirectCall::emit_to_interp_stub(cbuf, call); + if (stub == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -3735,7 +3728,7 @@ encode %{ C2_MacroAssembler _masm(&cbuf); int method_index = resolved_method_index(cbuf); address call = __ ic_call((address)$meth$$method, method_index); - if (call == NULL) { + if (call == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -3764,7 +3757,7 @@ encode %{ CodeBlob *cb = CodeCache::find_blob(entry); if (cb) { address call = __ trampoline_call(Address(entry, relocInfo::runtime_call_type)); - if (call == NULL) { + if (call == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -4663,7 +4656,7 @@ operand immP() interface(CONST_INTER); %} -// NULL Pointer Immediate +// Null Pointer Immediate operand immP0() %{ predicate(n->get_ptr() == 0); @@ -4795,7 +4788,7 @@ operand immN() interface(CONST_INTER); %} -// Narrow NULL Pointer Immediate +// Narrow Null Pointer Immediate operand immN0() %{ predicate(n->get_narrowcon() == 0); @@ -7219,7 +7212,7 @@ instruct loadConP0(iRegPNoSp dst, immP0 con) match(Set dst con); ins_cost(INSN_COST); - format %{ "mov $dst, $con\t# NULL ptr" %} + format %{ "mov $dst, $con\t# null pointer" %} ins_encode(aarch64_enc_mov_p0(dst, con)); @@ -7233,7 +7226,7 @@ instruct loadConP1(iRegPNoSp dst, immP_1 con) match(Set dst con); ins_cost(INSN_COST); - format %{ "mov $dst, $con\t# NULL ptr" %} + format %{ "mov $dst, $con\t# null pointer" %} ins_encode(aarch64_enc_mov_p1(dst, con)); @@ -7275,7 +7268,7 @@ instruct loadConN0(iRegNNoSp dst, immN0 con) match(Set dst con); ins_cost(INSN_COST); - format %{ "mov $dst, $con\t# compressed NULL ptr" %} + format %{ "mov $dst, $con\t# compressed null pointer" %} ins_encode(aarch64_enc_mov_n0(dst, con)); @@ -15256,7 +15249,7 @@ instruct clearArray_reg_reg(iRegL_R11 cnt, iRegP_R10 base, Universe dummy, rFlag ins_encode %{ address tpc = __ zero_words($base$$Register, $cnt$$Register); - if (tpc == NULL) { + if (tpc == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -15277,7 +15270,7 @@ instruct clearArray_imm_reg(immL cnt, iRegP_R10 base, iRegL_R11 temp, Universe d ins_encode %{ address tpc = __ zero_words($base$$Register, (uint64_t)$cnt$$constant); - if (tpc == NULL) { + if (tpc == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -17104,23 +17097,7 @@ instruct string_equalsL(iRegP_R1 str1, iRegP_R3 str2, iRegI_R4 cnt, ins_encode %{ // Count is in 8-bit bytes; non-Compact chars are 16 bits. __ string_equals($str1$$Register, $str2$$Register, - $result$$Register, $cnt$$Register, 1); - %} - ins_pipe(pipe_class_memory); -%} - -instruct string_equalsU(iRegP_R1 str1, iRegP_R3 str2, iRegI_R4 cnt, - iRegI_R0 result, rFlagsReg cr) -%{ - predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU); - match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); - - format %{ "String Equals $str1,$str2,$cnt -> $result" %} - ins_encode %{ - // Count is in 8-bit bytes; non-Compact chars are 16 bits. - __ string_equals($str1$$Register, $str2$$Register, - $result$$Register, $cnt$$Register, 2); + $result$$Register, $cnt$$Register); %} ins_pipe(pipe_class_memory); %} @@ -17142,7 +17119,7 @@ instruct array_equalsB(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, address tpc = __ arrays_equals($ary1$$Register, $ary2$$Register, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $result$$Register, $tmp$$Register, 1); - if (tpc == NULL) { + if (tpc == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -17167,7 +17144,7 @@ instruct array_equalsC(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, address tpc = __ arrays_equals($ary1$$Register, $ary2$$Register, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $result$$Register, $tmp$$Register, 2); - if (tpc == NULL) { + if (tpc == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -17182,7 +17159,7 @@ instruct count_positives(iRegP_R1 ary1, iRegI_R2 len, iRegI_R0 result, rFlagsReg format %{ "count positives byte[] $ary1,$len -> $result" %} ins_encode %{ address tpc = __ count_positives($ary1$$Register, $len$$Register, $result$$Register); - if (tpc == NULL) { + if (tpc == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -17225,7 +17202,7 @@ instruct string_inflate(Universe dummy, iRegP_R0 src, iRegP_R1 dst, iRegI_R2 len address tpc = __ byte_array_inflate($src$$Register, $dst$$Register, $len$$Register, $vtmp0$$FloatRegister, $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, $tmp$$Register); - if (tpc == NULL) { + if (tpc == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad index 210efa0b760..d611c14f403 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector.ad +++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2020, 2023, Arm Limited. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // @@ -126,7 +126,7 @@ source %{ } } - bool Matcher::match_rule_supported_superword(int opcode, int vlen, BasicType bt) { + bool Matcher::match_rule_supported_auto_vectorization(int opcode, int vlen, BasicType bt) { if (UseSVE == 0) { // These operations are not profitable to be vectorized on NEON, because no direct // NEON instructions support them. But the match rule support for them is profitable for diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 index 3f4ed020f55..5c4e13d432f 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 @@ -1,5 +1,5 @@ // -// Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2020, 2023, Arm Limited. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // @@ -116,7 +116,7 @@ source %{ } } - bool Matcher::match_rule_supported_superword(int opcode, int vlen, BasicType bt) { + bool Matcher::match_rule_supported_auto_vectorization(int opcode, int vlen, BasicType bt) { if (UseSVE == 0) { // These operations are not profitable to be vectorized on NEON, because no direct // NEON instructions support them. But the match rule support for them is profitable for diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.cpp b/src/hotspot/cpu/aarch64/assembler_aarch64.cpp index afeb19e906e..c7b867a4207 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.cpp @@ -187,6 +187,26 @@ void Address::lea(MacroAssembler *as, Register r) const { zrf(Rd, 0); } +// This encoding is similar (but not quite identical) to the encoding used +// by literal ld/st. see JDK-8324123. +// PRFM does not support writeback or pre/post index. +void Assembler::prfm(const Address &adr, prfop pfop) { + Address::mode mode = adr.getMode(); + // PRFM does not support pre/post index + guarantee((mode != Address::pre) && (mode != Address::post), "prfm does not support pre/post indexing"); + if (mode == Address::literal) { + starti; + f(0b11, 31, 30), f(0b011, 29, 27), f(0b000, 26, 24); + f(pfop, 4, 0); + int64_t offset = (adr.target() - pc()) >> 2; + sf(offset, 23, 5); + } else { + assert((mode == Address::base_plus_offset) + || (mode == Address::base_plus_offset_reg), "must be base_plus_offset/base_plus_offset_reg"); + ld_st2(as_Register(pfop), adr, 0b11, 0b10); + } +} + // An "all-purpose" add/subtract immediate, per ARM documentation: // A "programmer-friendly" assembler may accept a negative immediate // between -(2^24 -1) and -1 inclusive, causing it to convert a diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 187c1209303..9c05c36706d 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -797,6 +797,8 @@ class Assembler : public AbstractAssembler { void adrp(Register Rd, const Address &dest, uint64_t &offset) = delete; + void prfm(const Address &adr, prfop pfop = PLDL1KEEP); + #undef INSN void add_sub_immediate(Instruction_aarch64 ¤t_insn, Register Rd, Register Rn, @@ -1574,17 +1576,6 @@ class Assembler : public AbstractAssembler { #undef INSN -#define INSN(NAME, size, op) \ - void NAME(const Address &adr, prfop pfop = PLDL1KEEP) { \ - ld_st2(as_Register(pfop), adr, size, op); \ - } - - INSN(prfm, 0b11, 0b10); // FIXME: PRFM should not be used with - // writeback modes, but the assembler - // doesn't enfore that. - -#undef INSN - #define INSN(NAME, size, op) \ void NAME(FloatRegister Rt, const Address &adr) { \ ld_st2(as_Register(Rt), adr, size, op, 1); \ diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index b83d6185062..ba613b62a3e 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -53,7 +53,6 @@ #endif NEEDS_CLEANUP // remove this definitions ? -const Register IC_Klass = rscratch2; // where the IC klass is cached const Register SYNC_header = r0; // synchronization header const Register SHIFT_count = r0; // where count for shift operations must be @@ -293,27 +292,7 @@ void LIR_Assembler::osr_entry() { // inline cache check; done before the frame is built. int LIR_Assembler::check_icache() { - Register receiver = FrameMap::receiver_opr->as_register(); - Register ic_klass = IC_Klass; - int start_offset = __ offset(); - __ inline_cache_check(receiver, ic_klass); - - // if icache check fails, then jump to runtime routine - // Note: RECEIVER must still contain the receiver! - Label dont; - __ br(Assembler::EQ, dont); - __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); - - // We align the verified entry point unless the method body - // (including its inline cache check) will fit in a single 64-byte - // icache line. - if (! method()->is_accessor() || __ offset() - start_offset > 4 * 4) { - // force alignment after the cache check. - __ align(CodeEntryAlignment); - } - - __ bind(dont); - return start_offset; + return __ ic_check(CodeEntryAlignment); } void LIR_Assembler::clinit_barrier(ciMethod* method) { @@ -2042,7 +2021,7 @@ void LIR_Assembler::emit_static_call_stub() { __ relocate(static_stub_Relocation::spec(call_pc)); __ emit_static_call_stub(); - assert(__ offset() - start + CompiledStaticCall::to_trampoline_stub_size() + assert(__ offset() - start + CompiledDirectCall::to_trampoline_stub_size() <= call_stub_size(), "stub too big"); __ end_a_stub(); } diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp index 43ec189255f..ef1b5fe2703 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp @@ -71,8 +71,8 @@ friend class ArrayCopyStub; void deoptimize_trap(CodeEmitInfo *info); enum { - // call stub: CompiledStaticCall::to_interp_stub_size() + - // CompiledStaticCall::to_trampoline_stub_size() + // call stub: CompiledDirectCall::to_interp_stub_size() + + // CompiledDirectCall::to_trampoline_stub_size() _call_stub_size = 13 * NativeInstruction::instruction_size, _exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175), _deopt_handler_size = 7 * NativeInstruction::instruction_size diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp index 952e060ed21..fd31d2dde5b 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -831,18 +831,12 @@ void LIRGenerator::do_LibmIntrinsic(Intrinsic* x) { } break; case vmIntrinsics::_dlog: - if (StubRoutines::dlog() != nullptr) { - __ call_runtime_leaf(StubRoutines::dlog(), getThreadTemp(), result_reg, cc->args()); - } else { - __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dlog), getThreadTemp(), result_reg, cc->args()); - } + // Math.log intrinsic is not implemented on AArch64 (see JDK-8210858), + // but we can still call the shared runtime. + __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dlog), getThreadTemp(), result_reg, cc->args()); break; case vmIntrinsics::_dlog10: - if (StubRoutines::dlog10() != nullptr) { - __ call_runtime_leaf(StubRoutines::dlog10(), getThreadTemp(), result_reg, cc->args()); - } else { - __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dlog10), getThreadTemp(), result_reg, cc->args()); - } + __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dlog10), getThreadTemp(), result_reg, cc->args()); break; case vmIntrinsics::_dpow: if (StubRoutines::dpow() != nullptr) { diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp index d3a746178f1..c0d1d1747ab 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp @@ -308,17 +308,6 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1, verify_oop(obj); } - -void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) { - verify_oop(receiver); - // explicit null check not needed since load from [klass_offset] causes a trap - // check against inline cache - assert(!MacroAssembler::needs_explicit_null_check(oopDesc::klass_offset_in_bytes()), "must add explicit null check"); - - cmp_klass(receiver, iCache, rscratch1); -} - - void C1_MacroAssembler::build_frame(int framesize, int bang_size_in_bytes) { assert(bang_size_in_bytes >= framesize, "stack bang size incorrect"); // Make sure there is enough stack space for this method's activation. diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp index d2f4744a049..63a32e714e3 100644 --- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp @@ -38,7 +38,6 @@ #include "interpreter/interpreter.hpp" #include "memory/universe.hpp" #include "nativeInst_aarch64.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "register_aarch64.hpp" diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index 7b9784ec47a..8910fba97a5 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, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,10 +111,10 @@ void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg, Register // Handle existing monitor. bind(object_has_monitor); - // The object's monitor m is unlocked iff m->owner == NULL, + // The object's monitor m is unlocked iff m->owner == nullptr, // otherwise m->owner may contain a thread or a stack address. // - // Try to CAS m->owner from NULL to current thread. + // Try to CAS m->owner from null to current thread. add(tmp, disp_hdr, (in_bytes(ObjectMonitor::owner_offset())-markWord::monitor_value)); cmpxchg(tmp, zr, rthread, Assembler::xword, /*acquire*/ true, /*release*/ true, /*weak*/ false, tmp3Reg); // Sets flags for result diff --git a/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp b/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp index c58ff8828bc..23c08f11d1a 100644 --- a/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp @@ -26,7 +26,6 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" #include "code/compiledIC.hpp" -#include "code/icBuffer.hpp" #include "code/nmethod.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" @@ -36,7 +35,7 @@ // ---------------------------------------------------------------------------- #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { +address CompiledDirectCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { precond(cbuf.stubs()->start() != badAddress); precond(cbuf.stubs()->end() != badAddress); @@ -71,11 +70,11 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) } #undef __ -int CompiledStaticCall::to_interp_stub_size() { +int CompiledDirectCall::to_interp_stub_size() { return MacroAssembler::static_call_stub_size(); } -int CompiledStaticCall::to_trampoline_stub_size() { +int CompiledDirectCall::to_trampoline_stub_size() { // Somewhat pessimistically, we count 3 instructions here (although // there are only two) because we sometimes emit an alignment nop. // Trampoline stubs are always word aligned. @@ -83,21 +82,14 @@ int CompiledStaticCall::to_trampoline_stub_size() { } // Relocation entries for call stub, compiled java to interpreter. -int CompiledStaticCall::reloc_to_interp_stub() { +int CompiledDirectCall::reloc_to_interp_stub() { return 4; // 3 in emit_to_interp_stub + 1 in emit_call } -void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) { +void CompiledDirectCall::set_to_interpreted(const methodHandle& callee, address entry) { address stub = find_stub(); guarantee(stub != nullptr, "stub not found"); - { - ResourceMark rm; - log_trace(inlinecache)("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s", - p2i(instruction_address()), - callee->name_and_sig_as_C_string()); - } - // Creation also verifies the object. NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + NativeInstruction::instruction_size); @@ -115,7 +107,7 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad set_destination_mt_safe(stub); } -void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) { +void CompiledDirectCall::set_stub_to_clean(static_stub_Relocation* static_stub) { // Reset stub. address stub = static_stub->addr(); assert(stub != nullptr, "stub not found"); @@ -132,7 +124,7 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_ // Non-product mode code #ifndef PRODUCT -void CompiledDirectStaticCall::verify() { +void CompiledDirectCall::verify() { // Verify call. _call->verify(); _call->verify_alignment(); diff --git a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp index d035ab21093..47b6f1f2f38 100644 --- a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. All rights reserved. - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ static char* reserve_at_eor_compatible_address(size_t size, bool aslr) { 0x7ffc, 0x7ffe, 0x7fff }; static constexpr int num_immediates = sizeof(immediates) / sizeof(immediates[0]); - const int start_index = aslr ? os::random() : 0; + const int start_index = aslr ? os::next_random((int)os::javaTimeNanos()) : 0; constexpr int max_tries = 64; for (int ntry = 0; result == nullptr && ntry < max_tries; ntry ++) { // As in os::attempt_reserve_memory_between, we alternate between higher and lower diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index c5b2ff8a4c0..8d0fa8895d1 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -678,7 +678,7 @@ static void printbc(Method *m, intptr_t bcx) { printf("%s : %s ==> %s\n", m->name_and_sig_as_C_string(), buf, name); } -void internal_pf(uintptr_t sp, uintptr_t fp, uintptr_t pc, uintptr_t bcx) { +static void internal_pf(uintptr_t sp, uintptr_t fp, uintptr_t pc, uintptr_t bcx) { if (! fp) return; diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp index b26eaa4bfcd..293cc6eb0d0 100644 --- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2019, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -117,7 +117,7 @@ define_pd_global(intx, InlineSmallCode, 1000); "Use prfm hint with specified distance in compiled code." \ "Value -1 means off.") \ range(-1, 4096) \ - product(ccstr, OnSpinWaitInst, "none", DIAGNOSTIC, \ + product(ccstr, OnSpinWaitInst, "yield", DIAGNOSTIC, \ "The instruction to use to implement " \ "java.lang.Thread.onSpinWait()." \ "Options: none, nop, isb, yield.") \ diff --git a/src/hotspot/cpu/aarch64/icBuffer_aarch64.cpp b/src/hotspot/cpu/aarch64/icBuffer_aarch64.cpp deleted file mode 100644 index bd8cfc42600..00000000000 --- a/src/hotspot/cpu/aarch64/icBuffer_aarch64.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/icBuffer.hpp" -#include "gc/shared/collectedHeap.inline.hpp" -#include "interpreter/bytecodes.hpp" -#include "memory/resourceArea.hpp" -#include "nativeInst_aarch64.hpp" -#include "oops/oop.inline.hpp" - -int InlineCacheBuffer::ic_stub_code_size() { - return (MacroAssembler::far_branches() ? 6 : 4) * NativeInstruction::instruction_size; -} - -#define __ masm-> - -void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin, void* cached_value, address entry_point) { - ResourceMark rm; - CodeBuffer code(code_begin, ic_stub_code_size()); - MacroAssembler* masm = new MacroAssembler(&code); - // note: even though the code contains an embedded value, we do not need reloc info - // because - // (1) the value is old (i.e., doesn't matter for scavenges) - // (2) these ICStubs are removed *before* a GC happens, so the roots disappear - // assert(cached_value == nullptr || cached_oop->is_perm(), "must be perm oop"); - - address start = __ pc(); - Label l; - __ ldr(rscratch2, l); - int jump_code_size = __ far_jump(ExternalAddress(entry_point)); - // IC stub code size is not expected to vary depending on target address. - // We use NOPs to make the [ldr + far_jump + nops + int64] stub size equal to ic_stub_code_size. - for (int size = NativeInstruction::instruction_size + jump_code_size + 8; - size < ic_stub_code_size(); size += NativeInstruction::instruction_size) { - __ nop(); - } - __ bind(l); - assert((uintptr_t)__ pc() % wordSize == 0, ""); - __ emit_int64((int64_t)cached_value); - // Only need to invalidate the 1st two instructions - not the whole ic stub - ICache::invalidate_range(code_begin, InlineCacheBuffer::ic_stub_code_size()); - assert(__ pc() - start == ic_stub_code_size(), "must be"); -} - -address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) { - NativeMovConstReg* move = nativeMovConstReg_at(code_begin); // creation also verifies the object - NativeJump* jump = nativeJump_at(code_begin + 4); - return jump->jump_destination(); -} - - -void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) { - // The word containing the cached value is at the end of this IC buffer - uintptr_t *p = (uintptr_t *)(code_begin + ic_stub_code_size() - wordSize); - void* o = (void*)*p; - return o; -} diff --git a/src/hotspot/cpu/aarch64/immediate_aarch64.cpp b/src/hotspot/cpu/aarch64/immediate_aarch64.cpp index 3d87fde2b5b..7caafc19fbd 100644 --- a/src/hotspot/cpu/aarch64/immediate_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/immediate_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -53,7 +53,7 @@ struct li_pair { static struct li_pair InverseLITable[LI_TABLE_SIZE]; // comparator to sort entries in the inverse table -int compare_immediate_pair(const void *i1, const void *i2) +static int compare_immediate_pair(const void *i1, const void *i2) { struct li_pair *li1 = (struct li_pair *)i1; struct li_pair *li2 = (struct li_pair *)i2; @@ -142,7 +142,7 @@ static inline uint32_t uimm(uint32_t val, int hi, int lo) // result // a bit string containing count copies of input bit string // -uint64_t replicate(uint64_t bits, int nbits, int count) +static uint64_t replicate(uint64_t bits, int nbits, int count) { assert(count > 0, "must be"); assert(nbits > 0, "must be"); @@ -231,8 +231,8 @@ uint64_t replicate(uint64_t bits, int nbits, int count) // For historical reasons the implementation of this function is much // more convoluted than is really necessary. -int expandLogicalImmediate(uint32_t immN, uint32_t immr, - uint32_t imms, uint64_t &bimm) +static int expandLogicalImmediate(uint32_t immN, uint32_t immr, + uint32_t imms, uint64_t &bimm) { int len; // ought to be <= 6 uint32_t levels; // 6 bits @@ -446,4 +446,3 @@ uint32_t encoding_for_fp_immediate(float immediate) res = (s << 7) | (r << 4) | f; return res; } - diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index a3c560b28d3..b19587ebe76 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -29,6 +29,7 @@ #include "asm/assembler.hpp" #include "asm/assembler.inline.hpp" #include "ci/ciEnv.hpp" +#include "code/compiledIC.hpp" #include "compiler/compileTask.hpp" #include "compiler/disassembler.hpp" #include "compiler/oopMap.hpp" @@ -965,7 +966,7 @@ int MacroAssembler::max_trampoline_stub_size() { } void MacroAssembler::emit_static_call_stub() { - // CompiledDirectStaticCall::set_to_interpreted knows the + // CompiledDirectCall::set_to_interpreted knows the // exact layout of this stub. isb(); @@ -995,10 +996,51 @@ address MacroAssembler::ic_call(address entry, jint method_index) { // address const_ptr = long_constant((jlong)Universe::non_oop_word()); // uintptr_t offset; // ldr_constant(rscratch2, const_ptr); - movptr(rscratch2, (uintptr_t)Universe::non_oop_word()); + movptr(rscratch2, (intptr_t)Universe::non_oop_word()); return trampoline_call(Address(entry, rh)); } +int MacroAssembler::ic_check_size() { + if (target_needs_far_branch(CAST_FROM_FN_PTR(address, SharedRuntime::get_ic_miss_stub()))) { + return NativeInstruction::instruction_size * 7; + } else { + return NativeInstruction::instruction_size * 5; + } +} + +int MacroAssembler::ic_check(int end_alignment) { + Register receiver = j_rarg0; + Register data = rscratch2; + Register tmp1 = rscratch1; + Register tmp2 = r10; + + // The UEP of a code blob ensures that the VEP is padded. However, the padding of the UEP is placed + // before the inline cache check, so we don't have to execute any nop instructions when dispatching + // through the UEP, yet we can ensure that the VEP is aligned appropriately. That's why we align + // before the inline cache check here, and not after + align(end_alignment, offset() + ic_check_size()); + + int uep_offset = offset(); + + if (UseCompressedClassPointers) { + ldrw(tmp1, Address(receiver, oopDesc::klass_offset_in_bytes())); + ldrw(tmp2, Address(data, CompiledICData::speculated_klass_offset())); + cmpw(tmp1, tmp2); + } else { + ldr(tmp1, Address(receiver, oopDesc::klass_offset_in_bytes())); + ldr(tmp2, Address(data, CompiledICData::speculated_klass_offset())); + cmp(tmp1, tmp2); + } + + Label dont; + br(Assembler::EQ, dont); + far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); + bind(dont); + assert((offset() % end_alignment) == 0, "Misaligned verified entry point"); + + return uep_offset; +} + // Implementation of call_VM versions void MacroAssembler::call_VM(Register oop_result, @@ -1100,7 +1142,14 @@ void MacroAssembler::get_vm_result_2(Register metadata_result, Register java_thr } void MacroAssembler::align(int modulus) { - while (offset() % modulus != 0) nop(); + align(modulus, offset()); +} + +// Ensure that the code at target bytes offset from the current offset() is aligned +// according to modulus. +void MacroAssembler::align(int modulus, int target) { + int delta = target - offset(); + while ((offset() + delta) % modulus != 0) nop(); } void MacroAssembler::post_call_nop() { @@ -1197,7 +1246,7 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, } // Look up the method for a megamorphic invokeinterface call in a single pass over itable: -// - check recv_klass (actual object class) is a subtype of resolved_klass from CompiledICHolder +// - check recv_klass (actual object class) is a subtype of resolved_klass from CompiledICData // - find a holder_klass (class that implements the method) vtable offset and get the method from vtable by index // The target method is determined by . // The receiver klass is in recv_klass. @@ -4258,108 +4307,117 @@ void MacroAssembler::kernel_crc32_common_fold_using_crypto_pmull(Register crc, R } add(table, table, table_offset); + // Registers v0..v7 are used as data registers. + // Registers v16..v31 are used as tmp registers. sub(buf, buf, 0x10); - ldrq(v1, Address(buf, 0x10)); - ldrq(v2, Address(buf, 0x20)); - ldrq(v3, Address(buf, 0x30)); - ldrq(v4, Address(buf, 0x40)); - ldrq(v5, Address(buf, 0x50)); - ldrq(v6, Address(buf, 0x60)); - ldrq(v7, Address(buf, 0x70)); - ldrq(v8, Address(pre(buf, 0x80))); - - movi(v25, T4S, 0); - mov(v25, S, 0, crc); - eor(v1, T16B, v1, v25); - - ldrq(v0, Address(table)); + ldrq(v0, Address(buf, 0x10)); + ldrq(v1, Address(buf, 0x20)); + ldrq(v2, Address(buf, 0x30)); + ldrq(v3, Address(buf, 0x40)); + ldrq(v4, Address(buf, 0x50)); + ldrq(v5, Address(buf, 0x60)); + ldrq(v6, Address(buf, 0x70)); + ldrq(v7, Address(pre(buf, 0x80))); + + movi(v31, T4S, 0); + mov(v31, S, 0, crc); + eor(v0, T16B, v0, v31); + + // Register v16 contains constants from the crc table. + ldrq(v16, Address(table)); b(CRC_by128_loop); align(OptoLoopAlignment); BIND(CRC_by128_loop); - pmull (v9, T1Q, v1, v0, T1D); - pmull2(v10, T1Q, v1, v0, T2D); - ldrq(v1, Address(buf, 0x10)); - eor3(v1, T16B, v9, v10, v1); - - pmull (v11, T1Q, v2, v0, T1D); - pmull2(v12, T1Q, v2, v0, T2D); - ldrq(v2, Address(buf, 0x20)); - eor3(v2, T16B, v11, v12, v2); - - pmull (v13, T1Q, v3, v0, T1D); - pmull2(v14, T1Q, v3, v0, T2D); - ldrq(v3, Address(buf, 0x30)); - eor3(v3, T16B, v13, v14, v3); - - pmull (v15, T1Q, v4, v0, T1D); - pmull2(v16, T1Q, v4, v0, T2D); - ldrq(v4, Address(buf, 0x40)); - eor3(v4, T16B, v15, v16, v4); - - pmull (v17, T1Q, v5, v0, T1D); - pmull2(v18, T1Q, v5, v0, T2D); - ldrq(v5, Address(buf, 0x50)); - eor3(v5, T16B, v17, v18, v5); - - pmull (v19, T1Q, v6, v0, T1D); - pmull2(v20, T1Q, v6, v0, T2D); - ldrq(v6, Address(buf, 0x60)); - eor3(v6, T16B, v19, v20, v6); - - pmull (v21, T1Q, v7, v0, T1D); - pmull2(v22, T1Q, v7, v0, T2D); - ldrq(v7, Address(buf, 0x70)); - eor3(v7, T16B, v21, v22, v7); - - pmull (v23, T1Q, v8, v0, T1D); - pmull2(v24, T1Q, v8, v0, T2D); - ldrq(v8, Address(pre(buf, 0x80))); - eor3(v8, T16B, v23, v24, v8); + pmull (v17, T1Q, v0, v16, T1D); + pmull2(v18, T1Q, v0, v16, T2D); + ldrq(v0, Address(buf, 0x10)); + eor3(v0, T16B, v17, v18, v0); + + pmull (v19, T1Q, v1, v16, T1D); + pmull2(v20, T1Q, v1, v16, T2D); + ldrq(v1, Address(buf, 0x20)); + eor3(v1, T16B, v19, v20, v1); + + pmull (v21, T1Q, v2, v16, T1D); + pmull2(v22, T1Q, v2, v16, T2D); + ldrq(v2, Address(buf, 0x30)); + eor3(v2, T16B, v21, v22, v2); + + pmull (v23, T1Q, v3, v16, T1D); + pmull2(v24, T1Q, v3, v16, T2D); + ldrq(v3, Address(buf, 0x40)); + eor3(v3, T16B, v23, v24, v3); + + pmull (v25, T1Q, v4, v16, T1D); + pmull2(v26, T1Q, v4, v16, T2D); + ldrq(v4, Address(buf, 0x50)); + eor3(v4, T16B, v25, v26, v4); + + pmull (v27, T1Q, v5, v16, T1D); + pmull2(v28, T1Q, v5, v16, T2D); + ldrq(v5, Address(buf, 0x60)); + eor3(v5, T16B, v27, v28, v5); + + pmull (v29, T1Q, v6, v16, T1D); + pmull2(v30, T1Q, v6, v16, T2D); + ldrq(v6, Address(buf, 0x70)); + eor3(v6, T16B, v29, v30, v6); + + // Reuse registers v23, v24. + // Using them won't block the first instruction of the next iteration. + pmull (v23, T1Q, v7, v16, T1D); + pmull2(v24, T1Q, v7, v16, T2D); + ldrq(v7, Address(pre(buf, 0x80))); + eor3(v7, T16B, v23, v24, v7); subs(len, len, 0x80); br(Assembler::GE, CRC_by128_loop); // fold into 512 bits - ldrq(v0, Address(table, 0x10)); + // Use v31 for constants because v16 can be still in use. + ldrq(v31, Address(table, 0x10)); - pmull (v10, T1Q, v1, v0, T1D); - pmull2(v11, T1Q, v1, v0, T2D); - eor3(v1, T16B, v10, v11, v5); + pmull (v17, T1Q, v0, v31, T1D); + pmull2(v18, T1Q, v0, v31, T2D); + eor3(v0, T16B, v17, v18, v4); - pmull (v12, T1Q, v2, v0, T1D); - pmull2(v13, T1Q, v2, v0, T2D); - eor3(v2, T16B, v12, v13, v6); + pmull (v19, T1Q, v1, v31, T1D); + pmull2(v20, T1Q, v1, v31, T2D); + eor3(v1, T16B, v19, v20, v5); - pmull (v14, T1Q, v3, v0, T1D); - pmull2(v15, T1Q, v3, v0, T2D); - eor3(v3, T16B, v14, v15, v7); + pmull (v21, T1Q, v2, v31, T1D); + pmull2(v22, T1Q, v2, v31, T2D); + eor3(v2, T16B, v21, v22, v6); - pmull (v16, T1Q, v4, v0, T1D); - pmull2(v17, T1Q, v4, v0, T2D); - eor3(v4, T16B, v16, v17, v8); + pmull (v23, T1Q, v3, v31, T1D); + pmull2(v24, T1Q, v3, v31, T2D); + eor3(v3, T16B, v23, v24, v7); // fold into 128 bits - ldrq(v5, Address(table, 0x20)); - pmull (v10, T1Q, v1, v5, T1D); - pmull2(v11, T1Q, v1, v5, T2D); - eor3(v4, T16B, v4, v10, v11); - - ldrq(v6, Address(table, 0x30)); - pmull (v12, T1Q, v2, v6, T1D); - pmull2(v13, T1Q, v2, v6, T2D); - eor3(v4, T16B, v4, v12, v13); - - ldrq(v7, Address(table, 0x40)); - pmull (v14, T1Q, v3, v7, T1D); - pmull2(v15, T1Q, v3, v7, T2D); - eor3(v1, T16B, v4, v14, v15); + // Use v17 for constants because v31 can be still in use. + ldrq(v17, Address(table, 0x20)); + pmull (v25, T1Q, v0, v17, T1D); + pmull2(v26, T1Q, v0, v17, T2D); + eor3(v3, T16B, v3, v25, v26); + + // Use v18 for constants because v17 can be still in use. + ldrq(v18, Address(table, 0x30)); + pmull (v27, T1Q, v1, v18, T1D); + pmull2(v28, T1Q, v1, v18, T2D); + eor3(v3, T16B, v3, v27, v28); + + // Use v19 for constants because v18 can be still in use. + ldrq(v19, Address(table, 0x40)); + pmull (v29, T1Q, v2, v19, T1D); + pmull2(v30, T1Q, v2, v19, T2D); + eor3(v0, T16B, v3, v29, v30); add(len, len, 0x80); add(buf, buf, 0x10); - mov(tmp0, v1, D, 0); - mov(tmp1, v1, D, 1); + mov(tmp0, v0, D, 0); + mov(tmp1, v0, D, 1); } SkipIfEqual::SkipIfEqual( @@ -5339,28 +5397,25 @@ address MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3, // For Strings we're passed the address of the first characters in a1 // and a2 and the length in cnt1. -// elem_size is the element size in bytes: either 1 or 2. // There are two implementations. For arrays >= 8 bytes, all // comparisons (including the final one, which may overlap) are // performed 8 bytes at a time. For strings < 8 bytes, we compare a // halfword, then a short, and then a byte. void MacroAssembler::string_equals(Register a1, Register a2, - Register result, Register cnt1, int elem_size) + Register result, Register cnt1) { Label SAME, DONE, SHORT, NEXT_WORD; Register tmp1 = rscratch1; Register tmp2 = rscratch2; Register cnt2 = tmp2; // cnt2 only used in array length compare - assert(elem_size == 1 || elem_size == 2, "must be 2 or 1 byte"); assert_different_registers(a1, a2, result, cnt1, rscratch1, rscratch2); #ifndef PRODUCT { - const char kind = (elem_size == 2) ? 'U' : 'L'; char comment[64]; - snprintf(comment, sizeof comment, "{string_equals%c", kind); + snprintf(comment, sizeof comment, "{string_equalsL"); BLOCK_COMMENT(comment); } #endif @@ -5408,14 +5463,12 @@ void MacroAssembler::string_equals(Register a1, Register a2, cbnzw(tmp1, DONE); } bind(TAIL01); - if (elem_size == 1) { // Only needed when comparing 1-byte elements - tbz(cnt1, 0, SAME); // 0-1 bytes left. + tbz(cnt1, 0, SAME); // 0-1 bytes left. { - ldrb(tmp1, a1); - ldrb(tmp2, a2); - eorw(tmp1, tmp1, tmp2); - cbnzw(tmp1, DONE); - } + ldrb(tmp1, a1); + ldrb(tmp2, a2); + eorw(tmp1, tmp1, tmp2); + cbnzw(tmp1, DONE); } // Arrays are equal. bind(SAME); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 84931c409cf..990e725d099 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -720,6 +720,7 @@ class MacroAssembler: public Assembler { // Alignment void align(int modulus); + void align(int modulus, int target); // nop void post_call_nop(); @@ -1247,6 +1248,8 @@ class MacroAssembler: public Assembler { // Emit the CompiledIC call idiom address ic_call(address entry, jint method_index = 0); + static int ic_check_size(); + int ic_check(int end_alignment); public: @@ -1399,8 +1402,7 @@ class MacroAssembler: public Assembler { address arrays_equals(Register a1, Register a2, Register result, Register cnt1, Register tmp1, Register tmp2, Register tmp3, int elem_size); - void string_equals(Register a1, Register a2, Register result, Register cnt1, - int elem_size); + void string_equals(Register a1, Register a2, Register result, Register cnt1); void fill_words(Register base, Register cnt, Register value); address zero_words(Register base, uint64_t cnt); @@ -1425,11 +1427,6 @@ class MacroAssembler: public Assembler { FloatRegister vtmp2, FloatRegister vtmp3, FloatRegister vtmp4, FloatRegister vtmp5); - void fast_log(FloatRegister vtmp0, FloatRegister vtmp1, FloatRegister vtmp2, - FloatRegister vtmp3, FloatRegister vtmp4, FloatRegister vtmp5, - FloatRegister tmpC1, FloatRegister tmpC2, FloatRegister tmpC3, - FloatRegister tmpC4, Register tmp1, Register tmp2, - Register tmp3, Register tmp4, Register tmp5); void generate_dsin_dcos(bool isCos, address npio2_hw, address two_over_pi, address pio2, address dsin_coef, address dcos_coef); private: diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64_log.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64_log.cpp deleted file mode 100644 index 45772ff1afd..00000000000 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64_log.cpp +++ /dev/null @@ -1,366 +0,0 @@ -/* Copyright (c) 2018, Cavium. All rights reserved. (By BELLSOFT) - * Copyright (c) 2016, 2021, Intel Corporation. All rights reserved. - * Intel Math Library (LIBM) Source Code - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/assembler.hpp" -#include "asm/assembler.inline.hpp" -#include "macroAssembler_aarch64.hpp" - -// Algorithm idea is taken from x86 hotspot intrinsic and adapted for AARCH64. -// -// For mathematical background please refer to the following literature: -// -// Tang, Ping-Tak Peter. -// Table-driven implementation of the logarithm function -// in IEEE floating-point arithmetic. -// ACM Transactions on Mathematical Software (TOMS) 16, no. 4, 1990: 378-400. - -/******************************************************************************/ -// ALGORITHM DESCRIPTION - LOG() -// --------------------- -// -// x=2^k * mx, mx in [1,2) -// -// Get B~1/mx based on the output of frecpe instruction (B0) -// B = int((B0*2^7+0.5))/2^7 -// -// Reduced argument: r=B*mx-1.0 (computed accurately in high and low parts) -// -// Result: k*log(2) - log(B) + p(r) if |x-1| >= small value (2^-6) and -// p(r) is a degree 7 polynomial -// -log(B) read from data table (high, low parts) -// Result is formed from high and low parts -// -// Special cases: -// 1. log(NaN) = quiet NaN -// 2. log(+INF) = that INF -// 3. log(0) = -INF -// 4. log(1) = +0 -// 5. log(x) = NaN if x < -0, including -INF -// -/******************************************************************************/ - -// Table with p(r) polynomial coefficients -// and table representation of logarithm values (hi and low parts) -ATTRIBUTE_ALIGNED(64) juint _L_tbl[] = -{ - // coefficients of p(r) polynomial: - // _coeff[] - 0x00000000UL, 0xbfd00000UL, // C1_0 = -0.25 - 0x92492492UL, 0x3fc24924UL, // C1_1 = 0.14285714285714285 - 0x55555555UL, 0x3fd55555UL, // C2_0 = 0.3333333333333333 - 0x3d6fb175UL, 0xbfc5555eUL, // C2_1 = -0.16666772842235003 - 0x00000000UL, 0xbfe00000UL, // C3_0 = -0.5 - 0x9999999aUL, 0x3fc99999UL, // C3_1 = 0.2 - // _log2[] - 0xfefa3800UL, 0x3fa62e42UL, // C4_0 = 0.043321698784993146 - 0x93c76730UL, 0x3ceef357UL, // C4_1 = 3.436201886692732e-15 - // _L_tbl[] with logarithm values (hi and low parts) - 0xfefa3800UL, 0x3fe62e42UL, 0x93c76730UL, 0x3d2ef357UL, 0xaa241800UL, - 0x3fe5ee82UL, 0x0cda46beUL, 0x3d220238UL, 0x5c364800UL, 0x3fe5af40UL, - 0xac10c9fbUL, 0x3d2dfa63UL, 0x26bb8c00UL, 0x3fe5707aUL, 0xff3303ddUL, - 0x3d09980bUL, 0x26867800UL, 0x3fe5322eUL, 0x5d257531UL, 0x3d05ccc4UL, - 0x835a5000UL, 0x3fe4f45aUL, 0x6d93b8fbUL, 0xbd2e6c51UL, 0x6f970c00UL, - 0x3fe4b6fdUL, 0xed4c541cUL, 0x3cef7115UL, 0x27e8a400UL, 0x3fe47a15UL, - 0xf94d60aaUL, 0xbd22cb6aUL, 0xf2f92400UL, 0x3fe43d9fUL, 0x481051f7UL, - 0xbcfd984fUL, 0x2125cc00UL, 0x3fe4019cUL, 0x30f0c74cUL, 0xbd26ce79UL, - 0x0c36c000UL, 0x3fe3c608UL, 0x7cfe13c2UL, 0xbd02b736UL, 0x17197800UL, - 0x3fe38ae2UL, 0xbb5569a4UL, 0xbd218b7aUL, 0xad9d8c00UL, 0x3fe35028UL, - 0x9527e6acUL, 0x3d10b83fUL, 0x44340800UL, 0x3fe315daUL, 0xc5a0ed9cUL, - 0xbd274e93UL, 0x57b0e000UL, 0x3fe2dbf5UL, 0x07b9dc11UL, 0xbd17a6e5UL, - 0x6d0ec000UL, 0x3fe2a278UL, 0xe797882dUL, 0x3d206d2bUL, 0x1134dc00UL, - 0x3fe26962UL, 0x05226250UL, 0xbd0b61f1UL, 0xd8bebc00UL, 0x3fe230b0UL, - 0x6e48667bUL, 0x3d12fc06UL, 0x5fc61800UL, 0x3fe1f863UL, 0xc9fe81d3UL, - 0xbd2a7242UL, 0x49ae6000UL, 0x3fe1c078UL, 0xed70e667UL, 0x3cccacdeUL, - 0x40f23c00UL, 0x3fe188eeUL, 0xf8ab4650UL, 0x3d14cc4eUL, 0xf6f29800UL, - 0x3fe151c3UL, 0xa293ae49UL, 0xbd2edd97UL, 0x23c75c00UL, 0x3fe11af8UL, - 0xbb9ddcb2UL, 0xbd258647UL, 0x8611cc00UL, 0x3fe0e489UL, 0x07801742UL, - 0x3d1c2998UL, 0xe2d05400UL, 0x3fe0ae76UL, 0x887e7e27UL, 0x3d1f486bUL, - 0x0533c400UL, 0x3fe078bfUL, 0x41edf5fdUL, 0x3d268122UL, 0xbe760400UL, - 0x3fe04360UL, 0xe79539e0UL, 0xbd04c45fUL, 0xe5b20800UL, 0x3fe00e5aUL, - 0xb1727b1cUL, 0xbd053ba3UL, 0xaf7a4800UL, 0x3fdfb358UL, 0x3c164935UL, - 0x3d0085faUL, 0xee031800UL, 0x3fdf4aa7UL, 0x6f014a8bUL, 0x3d12cde5UL, - 0x56b41000UL, 0x3fdee2a1UL, 0x5a470251UL, 0x3d2f27f4UL, 0xc3ddb000UL, - 0x3fde7b42UL, 0x5372bd08UL, 0xbd246550UL, 0x1a272800UL, 0x3fde148aUL, - 0x07322938UL, 0xbd1326b2UL, 0x484c9800UL, 0x3fddae75UL, 0x60dc616aUL, - 0xbd1ea42dUL, 0x46def800UL, 0x3fdd4902UL, 0xe9a767a8UL, 0x3d235bafUL, - 0x18064800UL, 0x3fdce42fUL, 0x3ec7a6b0UL, 0xbd0797c3UL, 0xc7455800UL, - 0x3fdc7ff9UL, 0xc15249aeUL, 0xbd29b6ddUL, 0x693fa000UL, 0x3fdc1c60UL, - 0x7fe8e180UL, 0x3d2cec80UL, 0x1b80e000UL, 0x3fdbb961UL, 0xf40a666dUL, - 0x3d27d85bUL, 0x04462800UL, 0x3fdb56faUL, 0x2d841995UL, 0x3d109525UL, - 0x5248d000UL, 0x3fdaf529UL, 0x52774458UL, 0xbd217cc5UL, 0x3c8ad800UL, - 0x3fda93edUL, 0xbea77a5dUL, 0x3d1e36f2UL, 0x0224f800UL, 0x3fda3344UL, - 0x7f9d79f5UL, 0x3d23c645UL, 0xea15f000UL, 0x3fd9d32bUL, 0x10d0c0b0UL, - 0xbd26279eUL, 0x43135800UL, 0x3fd973a3UL, 0xa502d9f0UL, 0xbd152313UL, - 0x635bf800UL, 0x3fd914a8UL, 0x2ee6307dUL, 0xbd1766b5UL, 0xa88b3000UL, - 0x3fd8b639UL, 0xe5e70470UL, 0xbd205ae1UL, 0x776dc800UL, 0x3fd85855UL, - 0x3333778aUL, 0x3d2fd56fUL, 0x3bd81800UL, 0x3fd7fafaUL, 0xc812566aUL, - 0xbd272090UL, 0x687cf800UL, 0x3fd79e26UL, 0x2efd1778UL, 0x3d29ec7dUL, - 0x76c67800UL, 0x3fd741d8UL, 0x49dc60b3UL, 0x3d2d8b09UL, 0xe6af1800UL, - 0x3fd6e60eUL, 0x7c222d87UL, 0x3d172165UL, 0x3e9c6800UL, 0x3fd68ac8UL, - 0x2756eba0UL, 0x3d20a0d3UL, 0x0b3ab000UL, 0x3fd63003UL, 0xe731ae00UL, - 0xbd2db623UL, 0xdf596000UL, 0x3fd5d5bdUL, 0x08a465dcUL, 0xbd0a0b2aUL, - 0x53c8d000UL, 0x3fd57bf7UL, 0xee5d40efUL, 0x3d1fadedUL, 0x0738a000UL, - 0x3fd522aeUL, 0x8164c759UL, 0x3d2ebe70UL, 0x9e173000UL, 0x3fd4c9e0UL, - 0x1b0ad8a4UL, 0xbd2e2089UL, 0xc271c800UL, 0x3fd4718dUL, 0x0967d675UL, - 0xbd2f27ceUL, 0x23d5e800UL, 0x3fd419b4UL, 0xec90e09dUL, 0x3d08e436UL, - 0x77333000UL, 0x3fd3c252UL, 0xb606bd5cUL, 0x3d183b54UL, 0x76be1000UL, - 0x3fd36b67UL, 0xb0f177c8UL, 0x3d116ecdUL, 0xe1d36000UL, 0x3fd314f1UL, - 0xd3213cb8UL, 0xbd28e27aUL, 0x7cdc9000UL, 0x3fd2bef0UL, 0x4a5004f4UL, - 0x3d2a9cfaUL, 0x1134d800UL, 0x3fd26962UL, 0xdf5bb3b6UL, 0x3d2c93c1UL, - 0x6d0eb800UL, 0x3fd21445UL, 0xba46baeaUL, 0x3d0a87deUL, 0x635a6800UL, - 0x3fd1bf99UL, 0x5147bdb7UL, 0x3d2ca6edUL, 0xcbacf800UL, 0x3fd16b5cUL, - 0xf7a51681UL, 0x3d2b9acdUL, 0x8227e800UL, 0x3fd1178eUL, 0x63a5f01cUL, - 0xbd2c210eUL, 0x67616000UL, 0x3fd0c42dUL, 0x163ceae9UL, 0x3d27188bUL, - 0x604d5800UL, 0x3fd07138UL, 0x16ed4e91UL, 0x3cf89cdbUL, 0x5626c800UL, - 0x3fd01eaeUL, 0x1485e94aUL, 0xbd16f08cUL, 0x6cb3b000UL, 0x3fcf991cUL, - 0xca0cdf30UL, 0x3d1bcbecUL, 0xe4dd0000UL, 0x3fcef5adUL, 0x65bb8e11UL, - 0xbcca2115UL, 0xffe71000UL, 0x3fce530eUL, 0x6041f430UL, 0x3cc21227UL, - 0xb0d49000UL, 0x3fcdb13dUL, 0xf715b035UL, 0xbd2aff2aUL, 0xf2656000UL, - 0x3fcd1037UL, 0x75b6f6e4UL, 0xbd084a7eUL, 0xc6f01000UL, 0x3fcc6ffbUL, - 0xc5962bd2UL, 0xbcf1ec72UL, 0x383be000UL, 0x3fcbd087UL, 0x595412b6UL, - 0xbd2d4bc4UL, 0x575bd000UL, 0x3fcb31d8UL, 0x4eace1aaUL, 0xbd0c358dUL, - 0x3c8ae000UL, 0x3fca93edUL, 0x50562169UL, 0xbd287243UL, 0x07089000UL, - 0x3fc9f6c4UL, 0x6865817aUL, 0x3d29904dUL, 0xdcf70000UL, 0x3fc95a5aUL, - 0x58a0ff6fUL, 0x3d07f228UL, 0xeb390000UL, 0x3fc8beafUL, 0xaae92cd1UL, - 0xbd073d54UL, 0x6551a000UL, 0x3fc823c1UL, 0x9a631e83UL, 0x3d1e0ddbUL, - 0x85445000UL, 0x3fc7898dUL, 0x70914305UL, 0xbd1c6610UL, 0x8b757000UL, - 0x3fc6f012UL, 0xe59c21e1UL, 0xbd25118dUL, 0xbe8c1000UL, 0x3fc6574eUL, - 0x2c3c2e78UL, 0x3d19cf8bUL, 0x6b544000UL, 0x3fc5bf40UL, 0xeb68981cUL, - 0xbd127023UL, 0xe4a1b000UL, 0x3fc527e5UL, 0xe5697dc7UL, 0x3d2633e8UL, - 0x8333b000UL, 0x3fc4913dUL, 0x54fdb678UL, 0x3d258379UL, 0xa5993000UL, - 0x3fc3fb45UL, 0x7e6a354dUL, 0xbd2cd1d8UL, 0xb0159000UL, 0x3fc365fcUL, - 0x234b7289UL, 0x3cc62fa8UL, 0x0c868000UL, 0x3fc2d161UL, 0xcb81b4a1UL, - 0x3d039d6cUL, 0x2a49c000UL, 0x3fc23d71UL, 0x8fd3df5cUL, 0x3d100d23UL, - 0x7e23f000UL, 0x3fc1aa2bUL, 0x44389934UL, 0x3d2ca78eUL, 0x8227e000UL, - 0x3fc1178eUL, 0xce2d07f2UL, 0x3d21ef78UL, 0xb59e4000UL, 0x3fc08598UL, - 0x7009902cUL, 0xbd27e5ddUL, 0x39dbe000UL, 0x3fbfe891UL, 0x4fa10afdUL, - 0xbd2534d6UL, 0x830a2000UL, 0x3fbec739UL, 0xafe645e0UL, 0xbd2dc068UL, - 0x63844000UL, 0x3fbda727UL, 0x1fa71733UL, 0x3d1a8940UL, 0x01bc4000UL, - 0x3fbc8858UL, 0xc65aacd3UL, 0x3d2646d1UL, 0x8dad6000UL, 0x3fbb6ac8UL, - 0x2bf768e5UL, 0xbd139080UL, 0x40b1c000UL, 0x3fba4e76UL, 0xb94407c8UL, - 0xbd0e42b6UL, 0x5d594000UL, 0x3fb9335eUL, 0x3abd47daUL, 0x3d23115cUL, - 0x2f40e000UL, 0x3fb8197eUL, 0xf96ffdf7UL, 0x3d0f80dcUL, 0x0aeac000UL, - 0x3fb700d3UL, 0xa99ded32UL, 0x3cec1e8dUL, 0x4d97a000UL, 0x3fb5e95aUL, - 0x3c5d1d1eUL, 0xbd2c6906UL, 0x5d208000UL, 0x3fb4d311UL, 0x82f4e1efUL, - 0xbcf53a25UL, 0xa7d1e000UL, 0x3fb3bdf5UL, 0xa5db4ed7UL, 0x3d2cc85eUL, - 0xa4472000UL, 0x3fb2aa04UL, 0xae9c697dUL, 0xbd20b6e8UL, 0xd1466000UL, - 0x3fb1973bUL, 0x560d9e9bUL, 0xbd25325dUL, 0xb59e4000UL, 0x3fb08598UL, - 0x7009902cUL, 0xbd17e5ddUL, 0xc006c000UL, 0x3faeea31UL, 0x4fc93b7bUL, - 0xbd0e113eUL, 0xcdddc000UL, 0x3faccb73UL, 0x47d82807UL, 0xbd1a68f2UL, - 0xd0fb0000UL, 0x3faaaef2UL, 0x353bb42eUL, 0x3d20fc1aUL, 0x149fc000UL, - 0x3fa894aaUL, 0xd05a267dUL, 0xbd197995UL, 0xf2d4c000UL, 0x3fa67c94UL, - 0xec19afa2UL, 0xbd029efbUL, 0xd42e0000UL, 0x3fa466aeUL, 0x75bdfd28UL, - 0xbd2c1673UL, 0x2f8d0000UL, 0x3fa252f3UL, 0xe021b67bUL, 0x3d283e9aUL, - 0x89e74000UL, 0x3fa0415dUL, 0x5cf1d753UL, 0x3d0111c0UL, 0xec148000UL, - 0x3f9c63d2UL, 0x3f9eb2f3UL, 0x3d2578c6UL, 0x28c90000UL, 0x3f984925UL, - 0x325a0c34UL, 0xbd2aa0baUL, 0x25980000UL, 0x3f9432a9UL, 0x928637feUL, - 0x3d098139UL, 0x58938000UL, 0x3f902056UL, 0x06e2f7d2UL, 0xbd23dc5bUL, - 0xa3890000UL, 0x3f882448UL, 0xda74f640UL, 0xbd275577UL, 0x75890000UL, - 0x3f801015UL, 0x999d2be8UL, 0xbd10c76bUL, 0x59580000UL, 0x3f700805UL, - 0xcb31c67bUL, 0x3d2166afUL, 0x00000000UL, 0x00000000UL, 0x00000000UL, - 0x80000000UL -}; - -// BEGIN dlog PSEUDO CODE: -// double dlog(double X) { -// // p(r) polynomial coefficients initialized from _L_tbl table -// double C1_0 = _L_tbl[0]; -// double C1_1 = _L_tbl[1]; -// double C2_0 = _L_tbl[2]; -// double C2_1 = _L_tbl[3]; -// double C3_0 = _L_tbl[4]; -// double C3_1 = _L_tbl[5]; -// double C4_0 = _L_tbl[6]; -// double C4_1 = _L_tbl[7]; -// // NOTE: operations with coefficients above are mostly vectorized in assembly -// // Check corner cases first -// if (X == 1.0d || AS_LONG_BITS(X) + 0x0010000000000000 <= 0x0010000000000000) { -// // NOTE: AS_LONG_BITS(X) + 0x0010000000000000 <= 0x0010000000000000 means -// // that X < 0 or X >= 0x7FF0000000000000 (0x7FF* is NaN or INF) -// if (X < 0 || X is NaN) return NaN; -// if (X == 1.0d) return 0.0d; -// if (X == 0.0d) return -INFINITY; -// if (X is INFINITY) return INFINITY; -// } -// // double representation is 2^exponent * mantissa -// // split X into two multipliers: 2^exponent and 1.0 * mantissa -// // pseudo function: zeroExponent(X) return value of X with exponent == 0 -// float vtmp5 = 1/(float)(zeroExponent(X)); // reciprocal estimate -// // pseudo function: HI16(X) returns high 16 bits of double value -// int hiWord = HI16(X); -// double vtmp1 = (double) 0x77F0 << 48 | mantissa(X); -// hiWord -= 16; -// if (AS_LONG_BITS(hiWord) > 0x8000) { -// // SMALL_VALUE branch -// vtmp0 = vtmp1 = vtmp0 * AS_DOUBLE_BITS(0x47F0000000000000); -// hiWord = HI16(vtmp1); -// vtmp0 = AS_DOUBLE_BITS(AS_LONG_BITS(vtmp0) |= 0x3FF0000000000000); -// vtmp5 = (double) (1/(float)vtmp0); -// vtmp1 <<= 12; -// vtmp1 >>= 12; -// } -// // MAIN branch -// double vtmp3 = AS_LONG_BITS(vtmp1) & 0xffffe00000000000; // hi part -// int intB0 = AS_INT_BITS(vtmp5) + 0x8000; -// double vtmp0 = AS_DOUBLE_BITS(0xffffe00000000000 & (intB0<<29)); -// int index = (intB0 >> 16) && 0xFF; -// double hiTableValue = _L_tbl[8+index]; // vtmp2[0] -// double lowTableValue = _L_tbl[16+index]; // vtmp2[1] -// vtmp5 = AS_DOUBLE_BITS(hiWord & 0x7FF0 - 0x3FE0); // 0x3FE = 1023 << 4 -// vtmp1 -= vtmp3; // low part -// vtmp3 = vtmp3*vtmp0 - 1.0; -// hiTableValue += C4_0 * vtmp5; -// lowTableValue += C4_1 * vtmp5; -// double r = vtmp1 * vtmp0 + vtmp3; // r = B*mx-1.0, computed in hi and low parts -// vtmp0 = hiTableValue + r; -// hiTableValue -= vtmp0; -// double r2 = r*r; -// double r3 = r2*r; -// double p7 = C3_0*r2 + C2_0*r3 + C1_0*r2*r2 + C3_1*r3*r2 + C2_1*r3*r3 -// + C1_1*r3*r2*r2; // degree 7 polynomial -// return p7 + (vtmp0 + ((r + hiTableValue) + lowTableValue)); -// } -// -// END dlog PSEUDO CODE - - -// Generate log(X). X passed in register v0. Return log(X) into v0. -// Generator parameters: 10 temporary FPU registers and temporary general -// purpose registers -void MacroAssembler::fast_log(FloatRegister vtmp0, FloatRegister vtmp1, - FloatRegister vtmp2, FloatRegister vtmp3, - FloatRegister vtmp4, FloatRegister vtmp5, - FloatRegister C1, FloatRegister C2, - FloatRegister C3, FloatRegister C4, - Register tmp1, Register tmp2, Register tmp3, - Register tmp4, Register tmp5) { - Label DONE, CHECK_CORNER_CASES, SMALL_VALUE, MAIN, - CHECKED_CORNER_CASES, RETURN_MINF_OR_NAN; - const int64_t INF_OR_NAN_PREFIX = 0x7FF0; - const int64_t MINF_OR_MNAN_PREFIX = 0xFFF0; - const int64_t ONE_PREFIX = 0x3FF0; - movz(tmp2, ONE_PREFIX, 48); - movz(tmp4, 0x0010, 48); - fmovd(rscratch1, v0); // rscratch1 = AS_LONG_BITS(X) - lea(rscratch2, ExternalAddress((address)_L_tbl)); - movz(tmp5, 0x7F); - add(tmp1, rscratch1, tmp4); - cmp(tmp2, rscratch1); - lsr(tmp3, rscratch1, 29); - ccmp(tmp1, tmp4, 0b1101 /* LE */, NE); - bfm(tmp3, tmp5, 41, 8); - fmovs(vtmp5, tmp3); - // Load coefficients from table. All coefficients are organized to be - // in specific order, because load below will load it in vectors to be used - // later in vector instructions. Load will be performed in parallel while - // branches are taken. C1 will contain vector of {C1_0, C1_1}, C2 = - // {C2_0, C2_1}, C3 = {C3_0, C3_1}, C4 = {C4_0, C4_1} - ld1(C1, C2, C3, C4, T2D, post(rscratch2, 64)); - br(LE, CHECK_CORNER_CASES); - bind(CHECKED_CORNER_CASES); - // all corner cases are handled - frecpe(vtmp5, vtmp5, S); // vtmp5 ~= 1/vtmp5 - lsr(tmp2, rscratch1, 48); - movz(tmp4, 0x77f0, 48); - fmovd(vtmp4, 1.0); - movz(tmp1, INF_OR_NAN_PREFIX, 48); - bfm(tmp4, rscratch1, 0, 51); // tmp4 = 0x77F0 << 48 | mantissa(X) - // vtmp1 = AS_DOUBLE_BITS(0x77F0 << 48 | mantissa(X)) == mx - fmovd(vtmp1, tmp4); - subw(tmp2, tmp2, 16); - subs(zr, tmp2, 0x8000); - br(GE, SMALL_VALUE); - bind(MAIN); - fmovs(tmp3, vtmp5); // int intB0 = AS_INT_BITS(B); - mov(tmp5, 0x3FE0); - uint64_t mask = UCONST64(0xffffe00000000000); - mov(rscratch1, mask); - andr(tmp2, tmp2, tmp1, LSR, 48); // hiWord & 0x7FF0 - sub(tmp2, tmp2, tmp5); // tmp2 = hiWord & 0x7FF0 - 0x3FE0 - scvtfwd(vtmp5, tmp2); // vtmp5 = (double)tmp2; - addw(tmp3, tmp3, 0x8000); // tmp3 = B - andr(tmp4, tmp4, rscratch1); // tmp4 == hi_part(mx) - andr(rscratch1, rscratch1, tmp3, LSL, 29); // rscratch1 = hi_part(B) - ubfm(tmp3, tmp3, 16, 23); // int index = (intB0 >> 16) && 0xFF - ldrq(vtmp2, Address(rscratch2, tmp3, Address::lsl(4))); // vtmp2 = _L_tbl[index] - // AS_LONG_BITS(vtmp1) & 0xffffe00000000000 // hi_part(mx) - fmovd(vtmp3, tmp4); - fmovd(vtmp0, rscratch1); // vtmp0 = hi_part(B) - fsubd(vtmp1, vtmp1, vtmp3); // vtmp1 -= vtmp3; // low_part(mx) - fnmsub(vtmp3, vtmp3, vtmp0, vtmp4); // vtmp3 = vtmp3*vtmp0 - vtmp4 - fmlavs(vtmp2, T2D, C4, vtmp5, 0); // vtmp2 += {C4} * vtmp5 - // vtmp1 = r = vtmp1 * vtmp0 + vtmp3 == low_part(mx) * hi_part(B) + (hi_part(mx)*hi_part(B) - 1.0) - fmaddd(vtmp1, vtmp1, vtmp0, vtmp3); - ins(vtmp5, D, vtmp2, 0, 1); // vtmp5 = vtmp2[1]; - faddd(vtmp0, vtmp2, vtmp1); // vtmp0 = vtmp2 + vtmp1 - fmlavs(C3, T2D, C2, vtmp1, 0); // {C3} += {C2}*vtmp1 - fsubd(vtmp2, vtmp2, vtmp0); // vtmp2 -= vtmp0 - fmuld(vtmp3, vtmp1, vtmp1); // vtmp3 = vtmp1*vtmp1 - faddd(C4, vtmp1, vtmp2); // C4[0] = vtmp1 + vtmp2 - fmlavs(C3, T2D, C1, vtmp3, 0); // {C3} += {C1}*vtmp3 - faddd(C4, C4, vtmp5); // C4 += vtmp5 - fmuld(vtmp4, vtmp3, vtmp1); // vtmp4 = vtmp3*vtmp1 - faddd(vtmp0, vtmp0, C4); // vtmp0 += C4 - fmlavs(C3, T2D, vtmp4, C3, 1); // {C3} += {vtmp4}*C3[1] - fmaddd(vtmp0, C3, vtmp3, vtmp0); // vtmp0 = C3 * vtmp3 + vtmp0 - ret(lr); - - block_comment("if (AS_LONG_BITS(hiWord) > 0x8000)"); { - bind(SMALL_VALUE); - movz(tmp2, 0x47F0, 48); - fmovd(vtmp1, tmp2); - fmuld(vtmp0, vtmp1, v0); - fmovd(vtmp1, vtmp0); - umov(tmp2, vtmp1, S, 3); - orr(vtmp0, T16B, vtmp0, vtmp4); - ushr(vtmp5, T2D, vtmp0, 27); - ushr(vtmp5, T4S, vtmp5, 2); - frecpe(vtmp5, vtmp5, S); - shl(vtmp1, T2D, vtmp1, 12); - ushr(vtmp1, T2D, vtmp1, 12); - b(MAIN); - } - - block_comment("Corner cases"); { - bind(RETURN_MINF_OR_NAN); - movz(tmp1, MINF_OR_MNAN_PREFIX, 48); - orr(rscratch1, rscratch1, tmp1); - fmovd(v0, rscratch1); - ret(lr); - bind(CHECK_CORNER_CASES); - movz(tmp1, INF_OR_NAN_PREFIX, 48); - cmp(rscratch1, zr); - br(LE, RETURN_MINF_OR_NAN); - cmp(rscratch1, tmp1); - br(GE, DONE); - cmp(rscratch1, tmp2); - br(NE, CHECKED_CORNER_CASES); - fmovd(v0, 0.0); - } - bind(DONE); - ret(lr); -} diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 8694734c751..216c1ff3509 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -30,7 +30,6 @@ #include "code/codeCache.hpp" #include "code/compiledIC.hpp" #include "code/debugInfoRec.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "compiler/oopMap.hpp" #include "gc/shared/barrierSetAssembler.hpp" @@ -39,7 +38,6 @@ #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "nativeInst_aarch64.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/klass.inline.hpp" #include "oops/method.inline.hpp" #include "prims/methodHandles.hpp" @@ -740,9 +738,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm address c2i_unverified_entry = __ pc(); Label skip_fixup; - Label ok; - - Register holder = rscratch2; + Register data = rscratch2; Register receiver = j_rarg0; Register tmp = r10; // A call-clobbered register not used for arg passing @@ -757,17 +753,12 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm { __ block_comment("c2i_unverified_entry {"); - __ load_klass(rscratch1, receiver); - __ ldr(tmp, Address(holder, CompiledICHolder::holder_klass_offset())); - __ cmp(rscratch1, tmp); - __ ldr(rmethod, Address(holder, CompiledICHolder::holder_metadata_offset())); - __ br(Assembler::EQ, ok); - __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); - - __ bind(ok); // Method might have been compiled since the call site was patched to // interpreted; if that is the case treat it as a miss so we can get // the call site corrected. + __ ic_check(1 /* end_alignment */); + __ ldr(rmethod, Address(data, CompiledICData::speculated_method_offset())); + __ ldr(rscratch1, Address(rmethod, in_bytes(Method::code_offset()))); __ cbz(rscratch1, skip_fixup); __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); @@ -1118,7 +1109,7 @@ static void gen_continuation_enter(MacroAssembler* masm, __ b(exit); CodeBuffer* cbuf = masm->code_section()->outer(); - address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, tr_call); + address stub = CompiledDirectCall::emit_to_interp_stub(*cbuf, tr_call); if (stub == nullptr) { fatal("CodeCache is full at gen_continuation_enter"); } @@ -1183,7 +1174,7 @@ static void gen_continuation_enter(MacroAssembler* masm, } CodeBuffer* cbuf = masm->code_section()->outer(); - address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, tr_call); + address stub = CompiledDirectCall::emit_to_interp_stub(*cbuf, tr_call); if (stub == nullptr) { fatal("CodeCache is full at gen_continuation_enter"); } @@ -1391,6 +1382,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, in_ByteSize(-1), oop_maps, exception_offset); + if (nm == nullptr) return nm; if (method->is_continuation_enter_intrinsic()) { ContinuationEntry::set_enter_code(nm, interpreted_entry_offset); } else if (method->is_continuation_yield_intrinsic()) { @@ -1538,25 +1530,15 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // restoring them except rfp. rfp is the only callee save register // as far as the interpreter and the compiler(s) are concerned. - - const Register ic_reg = rscratch2; const Register receiver = j_rarg0; - Label hit; Label exception_pending; - assert_different_registers(ic_reg, receiver, rscratch1); + assert_different_registers(receiver, rscratch1); __ verify_oop(receiver); - __ cmp_klass(receiver, ic_reg, rscratch1); - __ br(Assembler::EQ, hit); - - __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); + __ ic_check(8 /* end_alignment */); // Verified entry point must be aligned - __ align(8); - - __ bind(hit); - int vep_offset = ((intptr_t)__ pc()) - start; // If we have to make this method not-entrant we'll overwrite its diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 97ca90ac764..46a7d796267 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2022, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -5327,19 +5327,6 @@ class StubGenerator: public StubCodeGenerator { return start; } - address generate_dlog() { - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "dlog"); - address entry = __ pc(); - FloatRegister vtmp0 = v0, vtmp1 = v1, vtmp2 = v2, vtmp3 = v3, vtmp4 = v4, - vtmp5 = v5, tmpC1 = v16, tmpC2 = v17, tmpC3 = v18, tmpC4 = v19; - Register tmp1 = r0, tmp2 = r1, tmp3 = r2, tmp4 = r3, tmp5 = r4; - __ fast_log(vtmp0, vtmp1, vtmp2, vtmp3, vtmp4, vtmp5, tmpC1, tmpC2, tmpC3, - tmpC4, tmp1, tmp2, tmp3, tmp4, tmp5); - return entry; - } - - // code for comparing 16 characters of strings with Latin1 and Utf16 encoding void compare_string_16_x_LU(Register tmpL, Register tmpU, Label &DIFF1, Label &DIFF2) { @@ -5487,6 +5474,32 @@ class StubGenerator: public StubCodeGenerator { return entry; } + // r0 = input (float16) + // v0 = result (float) + // v1 = temporary float register + address generate_float16ToFloat() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "float16ToFloat"); + address entry = __ pc(); + BLOCK_COMMENT("Entry:"); + __ flt16_to_flt(v0, r0, v1); + __ ret(lr); + return entry; + } + + // v0 = input (float) + // r0 = result (float16) + // v1 = temporary float register + address generate_floatToFloat16() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "floatToFloat16"); + address entry = __ pc(); + BLOCK_COMMENT("Entry:"); + __ flt_to_flt16(r0, v0, v1); + __ ret(lr); + return entry; + } + address generate_method_entry_barrier() { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", "nmethod_entry_barrier"); @@ -8333,11 +8346,6 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(); } - // Disabled until JDK-8210858 is fixed - // if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dlog)) { - // StubRoutines::_dlog = generate_dlog(); - // } - if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dsin)) { StubRoutines::_dsin = generate_dsin_dcos(/* isCos = */ false); } @@ -8345,6 +8353,12 @@ class StubGenerator: public StubCodeGenerator { if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dcos)) { StubRoutines::_dcos = generate_dsin_dcos(/* isCos = */ true); } + + if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_float16ToFloat) && + vmIntrinsics::is_intrinsic_available(vmIntrinsics::_floatToFloat16)) { + StubRoutines::_hf2f = generate_float16ToFloat(); + StubRoutines::_f2hf = generate_floatToFloat16(); + } } void generate_continuation_stubs() { diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index f7fe2f7dec8..18f310c746c 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -143,11 +143,19 @@ 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))) { + // Ampere CPUs + if (_cpu == CPU_AMPERE && ((_model == CPU_MODEL_AMPERE_1) || + (_model == CPU_MODEL_AMPERE_1A) || + (_model == CPU_MODEL_AMPERE_1B))) { if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps)) { FLAG_SET_DEFAULT(UseSIMDForMemoryOps, true); } + if (FLAG_IS_DEFAULT(OnSpinWaitInst)) { + FLAG_SET_DEFAULT(OnSpinWaitInst, "isb"); + } + if (FLAG_IS_DEFAULT(OnSpinWaitInstCount)) { + FLAG_SET_DEFAULT(OnSpinWaitInstCount, 2); + } } // ThunderX diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp index 4b2e5cc5a4d..0a85d339a55 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp @@ -110,7 +110,8 @@ enum Ampere_CPU_Model { 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 */ + CPU_MODEL_AMPERE_1A = 0xac4, /* CPU implementer is CPU_AMPERE */ + CPU_MODEL_AMPERE_1B = 0xac5 /* AMPERE_1B core Implements ARMv8.7 with CSSC, MTE, SM3/SM4 extensions */ }; #define CPU_FEATURE_FLAGS(decl) \ diff --git a/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp index c895ff5cc0e..2bb53d16a3c 100644 --- a/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp @@ -26,10 +26,10 @@ #include "precompiled.hpp" #include "asm/assembler.inline.hpp" #include "asm/macroAssembler.inline.hpp" +#include "code/compiledIC.hpp" #include "code/vtableStubs.hpp" #include "interp_masm_aarch64.hpp" #include "memory/resourceArea.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/instanceKlass.hpp" #include "oops/klassVtable.hpp" #include "runtime/sharedRuntime.hpp" @@ -168,22 +168,22 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); // Entry arguments: - // rscratch2: CompiledICHolder + // rscratch2: CompiledICData // j_rarg0: Receiver // This stub is called from compiled code which has no callee-saved registers, // so all registers except arguments are free at this point. const Register recv_klass_reg = r10; - const Register holder_klass_reg = r16; // declaring interface klass (DECC) + const Register holder_klass_reg = r16; // declaring interface klass (DEFC) const Register resolved_klass_reg = r17; // resolved interface klass (REFC) const Register temp_reg = r11; const Register temp_reg2 = r15; - const Register icholder_reg = rscratch2; + const Register icdata_reg = rscratch2; Label L_no_such_interface; - __ ldr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset())); - __ ldr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset())); + __ ldr(resolved_klass_reg, Address(icdata_reg, CompiledICData::itable_refc_klass_offset())); + __ ldr(holder_klass_reg, Address(icdata_reg, CompiledICData::itable_defc_klass_offset())); start_pc = __ pc(); diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index e31ad91613a..1a833b08c4c 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -195,7 +195,7 @@ void emit_call_reloc(CodeBuffer &cbuf, const MachCallNode *n, MachOper *m, Reloc assert(maybe_far_call(n) == !__ reachable_from_cache(target), "sanity"); assert(cache_reachable() == __ cache_fully_reachable(), "sanity"); - assert(target != NULL, "need real address"); + assert(target != nullptr, "need real address"); int ret_addr_offset = -1; if (rspec.type() == relocInfo::runtime_call_type) { @@ -290,7 +290,7 @@ void MachPrologNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { st->print ("SUB R_SP, R_SP, " SIZE_FORMAT,framesize); } - if (C->stub_function() == NULL && BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) { + if (C->stub_function() == nullptr && BarrierSet::barrier_set()->barrier_set_nmethod() != nullptr) { 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"); @@ -332,7 +332,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { __ sub_slow(SP, SP, framesize); } - if (C->stub_function() == NULL) { + if (C->stub_function() == nullptr) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->nmethod_entry_barrier(&_masm); } @@ -454,7 +454,7 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, return size; // Self copy, no move #ifdef TODO - if (bottom_type()->isa_vect() != NULL) { + if (bottom_type()->isa_vect() != nullptr) { } #endif @@ -804,16 +804,16 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, #ifndef PRODUCT void MachSpillCopyNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { - implementation( NULL, ra_, false, st ); + implementation(nullptr, ra_, false, st ); } #endif void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - implementation( &cbuf, ra_, false, NULL ); + implementation( &cbuf, ra_, false, nullptr ); } uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { - return implementation( NULL, ra_, true, NULL ); + return implementation( nullptr, ra_, true, nullptr ); } //============================================================================= @@ -869,12 +869,7 @@ uint BoxLockNode::size(PhaseRegAlloc *ra_) const { #define R_RTEMP "R_R12" void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { st->print_cr("\nUEP:"); - if (UseCompressedClassPointers) { - st->print_cr("\tLDR_w " R_RTEMP ",[R_R0 + oopDesc::klass_offset_in_bytes]\t! Inline cache check"); - st->print_cr("\tdecode_klass " R_RTEMP); - } else { - st->print_cr("\tLDR " R_RTEMP ",[R_R0 + oopDesc::klass_offset_in_bytes]\t! Inline cache check"); - } + st->print_cr("\tLDR " R_RTEMP ",[R_R0 + oopDesc::klass_offset_in_bytes]\t! Inline cache check"); st->print_cr("\tCMP " R_RTEMP ",R_R8" ); st->print ("\tB.NE SharedRuntime::handle_ic_miss_stub"); } @@ -882,13 +877,7 @@ void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { C2_MacroAssembler _masm(&cbuf); - Register iCache = reg_to_register_object(Matcher::inline_cache_reg_encode()); - assert(iCache == Ricklass, "should be"); - Register receiver = R0; - - __ load_klass(Rtemp, receiver); - __ cmp(Rtemp, iCache); - __ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, noreg, ne); + __ ic_check(InteriorEntryAlignment); } uint MachUEPNode::size(PhaseRegAlloc *ra_) const { @@ -903,7 +892,7 @@ int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) { C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_exception_handler()); - if (base == NULL) { + if (base == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return 0; // CodeBuffer::expand failed } @@ -926,7 +915,7 @@ int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_deopt_handler()); - if (base == NULL) { + if (base == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return 0; // CodeBuffer::expand failed } @@ -1002,7 +991,7 @@ bool Matcher::match_rule_supported(int opcode) { return true; // Per default match rules are supported. } -bool Matcher::match_rule_supported_superword(int opcode, int vlen, BasicType bt) { +bool Matcher::match_rule_supported_auto_vectorization(int opcode, int vlen, BasicType bt) { return match_rule_supported_vector(opcode, vlen, bt); } @@ -1026,11 +1015,11 @@ bool Matcher::vector_needs_partial_operations(Node* node, const TypeVect* vt) { } const RegMask* Matcher::predicate_reg_mask(void) { - return NULL; + return nullptr; } const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return NULL; + return nullptr; } // Vector calling convention not yet implemented. @@ -1074,7 +1063,7 @@ int Matcher::min_vector_size(const BasicType bt) { return 8/type2aelembytes(bt); } -int Matcher::superword_max_vector_size(const BasicType bt) { +int Matcher::max_vector_size_auto_vectorization(const BasicType bt) { return Matcher::max_vector_size(bt); } @@ -1094,7 +1083,7 @@ bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) { MachOper* Matcher::pd_specialize_generic_vector_operand(MachOper* original_opnd, uint ideal_reg, bool is_temp) { ShouldNotReachHere(); // generic vector operands not supported - return NULL; + return nullptr; } bool Matcher::is_reg2reg_move(MachNode* m) { @@ -1241,8 +1230,8 @@ encode %{ emit_call_reloc(cbuf, as_MachCall(), $meth, rspec); // Emit stubs for static call. - address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); - if (stub == NULL) { + address stub = CompiledDirectCall::emit_to_interp_stub(cbuf); + if (stub == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -1987,7 +1976,7 @@ operand immNKlass() interface(CONST_INTER); %} -// NULL Pointer Immediate +// Null Pointer Immediate operand immN0() %{ predicate(n->get_narrowcon() == 0); diff --git a/src/hotspot/cpu/arm/arm_32.ad b/src/hotspot/cpu/arm/arm_32.ad index affe5a816fc..dd7d6f491da 100644 --- a/src/hotspot/cpu/arm/arm_32.ad +++ b/src/hotspot/cpu/arm/arm_32.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -431,7 +431,7 @@ OptoRegPair c2::return_value(int ideal_reg) { // will point. int MachCallStaticJavaNode::ret_addr_offset() { - bool far = (_method == NULL) ? maybe_far_call(this) : !cache_reachable(); + bool far = (_method == nullptr) ? maybe_far_call(this) : !cache_reachable(); return ((far ? 3 : 1) + (_method_handle_invoke ? 1 : 0)) * NativeInstruction::instruction_size; } diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp index 999309c0225..16aeaa20c04 100644 --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp @@ -161,10 +161,7 @@ void LIR_Assembler::osr_entry() { int LIR_Assembler::check_icache() { - Register receiver = LIR_Assembler::receiverOpr()->as_register(); - int offset = __ offset(); - __ inline_cache_check(receiver, Ricklass); - return offset; + return __ ic_check(CodeEntryAlignment); } void LIR_Assembler::clinit_barrier(ciMethod* method) { @@ -1950,7 +1947,7 @@ void LIR_Assembler::emit_static_call_stub() { __ relocate(static_stub_Relocation::spec(call_pc)); // If not a single instruction, NativeMovConstReg::next_instruction_address() // must jump over the whole following ldr_literal. - // (See CompiledStaticCall::set_to_interpreted()) + // (See CompiledDirectCall::set_to_interpreted()) #ifdef ASSERT address ldr_site = __ pc(); #endif diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp index c09e54e0e57..d9d042bb2e4 100644 --- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp @@ -43,16 +43,6 @@ // arm [macro]assembler) and used with care in the other C1 specific // files. -void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) { - Label verified; - load_klass(Rtemp, receiver); - cmp(Rtemp, iCache); - b(verified, eq); // jump over alignment no-ops - jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type); - align(CodeEntryAlignment); - bind(verified); -} - void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_bytes) { assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect"); assert((frame_size_in_bytes % StackAlignmentInBytes) == 0, "frame size should be aligned"); diff --git a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp index 62faa617083..9862a074a68 100644 --- a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp +++ b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp @@ -37,7 +37,6 @@ #include "interpreter/interpreter.hpp" #include "memory/universe.hpp" #include "nativeInst_arm.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "register_arm.hpp" diff --git a/src/hotspot/cpu/arm/compiledIC_arm.cpp b/src/hotspot/cpu/arm/compiledIC_arm.cpp index 2d4187b7d6c..71389d2353d 100644 --- a/src/hotspot/cpu/arm/compiledIC_arm.cpp +++ b/src/hotspot/cpu/arm/compiledIC_arm.cpp @@ -25,7 +25,6 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" #include "code/compiledIC.hpp" -#include "code/icBuffer.hpp" #include "code/nativeInst.hpp" #include "code/nmethod.hpp" #include "logging/log.hpp" @@ -37,7 +36,7 @@ #if COMPILER2_OR_JVMCI #define __ _masm. // emit call stub, compiled java to interpreter -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { +address CompiledDirectCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { // Stub is fixed up when the corresponding call is converted from calling // compiled code to calling interpreted code. // set (empty), R9 @@ -59,7 +58,7 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) InlinedMetadata object_literal(nullptr); // single instruction, see NativeMovConstReg::next_instruction_address() in - // CompiledStaticCall::set_to_interpreted() + // CompiledDirectCall::set_to_interpreted() __ ldr_literal(Rmethod, object_literal); __ set_inst_mark(); // Who uses this? @@ -87,32 +86,25 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) #undef __ // Relocation entries for call stub, compiled java to interpreter. -int CompiledStaticCall::reloc_to_interp_stub() { +int CompiledDirectCall::reloc_to_interp_stub() { return 10; // 4 in emit_to_interp_stub + 1 in Java_Static_Call } #endif // COMPILER2_OR_JVMCI -int CompiledStaticCall::to_trampoline_stub_size() { +int CompiledDirectCall::to_trampoline_stub_size() { // ARM doesn't use trampolines. return 0; } // size of C2 call stub, compiled java to interpreter -int CompiledStaticCall::to_interp_stub_size() { +int CompiledDirectCall::to_interp_stub_size() { return 8 * NativeInstruction::instruction_size; } -void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) { +void CompiledDirectCall::set_to_interpreted(const methodHandle& callee, address entry) { address stub = find_stub(); guarantee(stub != nullptr, "stub not found"); - { - ResourceMark rm; - log_trace(inlinecache)("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s", - p2i(instruction_address()), - callee->name_and_sig_as_C_string()); - } - // Creation also verifies the object. NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); @@ -128,7 +120,7 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad set_destination_mt_safe(stub); } -void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) { +void CompiledDirectCall::set_stub_to_clean(static_stub_Relocation* static_stub) { // Reset stub. address stub = static_stub->addr(); assert(stub != nullptr, "stub not found"); @@ -144,7 +136,7 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_ // Non-product mode code #ifndef PRODUCT -void CompiledDirectStaticCall::verify() { +void CompiledDirectCall::verify() { // Verify call. _call->verify(); _call->verify_alignment(); diff --git a/src/hotspot/cpu/arm/icBuffer_arm.cpp b/src/hotspot/cpu/arm/icBuffer_arm.cpp deleted file mode 100644 index e3a1c148ec6..00000000000 --- a/src/hotspot/cpu/arm/icBuffer_arm.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/assembler.inline.hpp" -#include "code/icBuffer.hpp" -#include "gc/shared/collectedHeap.inline.hpp" -#include "interpreter/bytecodes.hpp" -#include "memory/resourceArea.hpp" -#include "nativeInst_arm.hpp" -#include "oops/oop.inline.hpp" - -#define __ masm-> - -int InlineCacheBuffer::ic_stub_code_size() { - return (4 * Assembler::InstructionSize); -} - -void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin, void* cached_value, address entry_point) { - ResourceMark rm; - CodeBuffer code(code_begin, ic_stub_code_size()); - MacroAssembler* masm = new MacroAssembler(&code); - - InlinedAddress oop_literal((address) cached_value); - __ ldr_literal(Ricklass, oop_literal); - // FIXME: OK to remove reloc here? - __ patchable_jump(entry_point, relocInfo::runtime_call_type, Rtemp); - __ bind_literal(oop_literal); - __ flush(); -} - -address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) { - address jump_address; - jump_address = code_begin + NativeInstruction::instruction_size; - NativeJump* jump = nativeJump_at(jump_address); - return jump->jump_destination(); -} - -void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) { - NativeMovConstReg* move = nativeMovConstReg_at(code_begin); - return (void*)move->data(); -} - -#undef __ diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.cpp b/src/hotspot/cpu/arm/macroAssembler_arm.cpp index b827e69d022..99d619bddb5 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp @@ -28,6 +28,7 @@ #include "asm/assembler.inline.hpp" #include "asm/macroAssembler.hpp" #include "ci/ciEnv.hpp" +#include "code/compiledIC.hpp" #include "code/nativeInst.hpp" #include "compiler/disassembler.hpp" #include "gc/shared/barrierSet.hpp" @@ -297,11 +298,13 @@ Address MacroAssembler::receiver_argument_address(Register params_base, Register return Address(tmp, -Interpreter::stackElementSize); } +void MacroAssembler::align(int modulus, int target) { + int delta = target - offset(); + while ((offset() + delta) % modulus != 0) nop(); +} void MacroAssembler::align(int modulus) { - while (offset() % modulus != 0) { - nop(); - } + align(modulus, offset()); } int MacroAssembler::set_last_Java_frame(Register last_java_sp, @@ -1860,3 +1863,31 @@ void MacroAssembler::lightweight_unlock(Register obj, Register t1, Register t2, // Fallthrough: success } + +int MacroAssembler::ic_check_size() { + return NativeInstruction::instruction_size * 7; +} + +int MacroAssembler::ic_check(int end_alignment) { + Register receiver = j_rarg0; + Register tmp1 = R4; + Register tmp2 = R5; + + // The UEP of a code blob ensures that the VEP is padded. However, the padding of the UEP is placed + // before the inline cache check, so we don't have to execute any nop instructions when dispatching + // through the UEP, yet we can ensure that the VEP is aligned appropriately. That's why we align + // before the inline cache check here, and not after + align(end_alignment, offset() + ic_check_size()); + + int uep_offset = offset(); + + ldr(tmp1, Address(receiver, oopDesc::klass_offset_in_bytes())); + ldr(tmp2, Address(Ricklass, CompiledICData::speculated_klass_offset())); + cmp(tmp1, tmp2); + + Label dont; + b(dont, eq); + jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type); + bind(dont); + return uep_offset; +} diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.hpp b/src/hotspot/cpu/arm/macroAssembler_arm.hpp index d9e49ab986c..691c8fa70ee 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.hpp @@ -221,6 +221,7 @@ class MacroAssembler: public Assembler { inline bool ignore_non_patchable_relocations() { return true; } void align(int modulus); + void align(int modulus, int target); // Support for VM calls // @@ -1077,6 +1078,9 @@ class MacroAssembler: public Assembler { void safepoint_poll(Register tmp1, Label& slow_path); void get_polling_page(Register dest); void read_polling_page(Register dest, relocInfo::relocType rtype); + + static int ic_check_size(); + int ic_check(int end_alignment); }; diff --git a/src/hotspot/cpu/arm/nativeInst_arm_32.cpp b/src/hotspot/cpu/arm/nativeInst_arm_32.cpp index 23ee01d3352..6a4062f29b3 100644 --- a/src/hotspot/cpu/arm/nativeInst_arm_32.cpp +++ b/src/hotspot/cpu/arm/nativeInst_arm_32.cpp @@ -25,7 +25,6 @@ #include "precompiled.hpp" #include "asm/assembler.inline.hpp" #include "code/codeCache.hpp" -#include "code/icBuffer.hpp" #include "memory/resourceArea.hpp" #include "nativeInst_arm.hpp" #include "oops/oop.inline.hpp" diff --git a/src/hotspot/cpu/arm/nativeInst_arm_32.hpp b/src/hotspot/cpu/arm/nativeInst_arm_32.hpp index 7006d770981..15b57188730 100644 --- a/src/hotspot/cpu/arm/nativeInst_arm_32.hpp +++ b/src/hotspot/cpu/arm/nativeInst_arm_32.hpp @@ -385,7 +385,7 @@ class NativeMovConstReg: public NativeInstruction { } void set_pc_relative_offset(address addr, address pc); address next_instruction_address() const { - // NOTE: CompiledStaticCall::set_to_interpreted() calls this but + // NOTE: CompiledDirectCall::set_to_interpreted() calls this but // are restricted to single-instruction ldr. No need to jump over // several instructions. assert(is_ldr_literal(), "Should only use single-instructions load"); diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 716c7b7575e..3792fab082b 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -24,15 +24,14 @@ #include "precompiled.hpp" #include "asm/assembler.inline.hpp" +#include "code/compiledIC.hpp" #include "code/debugInfoRec.hpp" -#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" -#include "oops/compiledICHolder.hpp" #include "oops/klass.inline.hpp" #include "prims/methodHandles.hpp" #include "runtime/jniHandles.hpp" @@ -626,12 +625,9 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm Label skip_fixup; const Register receiver = R0; const Register holder_klass = Rtemp; // XXX should be OK for C2 but not 100% sure - const Register receiver_klass = R4; - __ load_klass(receiver_klass, receiver); - __ ldr(holder_klass, Address(Ricklass, CompiledICHolder::holder_klass_offset())); - __ ldr(Rmethod, Address(Ricklass, CompiledICHolder::holder_metadata_offset())); - __ cmp(receiver_klass, holder_klass); + __ ic_check(1 /* end_alignment */); + __ ldr(Rmethod, Address(Ricklass, CompiledICData::speculated_method_offset())); __ ldr(Rtemp, Address(Rmethod, Method::code_offset()), eq); __ cmp(Rtemp, 0, eq); @@ -819,21 +815,14 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Unverified entry point address start = __ pc(); - // Inline cache check, same as in C1_MacroAssembler::inline_cache_check() const Register receiver = R0; // see receiverOpr() - __ load_klass(Rtemp, receiver); - __ cmp(Rtemp, Ricklass); - Label verified; - - __ b(verified, eq); // jump over alignment no-ops too - __ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, Rtemp); - __ align(CodeEntryAlignment); + __ verify_oop(receiver); + // Inline cache check + __ ic_check(CodeEntryAlignment /* end_alignment */); // Verified entry point - __ bind(verified); int vep_offset = __ pc() - start; - if ((InlineObjectHash && method->intrinsic_id() == vmIntrinsics::_hashCode) || (method->intrinsic_id() == vmIntrinsics::_identityHashCode)) { // Object.hashCode, System.identityHashCode can pull the hashCode from the header word // instead of doing a full VM transition once it's been computed. diff --git a/src/hotspot/cpu/arm/vtableStubs_arm.cpp b/src/hotspot/cpu/arm/vtableStubs_arm.cpp index 539e288f63f..1229b5073f5 100644 --- a/src/hotspot/cpu/arm/vtableStubs_arm.cpp +++ b/src/hotspot/cpu/arm/vtableStubs_arm.cpp @@ -25,10 +25,10 @@ #include "precompiled.hpp" #include "asm/assembler.inline.hpp" #include "asm/macroAssembler.inline.hpp" +#include "code/compiledIC.hpp" #include "code/vtableStubs.hpp" #include "interp_masm_arm.hpp" #include "memory/resourceArea.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/instanceKlass.hpp" #include "oops/klassVtable.hpp" #include "oops/klass.inline.hpp" @@ -160,7 +160,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { __ load_klass(Rclass, R0); // Receiver subtype check against REFC. - __ ldr(Rintf, Address(Ricklass, CompiledICHolder::holder_klass_offset())); + __ ldr(Rintf, Address(Ricklass, CompiledICData::itable_refc_klass_offset())); __ lookup_interface_method(// inputs: rec. class, interface, itable index Rclass, Rintf, noreg, // outputs: temp reg1, temp reg2 @@ -171,7 +171,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { start_pc = __ pc(); // Get Method* and entry point for compiler - __ ldr(Rintf, Address(Ricklass, CompiledICHolder::holder_metadata_offset())); + __ ldr(Rintf, Address(Ricklass, CompiledICData::itable_defc_klass_offset())); __ lookup_interface_method(// inputs: rec. class, interface, itable index Rclass, Rintf, itable_index, // outputs: temp reg1, temp reg2, temp reg3 diff --git a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp index 47b681ce26b..d78dec964cb 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp @@ -451,7 +451,7 @@ inline void Assembler::bcctrl(int boint, int biint, int bhint, relocInfo::relocT // helper function for b inline bool Assembler::is_within_range_of_b(address a, address pc) { - // Guard against illegal branch targets, e.g. -1 (see CompiledStaticCall and ad-file). + // Guard against illegal branch targets, e.g. -1 (see CompiledDirectCall and ad-file). if ((((uint64_t)a) & 0x3) != 0) return false; const int range = 1 << (29-6); // li field is from bit 6 to bit 29. @@ -465,7 +465,7 @@ inline bool Assembler::is_within_range_of_b(address a, address pc) { // helper functions for bcxx. inline bool Assembler::is_within_range_of_bcxx(address a, address pc) { - // Guard against illegal branch targets, e.g. -1 (see CompiledStaticCall and ad-file). + // Guard against illegal branch targets, e.g. -1 (see CompiledDirectCall and ad-file). if ((((uint64_t)a) & 0x3) != 0) return false; const int range = 1 << (29-16); // bd field is from bit 16 to bit 29. diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index d316c2b3db2..4b29bcf57e4 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -77,9 +77,7 @@ int LIR_Assembler::initial_frame_size_in_bytes() const { // we fetch the class of the receiver and compare it with the cached class. // If they do not match we jump to slow case. int LIR_Assembler::check_icache() { - int offset = __ offset(); - __ inline_cache_check(R3_ARG1, R19_inline_cache_reg); - return offset; + return __ ic_check(CodeEntryAlignment); } void LIR_Assembler::clinit_barrier(ciMethod* method) { diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index 577dcae25f4..b379d4141a3 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -40,29 +40,6 @@ #include "utilities/macros.hpp" #include "utilities/powerOfTwo.hpp" -void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) { - const Register temp_reg = R12_scratch2; - Label Lmiss; - - verify_oop(receiver, FILE_AND_LINE); - load_klass_check_null(temp_reg, receiver, &Lmiss); - - if (TrapBasedICMissChecks && TrapBasedNullChecks) { - trap_ic_miss_check(temp_reg, iCache); - } else { - Label Lok; - cmpd(CCR0, temp_reg, iCache); - beq(CCR0, Lok); - bind(Lmiss); - //load_const_optimized(temp_reg, SharedRuntime::get_ic_miss_stub(), R0); - calculate_address_from_global_toc(temp_reg, SharedRuntime::get_ic_miss_stub(), true, true, false); - mtctr(temp_reg); - bctr(); - align(32, 12); - bind(Lok); - } -} - void C1_MacroAssembler::explicit_null_check(Register base) { Unimplemented(); diff --git a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp index 2ba6a6bca4e..63914c5d1cb 100644 --- a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp @@ -34,7 +34,6 @@ #include "gc/shared/cardTableBarrierSet.hpp" #include "interpreter/interpreter.hpp" #include "nativeInst_ppc.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "register_ppc.hpp" diff --git a/src/hotspot/cpu/ppc/compiledIC_ppc.cpp b/src/hotspot/cpu/ppc/compiledIC_ppc.cpp index 54f9cfa9367..355ac4815d5 100644 --- a/src/hotspot/cpu/ppc/compiledIC_ppc.cpp +++ b/src/hotspot/cpu/ppc/compiledIC_ppc.cpp @@ -26,7 +26,6 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" #include "code/compiledIC.hpp" -#include "code/icBuffer.hpp" #include "code/nmethod.hpp" #include "memory/resourceArea.hpp" #include "runtime/mutexLocker.hpp" @@ -37,7 +36,7 @@ // ---------------------------------------------------------------------------- -// A PPC CompiledDirectStaticCall looks like this: +// A PPC CompiledDirectCall looks like this: // // >>>> consts // @@ -79,7 +78,7 @@ const int IC_pos_in_java_to_interp_stub = 8; #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* = nullptr*/) { +address CompiledDirectCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* = nullptr*/) { #ifdef COMPILER2 if (mark == nullptr) { // Get the mark within main instrs section which is set to the address of the call. @@ -91,7 +90,7 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* MacroAssembler _masm(&cbuf); // Start the stub. - address stub = __ start_a_stub(CompiledStaticCall::to_interp_stub_size()); + address stub = __ start_a_stub(CompiledDirectCall::to_interp_stub_size()); if (stub == nullptr) { return nullptr; // CodeCache is full } @@ -135,7 +134,7 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* // FIXME: Assert that the stub can be identified and patched. // Java_to_interp_stub_size should be good. - assert((__ offset() - stub_start_offset) <= CompiledStaticCall::to_interp_stub_size(), + assert((__ offset() - stub_start_offset) <= CompiledDirectCall::to_interp_stub_size(), "should be good size"); assert(!is_NativeCallTrampolineStub_at(__ addr_at(stub_start_offset)), "must not confuse java_to_interp with trampoline stubs"); @@ -153,27 +152,20 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* // Size of java_to_interp stub, this doesn't need to be accurate but it must // be larger or equal to the real size of the stub. // Used for optimization in Compile::Shorten_branches. -int CompiledStaticCall::to_interp_stub_size() { +int CompiledDirectCall::to_interp_stub_size() { return 12 * BytesPerInstWord; } // Relocation entries for call stub, compiled java to interpreter. // Used for optimization in Compile::Shorten_branches. -int CompiledStaticCall::reloc_to_interp_stub() { +int CompiledDirectCall::reloc_to_interp_stub() { return 5; } -void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) { +void CompiledDirectCall::set_to_interpreted(const methodHandle& callee, address entry) { address stub = find_stub(); guarantee(stub != nullptr, "stub not found"); - { - ResourceMark rm; - log_trace(inlinecache)("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s", - p2i(instruction_address()), - callee->name_and_sig_as_C_string()); - } - // Creation also verifies the object. NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + IC_pos_in_java_to_interp_stub); NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); @@ -188,7 +180,7 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad set_destination_mt_safe(stub); } -void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) { +void CompiledDirectCall::set_stub_to_clean(static_stub_Relocation* static_stub) { // Reset stub. address stub = static_stub->addr(); assert(stub != nullptr, "stub not found"); @@ -204,7 +196,7 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_ // Non-product mode code #ifndef PRODUCT -void CompiledDirectStaticCall::verify() { +void CompiledDirectCall::verify() { // Verify call. _call->verify(); _call->verify_alignment(); diff --git a/src/hotspot/cpu/ppc/icBuffer_ppc.cpp b/src/hotspot/cpu/ppc/icBuffer_ppc.cpp deleted file mode 100644 index 4157a5b0fd7..00000000000 --- a/src/hotspot/cpu/ppc/icBuffer_ppc.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2013 SAP SE. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/assembler.inline.hpp" -#include "code/icBuffer.hpp" -#include "gc/shared/collectedHeap.inline.hpp" -#include "interpreter/bytecodes.hpp" -#include "memory/resourceArea.hpp" -#include "nativeInst_ppc.hpp" -#include "oops/oop.inline.hpp" - -#define __ masm. - -int InlineCacheBuffer::ic_stub_code_size() { - return MacroAssembler::load_const_size + MacroAssembler::b64_patchable_size; -} - -void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin, void* cached_value, address entry_point) { - ResourceMark rm; - CodeBuffer code(code_begin, ic_stub_code_size()); - MacroAssembler masm(&code); - // Note: even though the code contains an embedded metadata, we do not need reloc info - // because - // (1) the metadata is old (i.e., doesn't matter for scavenges) - // (2) these ICStubs are removed *before* a GC happens, so the roots disappear. - - // Load the oop ... - __ load_const(R19_method, (address) cached_value, R0); - // ... and jump to entry point. - __ b64_patchable((address) entry_point, relocInfo::none); - - __ flush(); -} - -address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) { - NativeMovConstReg* move = nativeMovConstReg_at(code_begin); // creation also verifies the object - NativeJump* jump = nativeJump_at(move->next_instruction_address()); - return jump->jump_destination(); -} - -void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) { - NativeMovConstReg* move = nativeMovConstReg_at(code_begin); // creation also verifies the object - void* o = (void*)move->data(); - return o; -} - diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index b9d1cdb19ac..fe19cf03500 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "code/compiledIC.hpp" #include "compiler/disassembler.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/barrierSet.hpp" @@ -1195,6 +1196,81 @@ void MacroAssembler::post_call_nop() { assert(is_post_call_nop(*(int*)(pc() - 4)), "post call not not found"); } +int MacroAssembler::ic_check_size() { + bool implicit_null_checks_available = ImplicitNullChecks && os::zero_page_read_protected(), + use_fast_receiver_null_check = implicit_null_checks_available || TrapBasedNullChecks, + use_trap_based_null_check = !implicit_null_checks_available && TrapBasedNullChecks; + + int num_ins; + if (use_fast_receiver_null_check && TrapBasedICMissChecks) { + num_ins = 3; + if (use_trap_based_null_check) num_ins += 1; + } else { + num_ins = 7; + if (!implicit_null_checks_available) num_ins += 2; + } + return num_ins * BytesPerInstWord; +} + +int MacroAssembler::ic_check(int end_alignment) { + bool implicit_null_checks_available = ImplicitNullChecks && os::zero_page_read_protected(), + use_fast_receiver_null_check = implicit_null_checks_available || TrapBasedNullChecks, + use_trap_based_null_check = !implicit_null_checks_available && TrapBasedNullChecks; + + Register receiver = R3_ARG1; + Register data = R19_inline_cache_reg; + Register tmp1 = R11_scratch1; + Register tmp2 = R12_scratch2; + + // The UEP of a code blob ensures that the VEP is padded. However, the padding of the UEP is placed + // before the inline cache check, so we don't have to execute any nop instructions when dispatching + // through the UEP, yet we can ensure that the VEP is aligned appropriately. That's why we align + // before the inline cache check here, and not after + align(end_alignment, end_alignment, end_alignment - ic_check_size()); + + int uep_offset = offset(); + + if (use_fast_receiver_null_check && TrapBasedICMissChecks) { + // Fast version which uses SIGTRAP + + if (use_trap_based_null_check) { + trap_null_check(receiver); + } + if (UseCompressedClassPointers) { + lwz(tmp1, oopDesc::klass_offset_in_bytes(), receiver); + } else { + ld(tmp1, oopDesc::klass_offset_in_bytes(), receiver); + } + ld(tmp2, in_bytes(CompiledICData::speculated_klass_offset()), data); + trap_ic_miss_check(tmp1, tmp2); + + } else { + // Slower version which doesn't use SIGTRAP + + // Load stub address using toc (fixed instruction size, unlike load_const_optimized) + calculate_address_from_global_toc(tmp1, SharedRuntime::get_ic_miss_stub(), + true, true, false); // 2 instructions + mtctr(tmp1); + + if (!implicit_null_checks_available) { + cmpdi(CCR0, receiver, 0); + beqctr(CCR0); + } + if (UseCompressedClassPointers) { + lwz(tmp1, oopDesc::klass_offset_in_bytes(), receiver); + } else { + ld(tmp1, oopDesc::klass_offset_in_bytes(), receiver); + } + ld(tmp2, in_bytes(CompiledICData::speculated_klass_offset()), data); + cmpd(CCR0, tmp1, tmp2); + bnectr(CCR0); + } + + assert((offset() % end_alignment) == 0, "Misaligned verified entry point"); + + return uep_offset; +} + void MacroAssembler::call_VM_base(Register oop_result, Register last_java_sp, address entry_point, diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index cddc8b92fa0..ec370a450ac 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -367,6 +367,9 @@ class MacroAssembler: public Assembler { Register toc); #endif + static int ic_check_size(); + int ic_check(int end_alignment); + protected: // It is imperative that all calls into the VM are handled via the diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index be37ff1785b..6f5e6dabec5 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2012, 2023 SAP SE. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // @@ -1026,7 +1026,7 @@ bool followed_by_acquire(const Node *load) { assert(load->is_Load(), "So far implemented only for loads."); // Find MemBarAcquire. - const Node *mba = NULL; + const Node *mba = nullptr; for (DUIterator_Fast imax, i = load->fast_outs(imax); i < imax; i++) { const Node *out = load->fast_out(i); if (out->Opcode() == Op_MemBarAcquire) { @@ -1043,7 +1043,7 @@ bool followed_by_acquire(const Node *load) { // edge to assure no other operations are in between the two nodes. // // So first get the Proj node, mem_proj, to use it to iterate forward. - Node *mem_proj = NULL; + Node *mem_proj = nullptr; for (DUIterator_Fast imax, i = mba->fast_outs(imax); i < imax; i++) { mem_proj = mba->fast_out(i); // Runs out of bounds and asserts if Proj not found. assert(mem_proj->is_Proj(), "only projections here"); @@ -1270,7 +1270,7 @@ source %{ void CallStubImpl::emit_trampoline_stub(C2_MacroAssembler &_masm, int destination_toc_offset, int insts_call_instruction_offset) { address stub = __ emit_trampoline_stub(destination_toc_offset, insts_call_instruction_offset); - if (stub == NULL) { + if (stub == nullptr) { ciEnv::current()->record_out_of_memory_failure(); } } @@ -1305,11 +1305,11 @@ EmitCallOffsets emit_call_with_trampoline_stub(C2_MacroAssembler &_masm, address offsets.insts_call_instruction_offset = __ offset(); // No entry point given, use the current pc. - if (entry_point == NULL) entry_point = __ pc(); + if (entry_point == nullptr) entry_point = __ pc(); // Put the entry point as a constant into the constant pool. const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none); - if (entry_point_toc_addr == NULL) { + if (entry_point_toc_addr == nullptr) { ciEnv::current()->record_out_of_memory_failure(); return offsets; } @@ -1355,8 +1355,8 @@ void MachConstantBaseNode::postalloc_expand(GrowableArray *nodes, Phase MachNode *m1 = new loadToc_hiNode(); MachNode *m2 = new loadToc_loNode(); - m1->add_req(NULL); - m2->add_req(NULL, m1); + m1->add_req(nullptr); + m2->add_req(nullptr, m1); m1->_opnds[0] = op_dst; m2->_opnds[0] = op_dst; m2->_opnds[1] = op_dst; @@ -1398,7 +1398,7 @@ void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const { st->print("push frame %ld\n\t", -framesize); } - if (C->stub_function() == NULL) { + if (C->stub_function() == nullptr) { st->print("nmethod entry barrier\n\t"); } } @@ -1554,7 +1554,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { __ std(return_pc, _abi0(lr), callers_sp); } - if (C->stub_function() == NULL) { + if (C->stub_function() == nullptr) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->nmethod_entry_barrier(&_masm, push_frame_temp); } @@ -1724,7 +1724,7 @@ uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, boo if (src_lo == dst_lo && src_hi == dst_hi) return size; // Self copy, no move. - if (bottom_type()->isa_vect() != NULL && ideal_reg() == Op_VecX) { + if (bottom_type()->isa_vect() != nullptr && ideal_reg() == Op_VecX) { // Memory->Memory Spill. if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { int src_offset = ra_->reg2offset(src_lo); @@ -1910,16 +1910,16 @@ void MachSpillCopyNode::format(PhaseRegAlloc *ra_, outputStream *st) const { if (!ra_) st->print("N%d = SpillCopy(N%d)", _idx, in(1)->_idx); else - implementation(NULL, ra_, false, st); + implementation(nullptr, ra_, false, st); } #endif void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - implementation(&cbuf, ra_, false, NULL); + implementation(&cbuf, ra_, false, nullptr); } uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { - return implementation(NULL, ra_, true, NULL); + return implementation(nullptr, ra_, true, nullptr); } #ifndef PRODUCT @@ -1978,42 +1978,7 @@ void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { // This is the unverified entry point. C2_MacroAssembler _masm(&cbuf); - // Inline_cache contains a klass. - Register ic_klass = as_Register(Matcher::inline_cache_reg_encode()); - Register receiver_klass = R12_scratch2; // tmp - - assert_different_registers(ic_klass, receiver_klass, R11_scratch1, R3_ARG1); - assert(R11_scratch1 == R11, "need prologue scratch register"); - - // Check for NULL argument if we don't have implicit null checks. - if (!ImplicitNullChecks || !os::zero_page_read_protected()) { - if (TrapBasedNullChecks) { - __ trap_null_check(R3_ARG1); - } else { - Label valid; - __ cmpdi(CCR0, R3_ARG1, 0); - __ bne_predict_taken(CCR0, valid); - // We have a null argument, branch to ic_miss_stub. - __ b64_patchable((address)SharedRuntime::get_ic_miss_stub(), - relocInfo::runtime_call_type); - __ bind(valid); - } - } - // Assume argument is not NULL, load klass from receiver. - __ load_klass(receiver_klass, R3_ARG1); - - if (TrapBasedICMissChecks) { - __ trap_ic_miss_check(receiver_klass, ic_klass); - } else { - Label valid; - __ cmpd(CCR0, receiver_klass, ic_klass); - __ beq_predict_taken(CCR0, valid); - // We have an unexpected klass, branch to ic_miss_stub. - __ b64_patchable((address)SharedRuntime::get_ic_miss_stub(), - relocInfo::runtime_call_type); - __ bind(valid); - } - + __ ic_check(CodeEntryAlignment); // Argument is valid and klass is as expected, continue. } @@ -2062,7 +2027,7 @@ int HandlerImpl::emit_exception_handler(CodeBuffer &cbuf) { C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_exception_handler()); - if (base == NULL) return 0; // CodeBuffer::expand failed + if (base == nullptr) return 0; // CodeBuffer::expand failed int offset = __ offset(); __ b64_patchable((address)OptoRuntime::exception_blob()->content_begin(), @@ -2079,7 +2044,7 @@ int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_deopt_handler()); - if (base == NULL) return 0; // CodeBuffer::expand failed + if (base == nullptr) return 0; // CodeBuffer::expand failed int offset = __ offset(); __ bl64_patchable((address)SharedRuntime::deopt_blob()->unpack(), @@ -2173,7 +2138,7 @@ bool Matcher::match_rule_supported(int opcode) { return true; // Per default match rules are supported. } -bool Matcher::match_rule_supported_superword(int opcode, int vlen, BasicType bt) { +bool Matcher::match_rule_supported_auto_vectorization(int opcode, int vlen, BasicType bt) { return match_rule_supported_vector(opcode, vlen, bt); } @@ -2193,11 +2158,11 @@ bool Matcher::vector_needs_partial_operations(Node* node, const TypeVect* vt) { } const RegMask* Matcher::predicate_reg_mask(void) { - return NULL; + return nullptr; } const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return NULL; + return nullptr; } // Vector calling convention not yet implemented. @@ -2242,7 +2207,7 @@ int Matcher::min_vector_size(const BasicType bt) { return max_vector_size(bt); // Same as max. } -int Matcher::superword_max_vector_size(const BasicType bt) { +int Matcher::max_vector_size_auto_vectorization(const BasicType bt) { return Matcher::max_vector_size(bt); } @@ -2275,7 +2240,7 @@ bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) { /* TODO: PPC port // Make a new machine dependent decode node (with its operands). MachTypeNode *Matcher::make_decode_node() { - assert(CompressedOops::base() == NULL && CompressedOops::shift() == 0, + assert(CompressedOops::base() == nullptr && CompressedOops::shift() == 0, "This method is only implemented for unscaled cOops mode so far"); MachTypeNode *decode = new decodeN_unscaledNode(); decode->set_opnd_array(0, new iRegPdstOper()); @@ -2286,7 +2251,7 @@ MachTypeNode *Matcher::make_decode_node() { MachOper* Matcher::pd_specialize_generic_vector_operand(MachOper* original_opnd, uint ideal_reg, bool is_temp) { ShouldNotReachHere(); // generic vector operands not supported - return NULL; + return nullptr; } bool Matcher::is_reg2reg_move(MachNode* m) { @@ -2545,7 +2510,7 @@ encode %{ // Create a non-oop constant, no relocation needed. // If it is an IC, it has a virtual_call_Relocation. const_toc_addr = __ long_constant((jlong)$src$$constant); - if (const_toc_addr == NULL) { + if (const_toc_addr == nullptr) { ciEnv::current()->record_out_of_memory_failure(); return; } @@ -2568,7 +2533,7 @@ encode %{ // Create a non-oop constant, no relocation needed. // If it is an IC, it has a virtual_call_Relocation. const_toc_addr = __ long_constant((jlong)$src$$constant); - if (const_toc_addr == NULL) { + if (const_toc_addr == nullptr) { ciEnv::current()->record_out_of_memory_failure(); return; } @@ -2607,8 +2572,8 @@ loadConLNodesTuple loadConLNodesTuple_create(PhaseRegAlloc *ra_, Node *toc, immL loadConL_loNode *m2 = new loadConL_loNode(); // inputs for new nodes - m1->add_req(NULL, toc); - m2->add_req(NULL, m1); + m1->add_req(nullptr, toc); + m2->add_req(nullptr, m1); // operands for new nodes m1->_opnds[0] = new iRegLdstOper(); // dst @@ -2632,14 +2597,14 @@ loadConLNodesTuple loadConLNodesTuple_create(PhaseRegAlloc *ra_, Node *toc, immL // Create result. nodes._large_hi = m1; nodes._large_lo = m2; - nodes._small = NULL; + nodes._small = nullptr; nodes._last = nodes._large_lo; assert(m2->bottom_type()->isa_long(), "must be long"); } else { loadConLNode *m2 = new loadConLNode(); // inputs for new nodes - m2->add_req(NULL, toc); + m2->add_req(nullptr, toc); // operands for new nodes m2->_opnds[0] = new iRegLdstOper(); // dst @@ -2653,8 +2618,8 @@ loadConLNodesTuple loadConLNodesTuple_create(PhaseRegAlloc *ra_, Node *toc, immL ra_->set_pair(m2->_idx, reg_second, reg_first); // Create result. - nodes._large_hi = NULL; - nodes._large_lo = NULL; + nodes._large_hi = nullptr; + nodes._large_lo = nullptr; nodes._small = m2; nodes._last = nodes._small; assert(m2->bottom_type()->isa_long(), "must be long"); @@ -2687,10 +2652,10 @@ loadConLReplicatedNodesTuple loadConLReplicatedNodesTuple_create(Compile *C, Pha xxspltdNode *m4 = new xxspltdNode(); // inputs for new nodes - m1->add_req(NULL, toc); - m2->add_req(NULL, m1); - m3->add_req(NULL, m2); - m4->add_req(NULL, m3); + m1->add_req(nullptr, toc); + m2->add_req(nullptr, m1); + m3->add_req(nullptr, m2); + m4->add_req(nullptr, m3); // operands for new nodes m1->_opnds[0] = new iRegLdstOper(); // dst @@ -2727,7 +2692,7 @@ loadConLReplicatedNodesTuple loadConLReplicatedNodesTuple_create(Compile *C, Pha nodes._large_lo = m2; nodes._moved = m3; nodes._replicated = m4; - nodes._small = NULL; + nodes._small = nullptr; nodes._last = nodes._replicated; assert(m2->bottom_type()->isa_long(), "must be long"); } else { @@ -2736,7 +2701,7 @@ loadConLReplicatedNodesTuple loadConLReplicatedNodesTuple_create(Compile *C, Pha xxspltdNode *m4 = new xxspltdNode(); // inputs for new nodes - m2->add_req(NULL, toc); + m2->add_req(nullptr, toc); // operands for new nodes m2->_opnds[0] = new iRegLdstOper(); // dst @@ -2760,8 +2725,8 @@ loadConLReplicatedNodesTuple loadConLReplicatedNodesTuple_create(Compile *C, Pha ra_->set_pair(m2->_idx, reg_second, reg_first); // Create result. - nodes._large_hi = NULL; - nodes._large_lo = NULL; + nodes._large_hi = nullptr; + nodes._large_lo = nullptr; nodes._small = m2; nodes._moved = m3; nodes._replicated = m4; @@ -2815,7 +2780,7 @@ encode %{ const_toc_addr = __ long_constant((jlong)$src$$constant); } - if (const_toc_addr == NULL) { + if (const_toc_addr == nullptr) { ciEnv::current()->record_out_of_memory_failure(); return; } @@ -2846,7 +2811,7 @@ encode %{ const_toc_addr = __ long_constant((jlong)$src$$constant); } - if (const_toc_addr == NULL) { + if (const_toc_addr == nullptr) { ciEnv::current()->record_out_of_memory_failure(); return; } @@ -2870,8 +2835,8 @@ encode %{ loadConP_loNode *m2 = new loadConP_loNode(); // inputs for new nodes - m1->add_req(NULL, n_toc); - m2->add_req(NULL, m1); + m1->add_req(nullptr, n_toc); + m2->add_req(nullptr, m1); // operands for new nodes m1->_opnds[0] = new iRegPdstOper(); // dst @@ -2896,7 +2861,7 @@ encode %{ loadConPNode *m2 = new loadConPNode(); // inputs for new nodes - m2->add_req(NULL, n_toc); + m2->add_req(nullptr, n_toc); // operands for new nodes m2->_opnds[0] = new iRegPdstOper(); // dst @@ -2923,7 +2888,7 @@ encode %{ m2 = new loadConFNode(); } // inputs for new nodes - m2->add_req(NULL, n_toc); + m2->add_req(nullptr, n_toc); // operands for new nodes m2->_opnds[0] = op_dst; @@ -2947,7 +2912,7 @@ encode %{ m2 = new loadConDNode(); } // inputs for new nodes - m2->add_req(NULL, n_toc); + m2->add_req(nullptr, n_toc); // operands for new nodes m2->_opnds[0] = op_dst; @@ -3258,9 +3223,9 @@ encode %{ Label d; // dummy __ bind(d); Label* p = ($lbl$$label); - // `p' is `NULL' when this encoding class is used only to + // `p' is `nullptr' when this encoding class is used only to // determine the size of the encoded instruction. - Label& l = (NULL == p)? d : *(p); + Label& l = (nullptr == p)? d : *(p); int cc = $cmp$$cmpcode; int flags_reg = $crx$$reg; assert((Assembler::bcondCRbiIs1 & ~Assembler::bcondCRbiIs0) == 8, "check encoding"); @@ -3287,9 +3252,9 @@ encode %{ Label d; // dummy __ bind(d); Label* p = ($lbl$$label); - // `p' is `NULL' when this encoding class is used only to + // `p' is `nullptr' when this encoding class is used only to // determine the size of the encoded instruction. - Label& l = (NULL == p)? d : *(p); + Label& l = (nullptr == p)? d : *(p); int cc = $cmp$$cmpcode; int flags_reg = $crx$$reg; int bhint = Assembler::bhintNoHint; @@ -3431,7 +3396,7 @@ encode %{ // Put the entry point as a constant into the constant pool. const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none); - if (entry_point_toc_addr == NULL) { + if (entry_point_toc_addr == nullptr) { ciEnv::current()->record_out_of_memory_failure(); return; } @@ -3452,8 +3417,8 @@ encode %{ __ bl(__ pc()); // Emits a relocation. // The stub for call to interpreter. - address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); - if (stub == NULL) { + address stub = CompiledDirectCall::emit_to_interp_stub(cbuf); + if (stub == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -3470,7 +3435,7 @@ encode %{ // Create a call trampoline stub for the given method. const address entry_point = !($meth$$method) ? 0 : (address)$meth$$method; const address entry_point_const = __ address_constant(entry_point, RelocationHolder::none); - if (entry_point_const == NULL) { + if (entry_point_const == nullptr) { ciEnv::current()->record_out_of_memory_failure(); return; } @@ -3479,13 +3444,13 @@ encode %{ if (ra_->C->env()->failing()) { return; } // Code cache may be full. // Build relocation at call site with ic position as data. - assert((_load_ic_hi_node != NULL && _load_ic_node == NULL) || - (_load_ic_hi_node == NULL && _load_ic_node != NULL), + assert((_load_ic_hi_node != nullptr && _load_ic_node == nullptr) || + (_load_ic_hi_node == nullptr && _load_ic_node != nullptr), "must have one, but can't have both"); - assert((_load_ic_hi_node != NULL && _load_ic_hi_node->_cbuf_insts_offset != -1) || - (_load_ic_node != NULL && _load_ic_node->_cbuf_insts_offset != -1), + assert((_load_ic_hi_node != nullptr && _load_ic_hi_node->_cbuf_insts_offset != -1) || + (_load_ic_node != nullptr && _load_ic_node->_cbuf_insts_offset != -1), "must contain instruction offset"); - const int virtual_call_oop_addr_offset = _load_ic_hi_node != NULL + const int virtual_call_oop_addr_offset = _load_ic_hi_node != nullptr ? _load_ic_hi_node->_cbuf_insts_offset : _load_ic_node->_cbuf_insts_offset; const address virtual_call_oop_addr = __ addr_at(virtual_call_oop_addr_offset); @@ -3507,7 +3472,7 @@ encode %{ // Create the nodes for loading the IC from the TOC. loadConLNodesTuple loadConLNodes_IC = - loadConLNodesTuple_create(ra_, n_toc, new immLOper((jlong)Universe::non_oop_word()), + loadConLNodesTuple_create(ra_, n_toc, new immLOper((jlong) Universe::non_oop_word()), OptoReg::Name(R19_H_num), OptoReg::Name(R19_num)); // Create the call node. @@ -3625,7 +3590,7 @@ encode %{ const address start_pc = __ pc(); #if defined(ABI_ELFv2) - address entry= !($meth$$method) ? NULL : (address)$meth$$method; + address entry= !($meth$$method) ? nullptr : (address)$meth$$method; __ call_c(entry, relocInfo::runtime_call_type); __ post_call_nop(); #else @@ -3682,13 +3647,13 @@ encode %{ // Create nodes and operands for loading the env pointer. - if (fd->env() != NULL) { + if (fd->env() != nullptr) { loadConLNodes_Env = loadConLNodesTuple_create(ra_, n_toc, new immLOper((jlong) fd->env()), OptoReg::Name(R11_H_num), OptoReg::Name(R11_num)); } else { - loadConLNodes_Env._large_hi = NULL; - loadConLNodes_Env._large_lo = NULL; - loadConLNodes_Env._small = NULL; + loadConLNodes_Env._large_hi = nullptr; + loadConLNodes_Env._large_lo = nullptr; + loadConLNodes_Env._small = nullptr; loadConLNodes_Env._last = new loadConL16Node(); loadConLNodes_Env._last->_opnds[0] = new iRegLdstOper(); loadConLNodes_Env._last->_opnds[1] = new immL16Oper(0); @@ -3702,7 +3667,7 @@ encode %{ // mtctr node MachNode *mtctr = new CallLeafDirect_mtctrNode(); - assert(loadConLNodes_Entry._last != NULL, "entry must exist"); + assert(loadConLNodes_Entry._last != nullptr, "entry must exist"); mtctr->add_req(0, loadConLNodes_Entry._last); mtctr->_opnds[0] = new iRegLdstOper(); @@ -3722,7 +3687,7 @@ encode %{ call->_guaranteed_safepoint = false; call->_oop_map = _oop_map; guarantee(!_jvms, "You must clone the jvms and adapt the offsets by fix_jvms()."); - call->_jvms = NULL; + call->_jvms = nullptr; call->_jvmadj = _jvmadj; call->_in_rms = _in_rms; call->_nesting = _nesting; @@ -3826,7 +3791,7 @@ frame %{ // opcodes. This simplifies the register allocator. c_return_value %{ assert((ideal_reg >= Op_RegI && ideal_reg <= Op_RegL) || - (ideal_reg == Op_RegN && CompressedOops::base() == NULL && CompressedOops::shift() == 0), + (ideal_reg == Op_RegN && CompressedOops::base() == nullptr && CompressedOops::shift() == 0), "only return normal values"); // enum names from opcodes.hpp: Op_Node Op_Set Op_RegN Op_RegI Op_RegP Op_RegF Op_RegD Op_RegL static int typeToRegLo[Op_RegL+1] = { 0, 0, R3_num, R3_num, R3_num, F1_num, F1_num, R3_num }; @@ -3837,7 +3802,7 @@ frame %{ // Location of compiled Java return values. Same as C return_value %{ assert((ideal_reg >= Op_RegI && ideal_reg <= Op_RegL) || - (ideal_reg == Op_RegN && CompressedOops::base() == NULL && CompressedOops::shift() == 0), + (ideal_reg == Op_RegN && CompressedOops::base() == nullptr && CompressedOops::shift() == 0), "only return normal values"); // enum names from opcodes.hpp: Op_Node Op_Set Op_RegN Op_RegI Op_RegP Op_RegF Op_RegD Op_RegL static int typeToRegLo[Op_RegL+1] = { 0, 0, R3_num, R3_num, R3_num, F1_num, F1_num, R3_num }; @@ -4110,7 +4075,7 @@ operand immN() %{ interface(CONST_INTER); %} -// NULL Pointer Immediate +// Null Pointer Immediate operand immN_0() %{ predicate(n->get_narrowcon() == 0); match(ConN); @@ -4682,7 +4647,7 @@ operand iRegN2P(iRegNsrc reg) %{ %} operand iRegN2P_klass(iRegNsrc reg) %{ - predicate(CompressedKlassPointers::base() == NULL && CompressedKlassPointers::shift() == 0); + predicate(CompressedKlassPointers::base() == nullptr && CompressedKlassPointers::shift() == 0); constraint(ALLOC_IN_RC(bits32_reg_ro)); match(DecodeNKlass reg); format %{ "$reg" %} @@ -4751,7 +4716,7 @@ operand indirectNarrow(iRegNsrc reg) %{ %} operand indirectNarrow_klass(iRegNsrc reg) %{ - predicate(CompressedKlassPointers::base() == NULL && CompressedKlassPointers::shift() == 0); + predicate(CompressedKlassPointers::base() == nullptr && CompressedKlassPointers::shift() == 0); constraint(ALLOC_IN_RC(bits64_reg_ro)); match(DecodeNKlass reg); op_cost(100); @@ -4780,7 +4745,7 @@ operand indOffset16Narrow(iRegNsrc reg, immL16 offset) %{ %} operand indOffset16Narrow_klass(iRegNsrc reg, immL16 offset) %{ - predicate(CompressedKlassPointers::base() == NULL && CompressedKlassPointers::shift() == 0); + predicate(CompressedKlassPointers::base() == nullptr && CompressedKlassPointers::shift() == 0); constraint(ALLOC_IN_RC(bits64_reg_ro)); match(AddP (DecodeNKlass reg) offset); op_cost(100); @@ -4809,7 +4774,7 @@ operand indOffset16NarrowAlg4(iRegNsrc reg, immL16Alg4 offset) %{ %} operand indOffset16NarrowAlg4_klass(iRegNsrc reg, immL16Alg4 offset) %{ - predicate(CompressedKlassPointers::base() == NULL && CompressedKlassPointers::shift() == 0); + predicate(CompressedKlassPointers::base() == nullptr && CompressedKlassPointers::shift() == 0); constraint(ALLOC_IN_RC(bits64_reg_ro)); match(AddP (DecodeNKlass reg) offset); op_cost(100); @@ -5544,7 +5509,7 @@ instruct loadN2P_unscaled(iRegPdst dst, memory mem) %{ instruct loadN2P_klass_unscaled(iRegPdst dst, memory mem) %{ match(Set dst (DecodeNKlass (LoadNKlass mem))); - predicate(CompressedKlassPointers::base() == NULL && CompressedKlassPointers::shift() == 0 && + predicate(CompressedKlassPointers::base() == nullptr && CompressedKlassPointers::shift() == 0 && _kids[0]->_leaf->as_Load()->is_unordered()); ins_cost(MEMORY_REF_COST); @@ -5954,7 +5919,7 @@ instruct loadConL_Ex(iRegLdst dst, immL src) %{ postalloc_expand( postalloc_expand_load_long_constant(dst, src, constanttablebase) ); %} -// Load NULL as compressed oop. +// Load nullptr as compressed oop. instruct loadConN0(iRegNdst dst, immN_0 src) %{ match(Set dst src); ins_cost(DEFAULT_COST); @@ -6045,9 +6010,9 @@ instruct loadConN_Ex(iRegNdst dst, immN src) %{ MachNode *m1 = new loadConN_hiNode(); MachNode *m2 = new loadConN_loNode(); MachNode *m3 = new clearMs32bNode(); - m1->add_req(NULL); - m2->add_req(NULL, m1); - m3->add_req(NULL, m2); + m1->add_req(nullptr); + m2->add_req(nullptr, m1); + m3->add_req(nullptr, m2); m1->_opnds[0] = op_dst; m1->_opnds[1] = op_src; m2->_opnds[0] = op_dst; @@ -6123,7 +6088,7 @@ instruct loadConNKlass_Ex(iRegNdst dst, immNKlass src) %{ postalloc_expand %{ // Load high bits into register. Sign extended. MachNode *m1 = new loadConNKlass_hiNode(); - m1->add_req(NULL); + m1->add_req(nullptr); m1->_opnds[0] = op_dst; m1->_opnds[1] = op_src; ra_->set_pair(m1->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); @@ -6133,7 +6098,7 @@ instruct loadConNKlass_Ex(iRegNdst dst, immNKlass src) %{ if (!Assembler::is_uimm((jlong)CompressedKlassPointers::encode((Klass *)op_src->constant()), 31)) { // Value might be 1-extended. Mask out these bits. m2 = new loadConNKlass_maskNode(); - m2->add_req(NULL, m1); + m2->add_req(nullptr, m1); m2->_opnds[0] = op_dst; m2->_opnds[1] = op_src; m2->_opnds[2] = op_dst; @@ -6142,7 +6107,7 @@ instruct loadConNKlass_Ex(iRegNdst dst, immNKlass src) %{ } MachNode *m3 = new loadConNKlass_loNode(); - m3->add_req(NULL, m2); + m3->add_req(nullptr, m2); m3->_opnds[0] = op_dst; m3->_opnds[1] = op_src; m3->_opnds[2] = op_dst; @@ -6243,7 +6208,7 @@ instruct loadConF(regF dst, immF src, iRegLdst toc) %{ size(4); ins_encode %{ address float_address = __ float_constant($src$$constant); - if (float_address == NULL) { + if (float_address == nullptr) { ciEnv::current()->record_out_of_memory_failure(); return; } @@ -6267,7 +6232,7 @@ instruct loadConFComp(regF dst, immF src, iRegLdst toc) %{ FloatRegister Rdst = $dst$$FloatRegister; Register Rtoc = $toc$$Register; address float_address = __ float_constant($src$$constant); - if (float_address == NULL) { + if (float_address == nullptr) { ciEnv::current()->record_out_of_memory_failure(); return; } @@ -6305,7 +6270,7 @@ instruct loadConD(regD dst, immD src, iRegLdst toc) %{ size(4); ins_encode %{ address float_address = __ double_constant($src$$constant); - if (float_address == NULL) { + if (float_address == nullptr) { ciEnv::current()->record_out_of_memory_failure(); return; } @@ -6330,7 +6295,7 @@ instruct loadConDComp(regD dst, immD src, iRegLdst toc) %{ FloatRegister Rdst = $dst$$FloatRegister; Register Rtoc = $toc$$Register; address float_address = __ double_constant($src$$constant); - if (float_address == NULL) { + if (float_address == nullptr) { ciEnv::current()->record_out_of_memory_failure(); return; } @@ -6632,7 +6597,7 @@ instruct cond_sub_base(iRegNdst dst, flagsRegSrc crx, iRegPsrc src1) %{ predicate(false); format %{ "BEQ $crx, done\n\t" - "SUB $dst, $src1, heapbase \t// encode: subtract base if != NULL\n" + "SUB $dst, $src1, heapbase \t// encode: subtract base if != nullptr\n" "done:" %} ins_encode %{ Label done; @@ -6701,7 +6666,7 @@ instruct encodeP_not_null_base_null(iRegNdst dst, iRegPsrc src) %{ predicate(CompressedOops::shift() != 0 && CompressedOops::base() ==0); - format %{ "SRDI $dst, $src, #3 \t// encodeP, $src != NULL" %} + format %{ "SRDI $dst, $src, #3 \t// encodeP, $src != nullptr" %} size(4); ins_encode %{ __ srdi($dst$$Register, $src$$Register, CompressedOops::shift() & 0x3f); @@ -6762,7 +6727,7 @@ instruct cond_add_base(iRegPdst dst, flagsRegSrc crx, iRegPsrc src) %{ predicate(false); format %{ "BEQ $crx, done\n\t" - "ADD $dst, $src, heapbase \t// DecodeN: add oop base if $src != NULL\n" + "ADD $dst, $src, heapbase \t// DecodeN: add oop base if $src != nullptr\n" "done:" %} ins_encode %{ Label done; @@ -6850,7 +6815,7 @@ instruct decodeN_Disjoint_notNull_Ex(iRegPdst dst, iRegNsrc src) %{ "RLDIMI $dst, $src, shift, 32-shift \t// decode with disjoint base" %} postalloc_expand %{ loadBaseNode *n1 = new loadBaseNode(); - n1->add_req(NULL); + n1->add_req(nullptr); n1->_opnds[0] = op_dst; decodeN_mergeDisjointNode *n2 = new decodeN_mergeDisjointNode(); @@ -6882,7 +6847,7 @@ instruct decodeN_Disjoint_isel_Ex(iRegPdst dst, iRegNsrc src, flagsReg crx) %{ format %{ "DecodeN $dst, $src \t// decode with disjoint base using isel" %} postalloc_expand %{ loadBaseNode *n1 = new loadBaseNode(); - n1->add_req(NULL); + n1->add_req(nullptr); n1->_opnds[0] = op_dst; cmpN_reg_imm0Node *n_compare = new cmpN_reg_imm0Node(); @@ -6929,7 +6894,7 @@ instruct decodeN_notNull_addBase_Ex(iRegPdst dst, iRegNsrc src) %{ CompressedOops::base() != 0); ins_cost(2 * DEFAULT_COST); - format %{ "DecodeN $dst, $src \t// $src != NULL, postalloc expanded" %} + format %{ "DecodeN $dst, $src \t// $src != nullptr, postalloc expanded" %} postalloc_expand( postalloc_expand_decode_oop_not_null(dst, src)); %} @@ -7086,7 +7051,7 @@ instruct decodeNKlass_notNull_addBase_Ex(iRegPdst dst, iRegLsrc base, iRegNsrc s //effect(kill src); // We need a register for the immediate result after shifting. predicate(false); - format %{ "DecodeNKlass $dst = $base + ($src << 3) \t// $src != NULL, postalloc expanded" %} + format %{ "DecodeNKlass $dst = $base + ($src << 3) \t// $src != nullptr, postalloc expanded" %} postalloc_expand %{ decodeNKlass_add_baseNode *n1 = new decodeNKlass_add_baseNode(); n1->add_req(n_region, n_base, n_src); @@ -7115,7 +7080,7 @@ instruct decodeNKlass_notNull_addBase_ExEx(iRegPdst dst, iRegNsrc src) %{ // predicate(CompressedKlassPointers::shift() != 0 && // CompressedKlassPointers::base() != 0); - //format %{ "DecodeNKlass $dst, $src \t// $src != NULL, expanded" %} + //format %{ "DecodeNKlass $dst, $src \t// $src != nullptr, expanded" %} ins_cost(DEFAULT_COST*2); // Don't count constant. expand %{ @@ -7602,7 +7567,7 @@ instruct compareAndSwapL_regP_regL_regL(iRegIdst res, iRegPdst mem_ptr, iRegLsrc // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgd(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - $res$$Register, NULL, true); + $res$$Register, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -7621,7 +7586,7 @@ instruct compareAndSwapP_regP_regP_regP(iRegIdst res, iRegPdst mem_ptr, iRegPsrc // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgd(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - $res$$Register, NULL, true); + $res$$Register, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -7815,7 +7780,7 @@ instruct weakCompareAndSwapL_regP_regL_regL(iRegIdst res, iRegPdst mem_ptr, iReg // value is never passed to caller. __ cmpxchgd(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, NULL, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7831,7 +7796,7 @@ instruct weakCompareAndSwapL_acq_regP_regL_regL(iRegIdst res, iRegPdst mem_ptr, // value is never passed to caller. __ cmpxchgd(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, NULL, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7845,7 +7810,7 @@ instruct weakCompareAndSwapP_regP_regP_regP(iRegIdst res, iRegPdst mem_ptr, iReg // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgd(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, NULL, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7861,7 +7826,7 @@ instruct weakCompareAndSwapP_acq_regP_regP_regP(iRegIdst res, iRegPdst mem_ptr, // value is never passed to caller. __ cmpxchgd(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, NULL, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -8081,7 +8046,7 @@ instruct compareAndExchangeL_regP_regL_regL(iRegLdst res, iRegPdst mem_ptr, iReg // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgd(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, NULL, true); + noreg, nullptr, true); %} ins_pipe(pipe_class_default); %} @@ -8095,7 +8060,7 @@ instruct compareAndExchangeL_acq_regP_regL_regL(iRegLdst res, iRegPdst mem_ptr, // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgd(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, NULL, true); + noreg, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -8116,7 +8081,7 @@ instruct compareAndExchangeP_regP_regP_regP(iRegPdst res, iRegPdst mem_ptr, iReg // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgd(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, NULL, true); + noreg, nullptr, true); %} ins_pipe(pipe_class_default); %} @@ -8131,7 +8096,7 @@ instruct compareAndExchangeP_acq_regP_regP_regP(iRegPdst res, iRegPdst mem_ptr, // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgd(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, NULL, true); + noreg, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -12043,9 +12008,9 @@ instruct branch(label labl) %{ Label d; // dummy __ bind(d); Label* p = $labl$$label; - // `p' is `NULL' when this encoding class is used only to + // `p' is `nullptr' when this encoding class is used only to // determine the size of the encoded instruction. - Label& l = (NULL == p)? d : *(p); + Label& l = (nullptr == p)? d : *(p); __ b(l); %} ins_pipe(pipe_class_default); @@ -12139,7 +12104,7 @@ instruct partialSubtypeCheck(iRegPdst result, iRegP_N2P subklass, iRegP_N2P supe format %{ "PartialSubtypeCheck $result = ($subklass instanceOf $superklass) tmp: $tmp_klass, $tmp_arrayptr" %} ins_encode %{ __ check_klass_subtype_slow_path($subklass$$Register, $superklass$$Register, $tmp_arrayptr$$Register, - $tmp_klass$$Register, NULL, $result$$Register); + $tmp_klass$$Register, nullptr, $result$$Register); %} ins_pipe(pipe_class_default); %} @@ -12318,21 +12283,6 @@ instruct string_equalsL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt, iRegIdst ins_pipe(pipe_class_default); %} -instruct string_equalsU(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt, iRegIdst result, - iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ - predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU); - match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP tmp, KILL ctr, KILL cr0); - ins_cost(300); - format %{ "String Equals char[] $str1,$str2,$cnt -> $result \t// KILL $tmp" %} - ins_encode %{ - __ array_equals(false, $str1$$Register, $str2$$Register, - $cnt$$Register, $tmp$$Register, - $result$$Register, false /* byte */); - %} - ins_pipe(pipe_class_default); -%} - instruct array_equalsB(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result, iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR0 cr1) %{ predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); @@ -12670,7 +12620,7 @@ instruct indexOf_U(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iRe ins_encode %{ __ string_indexof($result$$Register, $haystack$$Register, $haycnt$$Register, - $needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant. + $needle$$Register, nullptr, $needlecnt$$Register, 0, // needlecnt not constant. $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UU); %} ins_pipe(pipe_class_compare); @@ -12691,7 +12641,7 @@ instruct indexOf_L(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iRe ins_encode %{ __ string_indexof($result$$Register, $haystack$$Register, $haycnt$$Register, - $needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant. + $needle$$Register, nullptr, $needlecnt$$Register, 0, // needlecnt not constant. $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::LL); %} ins_pipe(pipe_class_compare); @@ -12712,7 +12662,7 @@ instruct indexOf_UL(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iR ins_encode %{ __ string_indexof($result$$Register, $haystack$$Register, $haycnt$$Register, - $needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant. + $needle$$Register, nullptr, $needlecnt$$Register, 0, // needlecnt not constant. $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UL); %} ins_pipe(pipe_class_compare); diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 3382df355da..5a080adc7a9 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -27,7 +27,6 @@ #include "asm/macroAssembler.inline.hpp" #include "code/debugInfoRec.hpp" #include "code/compiledIC.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "frame_ppc.hpp" #include "compiler/oopMap.hpp" @@ -35,7 +34,6 @@ #include "interpreter/interpreter.hpp" #include "interpreter/interp_masm.hpp" #include "memory/resourceArea.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/klass.inline.hpp" #include "prims/methodHandles.hpp" #include "runtime/continuation.hpp" @@ -1174,8 +1172,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm BLOCK_COMMENT("c2i unverified entry"); c2i_unverified_entry = __ pc(); - // inline_cache contains a compiledICHolder - const Register ic = R19_method; + // inline_cache contains a CompiledICData + const Register ic = R19_inline_cache_reg; const Register ic_klass = R11_scratch1; const Register receiver_klass = R12_scratch2; const Register code = R21_tmp1; @@ -1186,45 +1184,10 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm Label call_interpreter; - assert(!MacroAssembler::needs_explicit_null_check(oopDesc::klass_offset_in_bytes()), - "klass offset should reach into any page"); - // Check for null argument if we don't have implicit null checks. - if (!ImplicitNullChecks || !os::zero_page_read_protected()) { - if (TrapBasedNullChecks) { - __ trap_null_check(R3_ARG1); - } else { - Label valid; - __ cmpdi(CCR0, R3_ARG1, 0); - __ bne_predict_taken(CCR0, valid); - // We have a null argument, branch to ic_miss_stub. - __ b64_patchable((address)SharedRuntime::get_ic_miss_stub(), - relocInfo::runtime_call_type); - __ BIND(valid); - } - } - // Assume argument is not null, load klass from receiver. - __ load_klass(receiver_klass, R3_ARG1); - - __ ld(ic_klass, CompiledICHolder::holder_klass_offset(), ic); - - if (TrapBasedICMissChecks) { - __ trap_ic_miss_check(receiver_klass, ic_klass); - } else { - Label valid; - __ cmpd(CCR0, receiver_klass, ic_klass); - __ beq_predict_taken(CCR0, valid); - // We have an unexpected klass, branch to ic_miss_stub. - __ b64_patchable((address)SharedRuntime::get_ic_miss_stub(), - relocInfo::runtime_call_type); - __ BIND(valid); - } - + __ ic_check(4 /* end_alignment */); + __ ld(R19_method, CompiledICData::speculated_method_offset(), ic); // Argument is valid and klass is as expected, continue. - // Extract method from inline cache, verified entry point needs it. - __ ld(R19_method, CompiledICHolder::holder_metadata_offset(), ic); - assert(R19_method == ic, "the inline cache register is dead here"); - __ ld(code, method_(code)); __ cmpdi(CCR0, code, 0); __ ld(ientry, method_(interpreter_entry)); // preloaded @@ -1798,7 +1761,7 @@ static void gen_continuation_enter(MacroAssembler* masm, // static stub for the call above CodeBuffer* cbuf = masm->code_section()->outer(); - stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, c2i_call_pc); + stub = CompiledDirectCall::emit_to_interp_stub(*cbuf, c2i_call_pc); guarantee(stub != nullptr, "no space for static stub"); } @@ -1891,7 +1854,7 @@ static void gen_continuation_enter(MacroAssembler* masm, // static stub for the call above CodeBuffer* cbuf = masm->code_section()->outer(); - stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, call_pc); + stub = CompiledDirectCall::emit_to_interp_stub(*cbuf, call_pc); guarantee(stub != nullptr, "no space for static stub"); } @@ -2039,6 +2002,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, in_ByteSize(-1), oop_maps, exception_offset); + if (nm == nullptr) return nm; if (method->is_continuation_enter_intrinsic()) { ContinuationEntry::set_enter_code(nm, interpreted_entry_offset); } else if (method->is_continuation_yield_intrinsic()) { @@ -2187,7 +2151,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, intptr_t frame_done_pc; intptr_t oopmap_pc; - Label ic_miss; Label handle_pending_exception; Register r_callers_sp = R21; @@ -2211,19 +2174,9 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // Check ic: object class == cached class? if (!method_is_static) { - Register ic = R19_inline_cache_reg; - Register receiver_klass = r_temp_1; - - __ cmpdi(CCR0, R3_ARG1, 0); - __ beq(CCR0, ic_miss); - __ verify_oop(R3_ARG1, FILE_AND_LINE); - __ load_klass(receiver_klass, R3_ARG1); - - __ cmpd(CCR0, receiver_klass, ic); - __ bne(CCR0, ic_miss); + __ ic_check(4 /* end_alignment */); } - // Generate the Verified Entry Point (VEP). // -------------------------------------------------------------------------- vep_start_pc = (intptr_t)__ pc(); @@ -2703,16 +2656,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ b64_patchable((address)StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type); - // Handler for a cache miss (out-of-line). - // -------------------------------------------------------------------------- - - if (!method_is_static) { - __ bind(ic_miss); - - __ b64_patchable((address)SharedRuntime::get_ic_miss_stub(), - relocInfo::runtime_call_type); - } - // Done. // -------------------------------------------------------------------------- diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index e26f03f52d8..094757ad3e1 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -3643,8 +3643,6 @@ class StubGenerator: public StubCodeGenerator { #define VALID_B64 0x80 #define VB64(x) (VALID_B64 | x) -#define VEC_ALIGN __attribute__ ((aligned(16))) - #define BLK_OFFSETOF(x) (offsetof(constant_block, x)) // In little-endian mode, the lxv instruction loads the element at EA into @@ -3681,7 +3679,7 @@ class StubGenerator: public StubCodeGenerator { unsigned char pack_permute_val[16]; } constant_block; - static const constant_block VEC_ALIGN const_block = { + alignas(16) static const constant_block const_block = { .offsetLUT_val = { ARRAY_TO_LXV_ORDER( @@ -4263,7 +4261,7 @@ class StubGenerator: public StubCodeGenerator { unsigned char base64_48_63_URL_val[16]; } constant_block; - static const constant_block VEC_ALIGN const_block = { + alignas(16) static const constant_block const_block = { .expand_permute_val = { ARRAY_TO_LXV_ORDER( 0, 4, 5, 6, diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp index 84ecfc4f934..86353aefb36 100644 --- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2013, 2023 SAP SE. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3803,16 +3803,15 @@ void TemplateTable::_new() { __ sldi(Roffset, Rindex, LogBytesPerWord); __ load_resolved_klass_at_offset(Rcpool, Roffset, RinstanceKlass); - // Make sure klass is fully initialized and get instance_size. - __ lbz(Rscratch, in_bytes(InstanceKlass::init_state_offset()), RinstanceKlass); + // Make sure klass is initialized. + assert(VM_Version::supports_fast_class_init_checks(), "Optimization requires support for fast class initialization checks"); + __ clinit_barrier(RinstanceKlass, R16_thread, nullptr /*L_fast_path*/, &Lslow_case); + __ lwz(Rinstance_size, in_bytes(Klass::layout_helper_offset()), RinstanceKlass); - __ cmpdi(CCR1, Rscratch, InstanceKlass::fully_initialized); // Make sure klass does not have has_finalizer, or is abstract, or interface or java/lang/Class. __ andi_(R0, Rinstance_size, Klass::_lh_instance_slow_path_bit); // slow path bit equals 0? - - __ crnand(CCR0, Assembler::equal, CCR1, Assembler::equal); // slow path bit set or not fully initialized? - __ beq(CCR0, Lslow_case); + __ bne(CCR0, Lslow_case); // -------------------------------------------------------------------------- // Fast case: diff --git a/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp b/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp index fe4eb3df8f1..28ba04d833b 100644 --- a/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp @@ -25,10 +25,10 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "code/compiledIC.hpp" #include "code/vtableStubs.hpp" #include "interp_masm_ppc.hpp" #include "memory/resourceArea.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/klassVtable.hpp" @@ -181,13 +181,13 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { __ load_klass_check_null(rcvr_klass, R3_ARG1); // Receiver subtype check against REFC. - __ ld(interface, CompiledICHolder::holder_klass_offset(), R19_method); + __ ld(interface, CompiledICData::itable_refc_klass_offset(), R19_method); __ lookup_interface_method(rcvr_klass, interface, noreg, R0, tmp1, tmp2, L_no_such_interface, /*return_method=*/ false); // Get Method* and entrypoint for compiler - __ ld(interface, CompiledICHolder::holder_metadata_offset(), R19_method); + __ ld(interface, CompiledICData::itable_defc_klass_offset(), R19_method); __ lookup_interface_method(rcvr_klass, interface, itable_index, R19_method, tmp1, tmp2, L_no_such_interface, /*return_method=*/ true); diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 0bbf3771a04..e3ec023aef2 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -51,7 +51,6 @@ #endif NEEDS_CLEANUP // remove this definitions ? -const Register IC_Klass = t1; // where the IC klass is cached const Register SYNC_header = x10; // synchronization header const Register SHIFT_count = x10; // where count for shift operations must be @@ -265,26 +264,7 @@ void LIR_Assembler::osr_entry() { // inline cache check; done before the frame is built. int LIR_Assembler::check_icache() { - Register receiver = FrameMap::receiver_opr->as_register(); - Register ic_klass = IC_Klass; - int start_offset = __ offset(); - Label dont; - __ inline_cache_check(receiver, ic_klass, dont); - - // if icache check fails, then jump to runtime routine - // Note: RECEIVER must still contain the receiver! - __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); - - // We align the verified entry point unless the method body - // (including its inline cache check) will fit in a single 64-byte - // icache line. - if (!method()->is_accessor() || __ offset() - start_offset > 4 * 4) { - // force alignment after the cache check. - __ align(CodeEntryAlignment); - } - - __ bind(dont); - return start_offset; + return __ ic_check(CodeEntryAlignment); } void LIR_Assembler::jobject2reg(jobject o, Register reg) { @@ -1398,7 +1378,7 @@ void LIR_Assembler::emit_static_call_stub() { __ relocate(static_stub_Relocation::spec(call_pc)); __ emit_static_call_stub(); - assert(__ offset() - start + CompiledStaticCall::to_trampoline_stub_size() + assert(__ offset() - start + CompiledDirectCall::to_trampoline_stub_size() <= call_stub_size(), "stub too big"); __ end_a_stub(); } diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp index b088498e6fc..ce23213776c 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp @@ -68,7 +68,7 @@ friend class ArrayCopyStub; enum { // See emit_static_call_stub for detail - // CompiledStaticCall::to_interp_stub_size() (14) + CompiledStaticCall::to_trampoline_stub_size() (1 + 3 + address) + // CompiledDirectCall::to_interp_stub_size() (14) + CompiledDirectCall::to_trampoline_stub_size() (1 + 3 + address) _call_stub_size = 14 * NativeInstruction::instruction_size + (NativeInstruction::instruction_size + NativeCallTrampolineStub::instruction_size), // See emit_exception_handler for detail diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp index 6c1dce0de15..2961b1a91ce 100644 --- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp @@ -314,15 +314,6 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register tmp1 verify_oop(obj); } -void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache, Label &L) { - verify_oop(receiver); - // explicit null check not needed since load from [klass_offset] causes a trap - // check against inline cache - assert(!MacroAssembler::needs_explicit_null_check(oopDesc::klass_offset_in_bytes()), "must add explicit null check"); - assert_different_registers(receiver, iCache, t0, t2); - cmp_klass(receiver, iCache, t0, t2 /* call-clobbered t2 as a tmp */, L); -} - void C1_MacroAssembler::build_frame(int framesize, int bang_size_in_bytes) { assert(bang_size_in_bytes >= framesize, "stack bang size incorrect"); // Make sure there is enough stack space for this method's activation. diff --git a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp index b76163a3084..9fa8939837a 100644 --- a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp @@ -37,7 +37,6 @@ #include "interpreter/interpreter.hpp" #include "memory/universe.hpp" #include "nativeInst_riscv.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "register_riscv.hpp" diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 0617c37687f..9670bc987a3 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, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -121,10 +121,10 @@ void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg, // Handle existing monitor. bind(object_has_monitor); - // The object's monitor m is unlocked iff m->owner == NULL, + // The object's monitor m is unlocked iff m->owner == nullptr, // otherwise m->owner may contain a thread or a stack address. // - // Try to CAS m->owner from NULL to current thread. + // Try to CAS m->owner from null to current thread. add(tmp, disp_hdr, (in_bytes(ObjectMonitor::owner_offset()) - markWord::monitor_value)); cmpxchg(/*memory address*/tmp, /*expected value*/zr, /*new value*/xthread, Assembler::int64, Assembler::aq, Assembler::rl, /*result*/flag); // cas succeeds if flag == zr(expected) @@ -1358,7 +1358,6 @@ void C2_MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3, // For Strings we're passed the address of the first characters in a1 // and a2 and the length in cnt1. -// elem_size is the element size in bytes: either 1 or 2. // There are two implementations. For arrays >= 8 bytes, all // comparisons (for hw supporting unaligned access: including the final one, // which may overlap) are performed 8 bytes at a time. @@ -1367,13 +1366,12 @@ void C2_MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3, // halfword, then a short, and then a byte. void C2_MacroAssembler::string_equals(Register a1, Register a2, - Register result, Register cnt1, int elem_size) + Register result, Register cnt1) { Label SAME, DONE, SHORT, NEXT_WORD; Register tmp1 = t0; Register tmp2 = t1; - assert(elem_size == 1 || elem_size == 2, "must be 2 or 1 byte"); assert_different_registers(a1, a2, result, cnt1, tmp1, tmp2); BLOCK_COMMENT("string_equals {"); @@ -1439,15 +1437,13 @@ void C2_MacroAssembler::string_equals(Register a1, Register a2, } bind(TAIL01); - if (elem_size == 1) { // Only needed when comparing 1-byte elements - // 0-1 bytes left. - test_bit(tmp1, cnt1, 0); - beqz(tmp1, SAME); - { - lbu(tmp1, Address(a1, 0)); - lbu(tmp2, Address(a2, 0)); - bne(tmp1, tmp2, DONE); - } + // 0-1 bytes left. + test_bit(tmp1, cnt1, 0); + beqz(tmp1, SAME); + { + lbu(tmp1, Address(a1, 0)); + lbu(tmp2, Address(a2, 0)); + bne(tmp1, tmp2, DONE); } // Arrays are equal. @@ -1829,6 +1825,49 @@ void C2_MacroAssembler::float16_to_float(FloatRegister dst, Register src, Regist bind(stub->continuation()); } +static void float_to_float16_slow_path(C2_MacroAssembler& masm, C2GeneralStub& stub) { +#define __ masm. + Register dst = stub.data<0>(); + FloatRegister src = stub.data<1>(); + Register tmp = stub.data<2>(); + __ bind(stub.entry()); + + __ fmv_x_w(dst, src); + + // preserve the payloads of non-canonical NaNs. + __ srai(dst, dst, 13); + // preserve the sign bit. + __ srai(tmp, dst, 13); + __ slli(tmp, tmp, 10); + __ mv(t0, 0x3ff); + __ orr(tmp, tmp, t0); + + // get the result by merging sign bit and payloads of preserved non-canonical NaNs. + __ andr(dst, dst, tmp); + + __ j(stub.continuation()); +#undef __ +} + +// j.l.Float.floatToFloat16 +void C2_MacroAssembler::float_to_float16(Register dst, FloatRegister src, FloatRegister ftmp, Register xtmp) { + auto stub = C2CodeStub::make(dst, src, xtmp, 130, float_to_float16_slow_path); + + // in riscv, NaN needs a special process as fcvt does not work in that case. + + // check whether it's a NaN. + // replace fclass with feq as performance optimization. + feq_s(t0, src, src); + // jump to stub processing NaN cases. + beqz(t0, stub->entry()); + + // non-NaN cases, just use built-in instructions. + fcvt_h_s(ftmp, src); + fmv_x_h(dst, ftmp); + + bind(stub->continuation()); +} + void C2_MacroAssembler::signum_fp_v(VectorRegister dst, VectorRegister one, BasicType bt, int vlen) { vsetvli_helper(bt, vlen); @@ -1942,7 +1981,7 @@ void C2_MacroAssembler::element_compare(Register a1, Register a2, Register resul mv(result, true); } -void C2_MacroAssembler::string_equals_v(Register a1, Register a2, Register result, Register cnt, int elem_size) { +void C2_MacroAssembler::string_equals_v(Register a1, Register a2, Register result, Register cnt) { Label DONE; Register tmp1 = t0; Register tmp2 = t1; @@ -1951,11 +1990,7 @@ void C2_MacroAssembler::string_equals_v(Register a1, Register a2, Register resul mv(result, false); - if (elem_size == 2) { - srli(cnt, cnt, 1); - } - - element_compare(a1, a2, result, cnt, tmp1, tmp2, v2, v4, v2, elem_size == 1, DONE); + element_compare(a1, a2, result, cnt, tmp1, tmp2, v2, v4, v2, true, DONE); bind(DONE); BLOCK_COMMENT("} string_equals_v"); diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index 7309c59110a..9fe4dc002c9 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -92,8 +92,7 @@ void arrays_hashcode_elload(Register dst, Address src, BasicType eltype); void string_equals(Register r1, Register r2, - Register result, Register cnt1, - int elem_size); + Register result, Register cnt1); // refer to conditional_branches and float_conditional_branches static const int bool_test_bits = 3; @@ -173,6 +172,7 @@ void signum_fp(FloatRegister dst, FloatRegister one, bool is_double); void float16_to_float(FloatRegister dst, Register src, Register tmp); + void float_to_float16(Register dst, FloatRegister src, FloatRegister ftmp, Register xtmp); void signum_fp_v(VectorRegister dst, VectorRegister one, BasicType bt, int vlen); @@ -187,8 +187,7 @@ void expand_bits_l_v(Register dst, Register src, Register mask); void string_equals_v(Register r1, Register r2, - Register result, Register cnt1, - int elem_size); + Register result, Register cnt1); void arrays_equals_v(Register r1, Register r2, Register result, Register cnt1, diff --git a/src/hotspot/cpu/riscv/compiledIC_riscv.cpp b/src/hotspot/cpu/riscv/compiledIC_riscv.cpp index e29dee56de8..fdb2bcb06ff 100644 --- a/src/hotspot/cpu/riscv/compiledIC_riscv.cpp +++ b/src/hotspot/cpu/riscv/compiledIC_riscv.cpp @@ -27,7 +27,6 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" #include "code/compiledIC.hpp" -#include "code/icBuffer.hpp" #include "code/nmethod.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" @@ -37,7 +36,7 @@ // ---------------------------------------------------------------------------- #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { +address CompiledDirectCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { precond(cbuf.stubs()->start() != badAddress); precond(cbuf.stubs()->end() != badAddress); // Stub is fixed up when the corresponding call is converted from @@ -69,11 +68,11 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) } #undef __ -int CompiledStaticCall::to_interp_stub_size() { +int CompiledDirectCall::to_interp_stub_size() { return MacroAssembler::static_call_stub_size(); } -int CompiledStaticCall::to_trampoline_stub_size() { +int CompiledDirectCall::to_trampoline_stub_size() { // Somewhat pessimistically, we count 4 instructions here (although // there are only 3) because we sometimes emit an alignment nop. // Trampoline stubs are always word aligned. @@ -81,21 +80,14 @@ int CompiledStaticCall::to_trampoline_stub_size() { } // Relocation entries for call stub, compiled java to interpreter. -int CompiledStaticCall::reloc_to_interp_stub() { +int CompiledDirectCall::reloc_to_interp_stub() { return 4; // 3 in emit_to_interp_stub + 1 in emit_call } -void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) { +void CompiledDirectCall::set_to_interpreted(const methodHandle& callee, address entry) { address stub = find_stub(); guarantee(stub != nullptr, "stub not found"); - { - ResourceMark rm; - log_trace(inlinecache)("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s", - p2i(instruction_address()), - callee->name_and_sig_as_C_string()); - } - // Creation also verifies the object. NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); @@ -112,7 +104,7 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad set_destination_mt_safe(stub); } -void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) { +void CompiledDirectCall::set_stub_to_clean(static_stub_Relocation* static_stub) { // Reset stub. address stub = static_stub->addr(); assert(stub != nullptr, "stub not found"); @@ -129,7 +121,7 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_ // Non-product mode code #ifndef PRODUCT -void CompiledDirectStaticCall::verify() { +void CompiledDirectCall::verify() { // Verify call. _call->verify(); _call->verify_alignment(); diff --git a/src/hotspot/cpu/riscv/icBuffer_riscv.cpp b/src/hotspot/cpu/riscv/icBuffer_riscv.cpp deleted file mode 100644 index ab904817816..00000000000 --- a/src/hotspot/cpu/riscv/icBuffer_riscv.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. - * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/icBuffer.hpp" -#include "gc/shared/collectedHeap.inline.hpp" -#include "interpreter/bytecodes.hpp" -#include "memory/resourceArea.hpp" -#include "nativeInst_riscv.hpp" -#include "oops/oop.inline.hpp" - -int InlineCacheBuffer::ic_stub_code_size() { - // 6: auipc + ld + auipc + jalr + address(2 * instruction_size) - return 6 * NativeInstruction::instruction_size; -} - -#define __ masm-> - -void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin, void* cached_value, address entry_point) { - assert_cond(code_begin != nullptr && entry_point != nullptr); - ResourceMark rm; - CodeBuffer code(code_begin, ic_stub_code_size()); - MacroAssembler* masm = new MacroAssembler(&code); - // Note: even though the code contains an embedded value, we do not need reloc info - // because - // (1) the value is old (i.e., doesn't matter for scavenges) - // (2) these ICStubs are removed *before* a GC happens, so the roots disappear - - address start = __ pc(); - Label l; - __ ld(t1, l); - __ far_jump(ExternalAddress(entry_point)); - __ align(wordSize); - __ bind(l); - __ emit_int64((intptr_t)cached_value); - // Only need to invalidate the 1st two instructions - not the whole ic stub - ICache::invalidate_range(code_begin, InlineCacheBuffer::ic_stub_code_size()); - assert(__ pc() - start == ic_stub_code_size(), "must be"); -} - -address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) { - NativeMovConstReg* move = nativeMovConstReg_at(code_begin); // creation also verifies the object - NativeJump* jump = nativeJump_at(move->next_instruction_address()); - return jump->jump_destination(); -} - - -void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) { - // The word containing the cached value is at the end of this IC buffer - uintptr_t *p = (uintptr_t *)(code_begin + ic_stub_code_size() - wordSize); - void* o = (void*)*p; - return o; -} diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index ce336c16aa7..96e07319e84 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -27,6 +27,7 @@ #include "precompiled.hpp" #include "asm/assembler.hpp" #include "asm/assembler.inline.hpp" +#include "code/compiledIC.hpp" #include "compiler/disassembler.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetAssembler.hpp" @@ -634,8 +635,8 @@ void MacroAssembler::unimplemented(const char* what) { } void MacroAssembler::emit_static_call_stub() { - IncompressibleRegion ir(this); // Fixed length: see CompiledStaticCall::to_interp_stub_size(). - // CompiledDirectStaticCall::set_to_interpreted knows the + IncompressibleRegion ir(this); // Fixed length: see CompiledDirectCall::to_interp_stub_size(). + // CompiledDirectCall::set_to_interpreted knows the // exact layout of this stub. mov_metadata(xmethod, (Metadata*)nullptr); @@ -2542,7 +2543,7 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, } // Look up the method for a megamorphic invokeinterface call in a single pass over itable: -// - check recv_klass (actual object class) is a subtype of resolved_klass from CompiledICHolder +// - check recv_klass (actual object class) is a subtype of resolved_klass from CompiledICData // - find a holder_klass (class that implements the method) vtable offset and get the method from vtable by index // The target method is determined by . // The receiver klass is in recv_klass. @@ -3542,6 +3543,48 @@ address MacroAssembler::ic_call(address entry, jint method_index) { return trampoline_call(Address(entry, rh)); } +int MacroAssembler::ic_check_size() { + // No compressed + return (NativeInstruction::instruction_size * (2 /* 2 loads */ + 1 /* branch */)) + + far_branch_size(); +} + +int MacroAssembler::ic_check(int end_alignment) { + IncompressibleRegion ir(this); + Register receiver = j_rarg0; + Register data = t1; + + Register tmp1 = t0; // t0 always scratch + // t2 is saved on call, thus should have been saved before this check. + // Hence we can clobber it. + Register tmp2 = t2; + + // The UEP of a code blob ensures that the VEP is padded. However, the padding of the UEP is placed + // before the inline cache check, so we don't have to execute any nop instructions when dispatching + // through the UEP, yet we can ensure that the VEP is aligned appropriately. That's why we align + // before the inline cache check here, and not after + align(end_alignment, ic_check_size()); + int uep_offset = offset(); + + if (UseCompressedClassPointers) { + lwu(tmp1, Address(receiver, oopDesc::klass_offset_in_bytes())); + lwu(tmp2, Address(data, CompiledICData::speculated_klass_offset())); + } else { + ld(tmp1, Address(receiver, oopDesc::klass_offset_in_bytes())); + ld(tmp2, Address(data, CompiledICData::speculated_klass_offset())); + } + + Label ic_hit; + beq(tmp1, tmp2, ic_hit); + // Note, far_jump is not fixed size. + // Is this ever generates a movptr alignment/size will be off. + far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); + bind(ic_hit); + + assert((offset() % end_alignment) == 0, "Misaligned verified entry point."); + return uep_offset; +} + // Emit a trampoline stub for a call to a target which is too far away. // // code sequences: diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index d283654e6e1..63cfb228551 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -1193,7 +1193,10 @@ class MacroAssembler: public Assembler { // // Return: the call PC or null if CodeCache is full. address trampoline_call(Address entry); + address ic_call(address entry, jint method_index = 0); + static int ic_check_size(); + int ic_check(int end_alignment = NativeInstruction::instruction_size); // Support for memory inc/dec // n.b. increment/decrement calls with an Address destination will diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 550e7947cc5..10a80cd0940 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. // Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -1196,13 +1196,13 @@ bool is_CAS(int opcode, bool maybe_volatile) // returns true if CAS needs to use an acquiring load otherwise false bool needs_acquiring_load_reserved(const Node *n) { - assert(n != NULL && is_CAS(n->Opcode(), true), "expecting a compare and swap"); + assert(n != nullptr && is_CAS(n->Opcode(), true), "expecting a compare and swap"); LoadStoreNode* ldst = n->as_LoadStore(); - if (n != NULL && is_CAS(n->Opcode(), false)) { - assert(ldst != NULL && ldst->trailing_membar() != NULL, "expected trailing membar"); + if (n != nullptr && is_CAS(n->Opcode(), false)) { + assert(ldst != nullptr && ldst->trailing_membar() != nullptr, "expected trailing membar"); } else { - return ldst != NULL && ldst->trailing_membar() != NULL; + return ldst != nullptr && ldst->trailing_membar() != nullptr; } // so we can just return true here return true; @@ -1247,7 +1247,7 @@ int MachCallRuntimeNode::ret_addr_offset() { // sd(t1, Address(sp, wordSize)) -> sd // jalr(t0) -> jalr CodeBlob *cb = CodeCache::find_blob(_entry_point); - if (cb != NULL) { + if (cb != nullptr) { return 1 * NativeInstruction::instruction_size; } else { return 11 * NativeInstruction::instruction_size; @@ -1286,7 +1286,7 @@ int CallDynamicJavaDirectNode::compute_padding(int current_offset) const #ifndef PRODUCT void MachBreakpointNode::format(PhaseRegAlloc *ra_, outputStream *st) const { - assert_cond(st != NULL); + assert_cond(st != nullptr); st->print("BREAKPOINT"); } #endif @@ -1342,14 +1342,14 @@ uint MachConstantBaseNode::size(PhaseRegAlloc* ra_) const { #ifndef PRODUCT void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const { - assert_cond(st != NULL); + assert_cond(st != nullptr); st->print("-- \t// MachConstantBaseNode (empty encoding)"); } #endif #ifndef PRODUCT void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const { - assert_cond(st != NULL && ra_ != NULL); + assert_cond(st != nullptr && ra_ != nullptr); Compile* C = ra_->C; int framesize = C->output()->frame_slots() << LogBytesPerInt; @@ -1363,7 +1363,7 @@ void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const { if (PreserveFramePointer) { st->print("sub fp, sp, #%d\n\t", 2 * wordSize); } st->print("sub sp, sp, #%d\n\t", framesize); - if (C->stub_function() == NULL && BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) { + if (C->stub_function() == nullptr && BarrierSet::barrier_set()->barrier_set_nmethod() != nullptr) { st->print("ld t0, [guard]\n\t"); st->print("membar LoadLoad\n\t"); st->print("ld t1, [xthread, #thread_disarmed_guard_value_offset]\n\t"); @@ -1377,7 +1377,7 @@ void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const { #endif void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - assert_cond(ra_ != NULL); + assert_cond(ra_ != nullptr); Compile* C = ra_->C; C2_MacroAssembler _masm(&cbuf); @@ -1392,7 +1392,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { __ nop(); // 4 bytes } - assert_cond(C != NULL); + assert_cond(C != nullptr); if (C->clinit_barrier_on_entry()) { assert(!C->method()->holder()->is_not_initialized(), "initialization should have been started"); @@ -1412,9 +1412,9 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { __ build_frame(framesize); - if (C->stub_function() == NULL) { + if (C->stub_function() == nullptr) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); - if (BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) { + if (BarrierSet::barrier_set()->barrier_set_nmethod() != nullptr) { // Dummy labels for just measuring the code size Label dummy_slow_path; Label dummy_continuation; @@ -1451,7 +1451,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { uint MachPrologNode::size(PhaseRegAlloc* ra_) const { - assert_cond(ra_ != NULL); + assert_cond(ra_ != nullptr); return MachNode::size(ra_); // too many variables; just compute it // the hard way } @@ -1465,9 +1465,9 @@ int MachPrologNode::reloc() const #ifndef PRODUCT void MachEpilogNode::format(PhaseRegAlloc *ra_, outputStream *st) const { - assert_cond(st != NULL && ra_ != NULL); + assert_cond(st != nullptr && ra_ != nullptr); Compile* C = ra_->C; - assert_cond(C != NULL); + assert_cond(C != nullptr); int framesize = C->output()->frame_size_in_bytes(); st->print("# pop frame %d\n\t", framesize); @@ -1491,10 +1491,10 @@ void MachEpilogNode::format(PhaseRegAlloc *ra_, outputStream *st) const { #endif void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - assert_cond(ra_ != NULL); + assert_cond(ra_ != nullptr); Compile* C = ra_->C; C2_MacroAssembler _masm(&cbuf); - assert_cond(C != NULL); + assert_cond(C != nullptr); int framesize = C->output()->frame_size_in_bytes(); __ remove_frame(framesize); @@ -1517,7 +1517,7 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { } uint MachEpilogNode::size(PhaseRegAlloc *ra_) const { - assert_cond(ra_ != NULL); + assert_cond(ra_ != nullptr); // Variable size. Determine dynamically. return MachNode::size(ra_); } @@ -1568,7 +1568,7 @@ static enum RC rc_class(OptoReg::Name reg) { } uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, bool do_size, outputStream *st) const { - assert_cond(ra_ != NULL); + assert_cond(ra_ != nullptr); Compile* C = ra_->C; // Get registers to move. @@ -1599,7 +1599,7 @@ uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, boo int src_offset = ra_->reg2offset(src_lo); int dst_offset = ra_->reg2offset(dst_lo); - if (bottom_type()->isa_vect() != NULL) { + if (bottom_type()->isa_vect() != nullptr) { uint ireg = ideal_reg(); if (ireg == Op_VecA && cbuf) { C2_MacroAssembler _masm(cbuf); @@ -1640,7 +1640,7 @@ uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, boo ShouldNotReachHere(); } } - } else if (cbuf != NULL) { + } else if (cbuf != nullptr) { C2_MacroAssembler _masm(cbuf); switch (src_lo_rc) { case rc_int: @@ -1711,7 +1711,7 @@ uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, boo } } - if (st != NULL) { + if (st != nullptr) { st->print("spill "); if (src_lo_rc == rc_stack) { st->print("[sp, #%d] -> ", src_offset); @@ -1745,16 +1745,16 @@ uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, boo #ifndef PRODUCT void MachSpillCopyNode::format(PhaseRegAlloc *ra_, outputStream *st) const { - if (ra_ == NULL) { + if (ra_ == nullptr) { st->print("N%d = SpillCopy(N%d)", _idx, in(1)->_idx); } else { - implementation(NULL, ra_, false, st); + implementation(nullptr, ra_, false, st); } } #endif void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - implementation(&cbuf, ra_, false, NULL); + implementation(&cbuf, ra_, false, nullptr); } uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { @@ -1765,7 +1765,7 @@ uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { #ifndef PRODUCT void BoxLockNode::format(PhaseRegAlloc *ra_, outputStream *st) const { - assert_cond(ra_ != NULL && st != NULL); + assert_cond(ra_ != nullptr && st != nullptr); int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); int reg = ra_->get_reg_first(this); st->print("add %s, sp, #%d\t# box lock", @@ -1777,7 +1777,7 @@ void BoxLockNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { C2_MacroAssembler _masm(&cbuf); Assembler::IncompressibleRegion ir(&_masm); // Fixed length: see BoxLockNode::size() - assert_cond(ra_ != NULL); + assert_cond(ra_ != nullptr); int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); int reg = ra_->get_encode(this); @@ -1805,17 +1805,16 @@ uint BoxLockNode::size(PhaseRegAlloc *ra_) const { #ifndef PRODUCT void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const { - assert_cond(st != NULL); + assert_cond(st != nullptr); st->print_cr("# MachUEPNode"); if (UseCompressedClassPointers) { - st->print_cr("\tlwu t0, [j_rarg0, oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - if (CompressedKlassPointers::shift() != 0) { - st->print_cr("\tdecode_klass_not_null t0, t0"); - } + st->print_cr("\tlwu t0, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + st->print_cr("\tlwu t2, [t1 + CompiledICData::speculated_klass_offset()]\t# compressed klass"); } else { - st->print_cr("\tld t0, [j_rarg0, oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + st->print_cr("\tld t0, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + st->print_cr("\tld t2, [t1 + CompiledICData::speculated_klass_offset()]\t# compressed klass"); } - st->print_cr("\tbeq t0, t1, ic_hit"); + st->print_cr("\tbeq t0, t2, ic_hit"); st->print_cr("\tj, SharedRuntime::_ic_miss_stub\t # Inline cache check"); st->print_cr("\tic_hit:"); } @@ -1825,20 +1824,16 @@ void MachUEPNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const { // This is the unverified entry point. C2_MacroAssembler _masm(&cbuf); + __ ic_check(CodeEntryAlignment); - Label skip; - __ cmp_klass(j_rarg0, t1, t0, t2 /* call-clobbered t2 as a tmp */, skip); - __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); - __ bind(skip); - - // These NOPs are critical so that verified entry point is properly - // 4 bytes aligned for patching by NativeJump::patch_verified_entry() - __ align(NativeInstruction::instruction_size); + // Verified entry point must be properly 4 bytes aligned for patching by NativeJump::patch_verified_entry(). + // ic_check() aligns to CodeEntryAlignment >= InteriorEntryAlignment(min 16) > NativeInstruction::instruction_size(4). + assert(((__ offset()) % CodeEntryAlignment) == 0, "Misaligned verified entry point"); } uint MachUEPNode::size(PhaseRegAlloc* ra_) const { - assert_cond(ra_ != NULL); + assert_cond(ra_ != nullptr); return MachNode::size(ra_); } @@ -1855,7 +1850,7 @@ int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) // That's why we must use the macroassembler to generate a handler. C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_exception_handler()); - if (base == NULL) { + if (base == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return 0; // CodeBuffer::expand failed } @@ -1873,7 +1868,7 @@ int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) // That's why we must use the macroassembler to generate a handler. C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_deopt_handler()); - if (base == NULL) { + if (base == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return 0; // CodeBuffer::expand failed } @@ -1934,6 +1929,7 @@ bool Matcher::match_rule_supported(int opcode) { return UseFMA; case Op_ConvHF2F: + case Op_ConvF2HF: return UseZfh; } @@ -2016,7 +2012,7 @@ int Matcher::min_vector_size(const BasicType bt) { return MIN2(size, max_size); } -int Matcher::superword_max_vector_size(const BasicType bt) { +int Matcher::max_vector_size_auto_vectorization(const BasicType bt) { return Matcher::max_vector_size(bt); } @@ -2037,7 +2033,7 @@ int Matcher::scalable_vector_reg_size(const BasicType bt) { MachOper* Matcher::pd_specialize_generic_vector_operand(MachOper* original_opnd, uint ideal_reg, bool is_temp) { ShouldNotReachHere(); // generic vector operands not supported - return NULL; + return nullptr; } bool Matcher::is_reg2reg_move(MachNode* m) { @@ -2140,10 +2136,10 @@ const RegMask Matcher::method_handle_invoke_SP_save_mask() { } bool size_fits_all_mem_uses(AddPNode* addp, int shift) { - assert_cond(addp != NULL); + assert_cond(addp != nullptr); for (DUIterator_Fast imax, i = addp->fast_outs(imax); i < imax; i++) { Node* u = addp->fast_out(i); - if (u != NULL && u->is_Mem()) { + if (u != nullptr && u->is_Mem()) { int opsize = u->as_Mem()->memory_size(); assert(opsize > 0, "unexpected memory operand size"); if (u->as_Mem()->memory_size() != (1 << shift)) { @@ -2156,7 +2152,7 @@ bool size_fits_all_mem_uses(AddPNode* addp, int shift) { // Should the Matcher clone input 'm' of node 'n'? bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { - assert_cond(m != NULL); + assert_cond(m != nullptr); if (is_vshift_con_pattern(n, m)) { // ShiftV src (ShiftCntV con) mstack.push(m, Visit); // m = ShiftCntV return true; @@ -2215,7 +2211,7 @@ encode %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); address con = (address)$src$$constant; - if (con == NULL || con == (address)1) { + if (con == nullptr || con == (address)1) { ShouldNotReachHere(); } else { relocInfo::relocType rtype = $src->constant_reloc(); @@ -2245,7 +2241,7 @@ encode %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); address con = (address)$src$$constant; - if (con == NULL) { + if (con == nullptr) { ShouldNotReachHere(); } else { relocInfo::relocType rtype = $src->constant_reloc(); @@ -2264,7 +2260,7 @@ encode %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); address con = (address)$src$$constant; - if (con == NULL) { + if (con == nullptr) { ShouldNotReachHere(); } else { relocInfo::relocType rtype = $src->constant_reloc(); @@ -2350,7 +2346,7 @@ encode %{ Label done; C2_MacroAssembler _masm(&cbuf); __ check_klass_subtype_slow_path(sub_reg, super_reg, temp_reg, result_reg, - NULL, &miss); + nullptr, &miss); if ($primary) { __ mv(result_reg, zr); } else { @@ -2371,12 +2367,12 @@ encode %{ Assembler::IncompressibleRegion ir(&_masm); // Fixed length: see ret_addr_offset address addr = (address)$meth$$method; - address call = NULL; - assert_cond(addr != NULL); + address call = nullptr; + assert_cond(addr != nullptr); if (!_method) { // A call to a runtime wrapper, e.g. new, new_typeArray_Java, uncommon_trap. call = __ trampoline_call(Address(addr, relocInfo::runtime_call_type)); - if (call == NULL) { + if (call == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -2390,7 +2386,7 @@ encode %{ RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) : static_call_Relocation::spec(method_index); call = __ trampoline_call(Address(addr, rspec)); - if (call == NULL) { + if (call == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -2401,8 +2397,8 @@ encode %{ cbuf.shared_stub_to_interp_for(_method, call - cbuf.insts_begin()); } else { // Emit stub for static call - address stub = CompiledStaticCall::emit_to_interp_stub(cbuf, call); - if (stub == NULL) { + address stub = CompiledDirectCall::emit_to_interp_stub(cbuf, call); + if (stub == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -2417,7 +2413,7 @@ encode %{ Assembler::IncompressibleRegion ir(&_masm); // Fixed length: see ret_addr_offset int method_index = resolved_method_index(cbuf); address call = __ ic_call((address)$meth$$method, method_index); - if (call == NULL) { + if (call == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -2443,9 +2439,9 @@ encode %{ // which loads the absolute address into a register. address entry = (address)$meth$$method; CodeBlob *cb = CodeCache::find_blob(entry); - if (cb != NULL) { + if (cb != nullptr) { address call = __ trampoline_call(Address(entry, relocInfo::runtime_call_type)); - if (call == NULL) { + if (call == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -2893,7 +2889,7 @@ operand immP() interface(CONST_INTER); %} -// NULL Pointer Immediate +// Null Pointer Immediate operand immP0() %{ predicate(n->get_ptr() == 0); @@ -3014,7 +3010,7 @@ operand immN() interface(CONST_INTER); %} -// Narrow NULL Pointer Immediate +// Narrow Null Pointer Immediate operand immN0() %{ predicate(n->get_narrowcon() == 0); @@ -4892,7 +4888,7 @@ instruct loadConP0(iRegPNoSp dst, immP0 con) match(Set dst con); ins_cost(ALU_COST); - format %{ "mv $dst, $con\t# NULL ptr, #@loadConP0" %} + format %{ "mv $dst, $con\t# null pointer, #@loadConP0" %} ins_encode(riscv_enc_mov_zero(dst)); @@ -4943,7 +4939,7 @@ instruct loadConN0(iRegNNoSp dst, immN0 con) match(Set dst con); ins_cost(ALU_COST); - format %{ "mv $dst, $con\t# compressed NULL ptr, #@loadConN0" %} + format %{ "mv $dst, $con\t# compressed null pointer, #@loadConN0" %} ins_encode(riscv_enc_mov_zero(dst)); @@ -8292,6 +8288,18 @@ instruct convHF2F_reg_reg(fRegF dst, iRegINoSp src, iRegINoSp tmp) %{ ins_pipe(pipe_slow); %} +instruct convF2HF_reg_reg(iRegINoSp dst, fRegF src, fRegF ftmp, iRegINoSp xtmp) %{ + match(Set dst (ConvF2HF src)); + effect(TEMP_DEF dst, TEMP ftmp, TEMP xtmp); + format %{ "fcvt.h.s $ftmp, $src\t# convert single precision to half\n\t" + "fmv.x.h $dst, $ftmp\t# move result from $ftmp to $dst" + %} + ins_encode %{ + __ float_to_float16($dst$$Register, $src$$FloatRegister, $ftmp$$FloatRegister, $xtmp$$Register); + %} + ins_pipe(pipe_slow); +%} + // float <-> int instruct convF2I_reg_reg(iRegINoSp dst, fRegF src) %{ @@ -10325,7 +10333,7 @@ instruct clearArray_reg_reg(iRegL_R29 cnt, iRegP_R28 base, iRegP_R30 tmp1, ins_encode %{ address tpc = __ zero_words($base$$Register, $cnt$$Register); - if (tpc == NULL) { + if (tpc == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -10362,23 +10370,7 @@ instruct string_equalsL(iRegP_R11 str1, iRegP_R13 str2, iRegI_R14 cnt, ins_encode %{ // Count is in 8-bit bytes; non-Compact chars are 16 bits. __ string_equals($str1$$Register, $str2$$Register, - $result$$Register, $cnt$$Register, 1); - %} - ins_pipe(pipe_class_memory); -%} - -instruct string_equalsU(iRegP_R11 str1, iRegP_R13 str2, iRegI_R14 cnt, - iRegI_R10 result, rFlagsReg cr) -%{ - predicate(!UseRVV && ((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU); - match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); - - format %{ "String Equals $str1, $str2, $cnt -> $result\t#@string_equalsU" %} - ins_encode %{ - // Count is in 8-bit bytes; non-Compact chars are 16 bits. - __ string_equals($str1$$Register, $str2$$Register, - $result$$Register, $cnt$$Register, 2); + $result$$Register, $cnt$$Register); %} ins_pipe(pipe_class_memory); %} diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index c163325fc81..d07f4dc7c9a 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2020, 2023, Arm Limited. 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. @@ -46,7 +46,7 @@ source %{ } } - bool Matcher::match_rule_supported_superword(int opcode, int vlen, BasicType bt) { + bool Matcher::match_rule_supported_auto_vectorization(int opcode, int vlen, BasicType bt) { return match_rule_supported_vector(opcode, vlen, bt); } @@ -2614,24 +2614,7 @@ instruct vstring_equalsL(iRegP_R11 str1, iRegP_R13 str2, iRegI_R14 cnt, ins_encode %{ // Count is in 8-bit bytes; non-Compact chars are 16 bits. __ string_equals_v($str1$$Register, $str2$$Register, - $result$$Register, $cnt$$Register, 1); - %} - ins_pipe(pipe_class_memory); -%} - -instruct vstring_equalsU(iRegP_R11 str1, iRegP_R13 str2, iRegI_R14 cnt, - iRegI_R10 result, vReg_V2 v2, - vReg_V3 v3, vReg_V4 v4, vReg_V5 v5, rFlagsReg cr) -%{ - predicate(UseRVV && ((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU); - match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP v2, TEMP v3, TEMP v4, TEMP v5, KILL cr); - - format %{ "String Equals $str1, $str2, $cnt -> $result\t#@string_equalsU" %} - ins_encode %{ - // Count is in 8-bit bytes; non-Compact chars are 16 bits. - __ string_equals_v($str1$$Register, $str2$$Register, - $result$$Register, $cnt$$Register, 2); + $result$$Register, $cnt$$Register); %} ins_pipe(pipe_class_memory); %} @@ -3217,7 +3200,7 @@ instruct vcvtBtoX(vReg dst, vReg src) %{ __ csrwi(CSR_FRM, C2_MacroAssembler::rne); __ vfcvt_f_x_v(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg)); } else { - __ integer_extend_v(as_VectorRegister($dst$$reg), bt, + __ integer_extend_v(as_VectorRegister($dst$$reg), bt, Matcher::vector_length(this), as_VectorRegister($src$$reg), T_BYTE); } %} diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index 01fe307bc27..7435b552d15 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -29,7 +29,6 @@ #include "asm/macroAssembler.inline.hpp" #include "code/compiledIC.hpp" #include "code/debugInfoRec.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "compiler/oopMap.hpp" #include "gc/shared/barrierSetAssembler.hpp" @@ -38,7 +37,6 @@ #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "nativeInst_riscv.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/klass.inline.hpp" #include "oops/method.inline.hpp" #include "prims/methodHandles.hpp" @@ -622,10 +620,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm address c2i_unverified_entry = __ pc(); Label skip_fixup; - Label ok; - - const Register holder = t1; const Register receiver = j_rarg0; + const Register data = t1; const Register tmp = t2; // A call-clobbered register not used for arg passing // ------------------------------------------------------------------------- @@ -639,16 +635,10 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm { __ block_comment("c2i_unverified_entry {"); - __ load_klass(t0, receiver, tmp); - __ ld(tmp, Address(holder, CompiledICHolder::holder_klass_offset())); - __ ld(xmethod, Address(holder, CompiledICHolder::holder_metadata_offset())); - __ beq(t0, tmp, ok); - __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); - __ bind(ok); - // Method might have been compiled since the call site was patched to - // interpreted; if that is the case treat it as a miss so we can get - // the call site corrected. + __ ic_check(); + __ ld(xmethod, Address(data, CompiledICData::speculated_method_offset())); + __ ld(t0, Address(xmethod, in_bytes(Method::code_offset()))); __ beqz(t0, skip_fixup); __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); @@ -985,7 +975,7 @@ static void gen_continuation_enter(MacroAssembler* masm, __ j(exit); CodeBuffer* cbuf = masm->code_section()->outer(); - address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, tr_call); + address stub = CompiledDirectCall::emit_to_interp_stub(*cbuf, tr_call); if (stub == nullptr) { fatal("CodeCache is full at gen_continuation_enter"); } @@ -1051,7 +1041,7 @@ static void gen_continuation_enter(MacroAssembler* masm, } CodeBuffer* cbuf = masm->code_section()->outer(); - address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, tr_call); + address stub = CompiledDirectCall::emit_to_interp_stub(*cbuf, tr_call); if (stub == nullptr) { fatal("CodeCache is full at gen_continuation_enter"); } @@ -1271,6 +1261,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, in_ByteSize(-1), oop_maps, exception_offset); + if (nm == nullptr) return nm; if (method->is_continuation_enter_intrinsic()) { ContinuationEntry::set_enter_code(nm, interpreted_entry_offset); } else if (method->is_continuation_yield_intrinsic()) { @@ -1424,19 +1415,10 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, const Register ic_reg = t1; const Register receiver = j_rarg0; - Label hit; - Label exception_pending; - __ verify_oop(receiver); - assert_different_registers(ic_reg, receiver, t0, t2); - __ cmp_klass(receiver, ic_reg, t0, t2 /* call-clobbered t2 as a tmp */, hit); - - __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); + assert_different_registers(receiver, t0, t1); - // Verified entry point must be aligned - __ align(8); - - __ bind(hit); + __ ic_check(); int vep_offset = ((intptr_t)__ pc()) - start; @@ -1871,6 +1853,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ leave(); // Any exception pending? + Label exception_pending; __ ld(t0, Address(xthread, in_bytes(Thread::pending_exception_offset()))); __ bnez(t0, exception_pending); diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index 73b4d1e28cc..58f57f32b2f 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -3547,11 +3547,10 @@ void TemplateTable::_new() { // get InstanceKlass __ load_resolved_klass_at_offset(x14, x13, x14, t0); - // make sure klass is initialized & doesn't have finalizer - // make sure klass is fully initialized - __ lbu(t0, Address(x14, InstanceKlass::init_state_offset())); - __ sub(t1, t0, (u1)InstanceKlass::fully_initialized); - __ bnez(t1, slow_case); + // make sure klass is initialized + assert(VM_Version::supports_fast_class_init_checks(), + "Optimization requires support for fast class initialization checks"); + __ clinit_barrier(x14, t0, nullptr /*L_fast_path*/, &slow_case); // get instance_size in InstanceKlass (scaled to a count of bytes) __ lwu(x13, Address(x14, Klass::layout_helper_offset())); diff --git a/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp b/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp index 9d08796681f..5d945dbc323 100644 --- a/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp +++ b/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp @@ -27,10 +27,10 @@ #include "precompiled.hpp" #include "asm/assembler.inline.hpp" #include "asm/macroAssembler.inline.hpp" +#include "code/compiledIC.hpp" #include "code/vtableStubs.hpp" #include "interp_masm_riscv.hpp" #include "memory/resourceArea.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/instanceKlass.hpp" #include "oops/klassVtable.hpp" #include "runtime/sharedRuntime.hpp" @@ -171,22 +171,22 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); // Entry arguments: - // t1: CompiledICHolder + // t1: CompiledICData // j_rarg0: Receiver // This stub is called from compiled code which has no callee-saved registers, // so all registers except arguments are free at this point. const Register recv_klass_reg = x18; - const Register holder_klass_reg = x19; // declaring interface klass (DECC) + const Register holder_klass_reg = x19; // declaring interface klass (DEFC) const Register resolved_klass_reg = x30; // resolved interface klass (REFC) const Register temp_reg = x28; const Register temp_reg2 = x29; - const Register icholder_reg = t1; + const Register icdata_reg = t1; Label L_no_such_interface; - __ ld(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset())); - __ ld(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset())); + __ ld(resolved_klass_reg, Address(icdata_reg, CompiledICData::itable_refc_klass_offset())); + __ ld(holder_klass_reg, Address(icdata_reg, CompiledICData::itable_defc_klass_offset())); start_pc = __ pc(); diff --git a/src/hotspot/cpu/s390/assembler_s390.hpp b/src/hotspot/cpu/s390/assembler_s390.hpp index 9bb143001b9..91cc7e611bf 100644 --- a/src/hotspot/cpu/s390/assembler_s390.hpp +++ b/src/hotspot/cpu/s390/assembler_s390.hpp @@ -107,7 +107,7 @@ class RelAddr { static bool is_in_range_of_RelAddr(address target, address pc, bool shortForm) { // Guard against illegal branch targets, e.g. -1. Occurrences in - // CompiledStaticCall and ad-file. Do not assert (it's a test + // CompiledDirectCall and ad-file. Do not assert (it's a test // function!). Just return false in case of illegal operands. if ((((uint64_t)target) & 0x0001L) != 0) return false; if ((((uint64_t)pc) & 0x0001L) != 0) return false; diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index 542ade8ed0e..13c45bb9fe7 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2023 SAP SE. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,10 +76,7 @@ int LIR_Assembler::initial_frame_size_in_bytes() const { // We fetch the class of the receiver and compare it with the cached class. // If they do not match we jump to the slow case. int LIR_Assembler::check_icache() { - Register receiver = receiverOpr()->as_register(); - int offset = __ offset(); - __ inline_cache_check(receiver, Z_inline_cache); - return offset; + return __ ic_check(CodeEntryAlignment); } void LIR_Assembler::clinit_barrier(ciMethod* method) { @@ -2480,23 +2477,30 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L assert_different_registers(obj, k_RInfo, klass_RInfo); if (op->should_profile()) { + Register mdo = klass_RInfo; + metadata2reg(md->constant_encoding(), mdo); NearLabel not_null; __ compareU64_and_branch(obj, (intptr_t) 0, Assembler::bcondNotEqual, not_null); // Object is null; update MDO and exit. - Register mdo = klass_RInfo; - metadata2reg(md->constant_encoding(), mdo); Address data_addr(mdo, md->byte_offset_of_slot(data, DataLayout::header_offset())); int header_bits = DataLayout::flag_mask_to_header_mask(BitData::null_seen_byte_constant()); __ or2mem_8(data_addr, header_bits); __ branch_optimized(Assembler::bcondAlways, *obj_is_null); __ bind(not_null); + + NearLabel update_done; + Register recv = k_RInfo; + __ load_klass(recv, obj); + type_profile_helper(mdo, md, data, recv, Rtmp1, &update_done); + Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); + __ add2mem_64(counter_addr, DataLayout::counter_increment, Rtmp1); + __ bind(update_done); } else { __ compareU64_and_branch(obj, (intptr_t) 0, Assembler::bcondEqual, *obj_is_null); } - NearLabel profile_cast_failure, profile_cast_success; - Label *failure_target = op->should_profile() ? &profile_cast_failure : failure; - Label *success_target = op->should_profile() ? &profile_cast_success : success; + Label *failure_target = failure; + Label *success_target = success; // Patching may screw with our temporaries, // so let's do it before loading the class. @@ -2536,28 +2540,12 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L store_parameter(klass_RInfo, 0); // sub store_parameter(k_RInfo, 1); // super emit_call_c(a); // Sets condition code 0 for match (2 otherwise). - CHECK_BAILOUT2(profile_cast_failure, profile_cast_success); __ branch_optimized(Assembler::bcondNotEqual, *failure_target); // Fall through to success case. } } - if (op->should_profile()) { - Register mdo = klass_RInfo, recv = k_RInfo; - assert_different_registers(obj, mdo, recv); - __ bind(profile_cast_success); - metadata2reg(md->constant_encoding(), mdo); - __ load_klass(recv, obj); - type_profile_helper(mdo, md, data, recv, Rtmp1, success); - __ branch_optimized(Assembler::bcondAlways, *success); - - __ bind(profile_cast_failure); - metadata2reg(md->constant_encoding(), mdo); - __ add2mem_64(Address(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())), -(int)DataLayout::counter_increment, Rtmp1); - __ branch_optimized(Assembler::bcondAlways, *failure); - } else { - __ branch_optimized(Assembler::bcondAlways, *success); - } + __ branch_optimized(Assembler::bcondAlways, *success); } void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { @@ -2587,21 +2575,29 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { assert(data != nullptr, "need data for type check"); assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); } - NearLabel profile_cast_success, profile_cast_failure, done; - Label *success_target = op->should_profile() ? &profile_cast_success : &done; - Label *failure_target = op->should_profile() ? &profile_cast_failure : stub->entry(); + NearLabel done; + Label *success_target = &done; + Label *failure_target = stub->entry(); if (op->should_profile()) { + Register mdo = klass_RInfo; + metadata2reg(md->constant_encoding(), mdo); NearLabel not_null; __ compareU64_and_branch(value, (intptr_t) 0, Assembler::bcondNotEqual, not_null); // Object is null; update MDO and exit. - Register mdo = klass_RInfo; - metadata2reg(md->constant_encoding(), mdo); Address data_addr(mdo, md->byte_offset_of_slot(data, DataLayout::header_offset())); int header_bits = DataLayout::flag_mask_to_header_mask(BitData::null_seen_byte_constant()); __ or2mem_8(data_addr, header_bits); __ branch_optimized(Assembler::bcondAlways, done); __ bind(not_null); + + NearLabel update_done; + Register recv = k_RInfo; + __ load_klass(recv, value); + type_profile_helper(mdo, md, data, recv, Rtmp1, &update_done); + Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); + __ add2mem_64(counter_addr, DataLayout::counter_increment, Rtmp1); + __ bind(update_done); } else { __ compareU64_and_branch(value, (intptr_t) 0, Assembler::bcondEqual, done); } @@ -2619,25 +2615,9 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { store_parameter(klass_RInfo, 0); // sub store_parameter(k_RInfo, 1); // super emit_call_c(a); // Sets condition code 0 for match (2 otherwise). - CHECK_BAILOUT3(profile_cast_success, profile_cast_failure, done); __ branch_optimized(Assembler::bcondNotEqual, *failure_target); // Fall through to success case. - if (op->should_profile()) { - Register mdo = klass_RInfo, recv = k_RInfo; - assert_different_registers(value, mdo, recv); - __ bind(profile_cast_success); - metadata2reg(md->constant_encoding(), mdo); - __ load_klass(recv, value); - type_profile_helper(mdo, md, data, recv, Rtmp1, &done); - __ branch_optimized(Assembler::bcondAlways, done); - - __ bind(profile_cast_failure); - metadata2reg(md->constant_encoding(), mdo); - __ add2mem_64(Address(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())), -(int)DataLayout::counter_increment, Rtmp1); - __ branch_optimized(Assembler::bcondAlways, *stub->entry()); - } - __ bind(done); } else { if (code == lir_checkcast) { diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.hpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.hpp index 229216ef20d..c8815f3a729 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.hpp @@ -45,7 +45,7 @@ } enum { - _call_stub_size = 512, // See Compile::MAX_stubs_size and CompiledStaticCall::emit_to_interp_stub. + _call_stub_size = 512, // See Compile::MAX_stubs_size and CompiledDirectCall::emit_to_interp_stub. _exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(128), _deopt_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(64) }; diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp index 40edca6559a..5dddc7a756f 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -40,31 +40,6 @@ #include "runtime/stubRoutines.hpp" #include "utilities/macros.hpp" -void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) { - Label ic_miss, ic_hit; - verify_oop(receiver, FILE_AND_LINE); - int klass_offset = oopDesc::klass_offset_in_bytes(); - - if (!ImplicitNullChecks || MacroAssembler::needs_explicit_null_check(klass_offset)) { - if (VM_Version::has_CompareBranch()) { - z_cgij(receiver, 0, Assembler::bcondEqual, ic_miss); - } else { - z_ltgr(receiver, receiver); - z_bre(ic_miss); - } - } - - compare_klass_ptr(iCache, klass_offset, receiver, false); - z_bre(ic_hit); - - // If icache check fails, then jump to runtime routine. - // Note: RECEIVER must still contain the receiver! - load_const_optimized(Z_R1_scratch, AddressLiteral(SharedRuntime::get_ic_miss_stub())); - z_br(Z_R1_scratch); - align(CodeEntryAlignment); - bind(ic_hit); -} - void C1_MacroAssembler::explicit_null_check(Register base) { ShouldNotCallThis(); // unused } diff --git a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp index 257148827be..decb3a1cafc 100644 --- a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp +++ b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp @@ -35,7 +35,6 @@ #include "interpreter/interpreter.hpp" #include "memory/universe.hpp" #include "nativeInst_s390.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "register_s390.hpp" diff --git a/src/hotspot/cpu/s390/compiledIC_s390.cpp b/src/hotspot/cpu/s390/compiledIC_s390.cpp index 7ea90c1de7c..3adcfbc85f1 100644 --- a/src/hotspot/cpu/s390/compiledIC_s390.cpp +++ b/src/hotspot/cpu/s390/compiledIC_s390.cpp @@ -26,7 +26,6 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" #include "code/compiledIC.hpp" -#include "code/icBuffer.hpp" #include "code/nmethod.hpp" #include "memory/resourceArea.hpp" #include "runtime/mutexLocker.hpp" @@ -40,7 +39,7 @@ #undef __ #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* = nullptr*/) { +address CompiledDirectCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* = nullptr*/) { #ifdef COMPILER2 // Stub is fixed up when the corresponding call is converted from calling // compiled code to calling interpreted code. @@ -54,7 +53,7 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* // That's why we must use the macroassembler to generate a stub. MacroAssembler _masm(&cbuf); - address stub = __ start_a_stub(CompiledStaticCall::to_interp_stub_size()); + address stub = __ start_a_stub(CompiledDirectCall::to_interp_stub_size()); if (stub == nullptr) { return nullptr; // CodeBuffer::expand failed. } @@ -81,27 +80,20 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* #undef __ -int CompiledStaticCall::to_interp_stub_size() { +int CompiledDirectCall::to_interp_stub_size() { return 2 * MacroAssembler::load_const_from_toc_size() + 2; // branch } // Relocation entries for call stub, compiled java to interpreter. -int CompiledStaticCall::reloc_to_interp_stub() { +int CompiledDirectCall::reloc_to_interp_stub() { return 5; // 4 in emit_java_to_interp + 1 in Java_Static_Call } -void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) { +void CompiledDirectCall::set_to_interpreted(const methodHandle& callee, address entry) { address stub = find_stub(); guarantee(stub != nullptr, "stub not found"); - { - ResourceMark rm; - log_trace(inlinecache)("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s", - p2i(instruction_address()), - callee->name_and_sig_as_C_string()); - } - // Creation also verifies the object. NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + NativeCall::get_IC_pos_in_java_to_interp_stub()); NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); @@ -115,7 +107,7 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad set_destination_mt_safe(stub); } -void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) { +void CompiledDirectCall::set_stub_to_clean(static_stub_Relocation* static_stub) { // Reset stub. address stub = static_stub->addr(); assert(stub != nullptr, "stub not found"); @@ -131,7 +123,7 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_ #ifndef PRODUCT -void CompiledDirectStaticCall::verify() { +void CompiledDirectCall::verify() { // Verify call. _call->verify(); _call->verify_alignment(); diff --git a/src/hotspot/cpu/s390/icBuffer_s390.cpp b/src/hotspot/cpu/s390/icBuffer_s390.cpp deleted file mode 100644 index 0dc936d6fad..00000000000 --- a/src/hotspot/cpu/s390/icBuffer_s390.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2016, 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. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/icBuffer.hpp" -#include "gc/shared/collectedHeap.inline.hpp" -#include "interpreter/bytecodes.hpp" -#include "memory/resourceArea.hpp" -#include "nativeInst_s390.hpp" -#include "oops/oop.inline.hpp" - -#define __ masm. - -int InlineCacheBuffer::ic_stub_code_size() { - return MacroAssembler::load_const_size() + Assembler::z_brul_size(); -} - -void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin, void* cached_oop, address entry_point) { - ResourceMark rm; - CodeBuffer code(code_begin, ic_stub_code_size()); - MacroAssembler masm(&code); - // Note: even though the code contains an embedded oop, we do not need reloc info - // because - // (1) the oop is old (i.e., doesn't matter for scavenges) - // (2) these ICStubs are removed *before* a GC happens, so the roots disappear. - - // Load the oop, - __ load_const(Z_method, (address) cached_oop); // inline cache reg = Z_method - // and do a tail-call (pc-relative). - __ z_brul((address) entry_point); - __ flush(); -} - -address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) { - NativeMovConstReg* move = nativeMovConstReg_at(code_begin); // Creation also verifies the object. - return MacroAssembler::get_target_addr_pcrel(move->next_instruction_address()); -} - -void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) { - NativeMovConstReg* move = nativeMovConstReg_at(code_begin); // Creation also verifies the object. - return (void*)move->data(); -} diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index ea691342b23..9ee38c619f0 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2023 SAP SE. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -447,9 +447,6 @@ void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, // Do the check. check_klass_subtype(Rsub_klass, Rsuper_klass, Rtmp1, Rtmp2, ok_is_subtype); - - // Profile the failure of the check. - profile_typecheck_failed(Rtmp1, Rtmp2); } // Pop topmost element from stack. It just disappears. @@ -1425,7 +1422,7 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver, } // Record the receiver type. - record_klass_in_profile(receiver, mdp, reg2, true); + record_klass_in_profile(receiver, mdp, reg2); bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. @@ -1448,11 +1445,9 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver, void InterpreterMacroAssembler::record_klass_in_profile_helper( Register receiver, Register mdp, Register reg2, int start_row, - Label& done, bool is_virtual_call) { + Label& done) { if (TypeProfileWidth == 0) { - if (is_virtual_call) { - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - } + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); return; } @@ -1487,23 +1482,19 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper( z_ltgr(reg2, reg2); if (start_row == last_row) { // The only thing left to do is handle the null case. - if (is_virtual_call) { - z_brz(found_null); - // Receiver did not match any saved receiver and there is no empty row for it. - // Increment total counter to indicate polymorphic case. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - z_bru(done); - bind(found_null); - } else { - z_brnz(done); - } + z_brz(found_null); + // Receiver did not match any saved receiver and there is no empty row for it. + // Increment total counter to indicate polymorphic case. + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + z_bru(done); + bind(found_null); break; } // Since null is rare, make it be the branch-taken case. z_brz(found_null); // Put all the "Case 3" tests here. - record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call); + record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done); // Found a null. Keep searching for a matching receiver, // but remember that this is an empty (unused) slot. @@ -1550,12 +1541,11 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper( // done: void InterpreterMacroAssembler::record_klass_in_profile(Register receiver, - Register mdp, Register reg2, - bool is_virtual_call) { + Register mdp, Register reg2) { assert(ProfileInterpreter, "must be profiling"); Label done; - record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call); + record_klass_in_profile_helper(receiver, mdp, reg2, 0, done); bind (done); } @@ -1615,24 +1605,6 @@ void InterpreterMacroAssembler::profile_null_seen(Register mdp) { } } -void InterpreterMacroAssembler::profile_typecheck_failed(Register mdp, Register tmp) { - if (ProfileInterpreter && TypeProfileCasts) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - int count_offset = in_bytes(CounterData::count_offset()); - // Back up the address, since we have already bumped the mdp. - count_offset -= in_bytes(VirtualCallData::virtual_call_data_size()); - - // *Decrement* the counter. We expect to see zero or small negatives. - increment_mdp_data_at(mdp, count_offset, tmp, true); - - bind (profile_continue); - } -} - void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass, Register reg2) { if (ProfileInterpreter) { Label profile_continue; @@ -1646,7 +1618,7 @@ void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass, mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); // Record the object type. - record_klass_in_profile(klass, mdp, reg2, false); + record_klass_in_profile(klass, mdp, reg2); } update_mdp_by_constant(mdp, mdp_delta); diff --git a/src/hotspot/cpu/s390/interp_masm_s390.hpp b/src/hotspot/cpu/s390/interp_masm_s390.hpp index 56abe295876..f94473b1700 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.hpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2023 SAP SE. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -281,10 +281,10 @@ class InterpreterMacroAssembler: public MacroAssembler { Label& not_equal_continue); void record_klass_in_profile(Register receiver, Register mdp, - Register reg2, bool is_virtual_call); + Register reg2); void record_klass_in_profile_helper(Register receiver, Register mdp, Register reg2, int start_row, - Label& done, bool is_virtual_call); + Label& done); void update_mdp_by_offset(Register mdp_in, int offset_of_offset); void update_mdp_by_offset(Register mdp_in, Register dataidx, int offset_of_disp); @@ -301,7 +301,6 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_ret(Register return_bci, Register mdp); void profile_null_seen(Register mdp); void profile_typecheck(Register mdp, Register klass, Register scratch); - void profile_typecheck_failed(Register mdp, Register tmp); void profile_switch_default(Register mdp); void profile_switch_case(Register index_in_scratch, Register mdp, Register scratch1, Register scratch2); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index d95a0b3a3c5..0226d494c89 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "asm/codeBuffer.hpp" #include "asm/macroAssembler.inline.hpp" +#include "code/compiledIC.hpp" #include "compiler/disassembler.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetAssembler.hpp" @@ -1097,7 +1098,13 @@ void MacroAssembler::clear_mem(const Address& addr, unsigned int size) { } void MacroAssembler::align(int modulus) { - while (offset() % modulus != 0) z_nop(); + align(modulus, offset()); +} + +void MacroAssembler::align(int modulus, int target) { + assert(((modulus % 2 == 0) && (target % 2 == 0)), "needs to be even"); + int delta = target - offset(); + while ((offset() + delta) % modulus != 0) z_nop(); } // Special version for non-relocateable code if required alignment @@ -2150,6 +2157,45 @@ void MacroAssembler::call_VM_leaf_base(address entry_point) { call_VM_leaf_base(entry_point, allow_relocation); } +int MacroAssembler::ic_check_size() { + return 30 + (ImplicitNullChecks ? 0 : 6); +} + +int MacroAssembler::ic_check(int end_alignment) { + Register R2_receiver = Z_ARG1; + Register R0_scratch = Z_R0_scratch; + Register R1_scratch = Z_R1_scratch; + Register R9_data = Z_inline_cache; + Label success, failure; + + // The UEP of a code blob ensures that the VEP is padded. However, the padding of the UEP is placed + // before the inline cache check, so we don't have to execute any nop instructions when dispatching + // through the UEP, yet we can ensure that the VEP is aligned appropriately. That's why we align + // before the inline cache check here, and not after + align(end_alignment, offset() + ic_check_size()); + + int uep_offset = offset(); + if (!ImplicitNullChecks) { + z_cgij(R2_receiver, 0, Assembler::bcondEqual, failure); + } + + if (UseCompressedClassPointers) { + z_llgf(R1_scratch, Address(R2_receiver, oopDesc::klass_offset_in_bytes())); + } else { + z_lg(R1_scratch, Address(R2_receiver, oopDesc::klass_offset_in_bytes())); + } + z_cg(R1_scratch, Address(R9_data, in_bytes(CompiledICData::speculated_klass_offset()))); + z_bre(success); + + bind(failure); + load_const(R1_scratch, AddressLiteral(SharedRuntime::get_ic_miss_stub())); + z_br(R1_scratch); + bind(success); + + assert((offset() % end_alignment) == 0, "Misaligned verified entry point, offset() = %d, end_alignment = %d", offset(), end_alignment); + return uep_offset; +} + void MacroAssembler::call_VM_base(Register oop_result, Register last_java_sp, address entry_point, @@ -3744,7 +3790,7 @@ void MacroAssembler::compare_klass_ptr(Register Rop1, int64_t disp, Register Rba Register current = Rop1; Label done; - if (maybenull) { // null ptr must be preserved! + if (maybenull) { // null pointer must be preserved! z_ltgr(Z_R0, current); z_bre(done); current = Z_R0; @@ -3883,7 +3929,7 @@ void MacroAssembler::compare_heap_oop(Register Rop1, Address mem, bool maybenull Label done; int pow2_offset = get_oop_base_complement(Z_R1, ((uint64_t)(intptr_t)base)); - if (maybenull) { // null ptr must be preserved! + if (maybenull) { // null pointer must be preserved! z_ltgr(Z_R0, Rop1); z_bre(done); } @@ -4123,7 +4169,7 @@ void MacroAssembler::oop_decoder(Register Rdst, Register Rsrc, bool maybenull, R Label done; // Rsrc contains a narrow oop. Thus we are sure the leftmost bits will never be set. - if (maybenull) { // null ptr must be preserved! + if (maybenull) { // null pointer must be preserved! z_slag(Rdst, Rsrc, oop_shift); // Arithmetic shift sets the condition code. z_bre(done); } else { @@ -4185,7 +4231,7 @@ void MacroAssembler::oop_decoder(Register Rdst, Register Rsrc, bool maybenull, R // Scale oop and check for null. // Rsrc contains a narrow oop. Thus we are sure the leftmost bits will never be set. - if (maybenull) { // null ptr must be preserved! + if (maybenull) { // null pointer must be preserved! z_slag(Rdst_tmp, Rsrc, oop_shift); // Arithmetic shift sets the condition code. z_bre(done); } else { diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index bf14b42e2d1..924583abdf5 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -257,6 +257,7 @@ class MacroAssembler: public Assembler { // nop padding void align(int modulus); + void align(int modulus, int target); void align_address(int modulus); // @@ -566,6 +567,9 @@ class MacroAssembler: public Assembler { // Get the pc where the last call will return to. Returns _last_calls_return_pc. inline address last_calls_return_pc(); + static int ic_check_size(); + int ic_check(int end_alignment); + private: static bool is_call_far_patchable_variant0_at(address instruction_addr); // Dynamic TOC: load target addr from CP and call. static bool is_call_far_patchable_variant2_at(address instruction_addr); // PC-relative call, prefixed with NOPs. diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 9f4e182a9e4..5db2db9d32c 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2017, 2022 SAP SE. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // @@ -740,7 +740,7 @@ int emit_call_reloc(C2_MacroAssembler &_masm, intptr_t entry_point, relocInfo::r if (rtype == relocInfo::runtime_call_w_cp_type) { assert((__ offset() & 2) == 0, "misaligned emit_call_reloc"); address call_addr = __ call_c_opt((address)entry_point); - if (call_addr == NULL) { + if (call_addr == nullptr) { Compile::current()->env()->record_out_of_memory_failure(); return -1; } @@ -835,7 +835,7 @@ void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const { st->print_cr("push_frame %d", (int)-framesize); st->print("\t"); - if (C->stub_function() == NULL) { + if (C->stub_function() == nullptr) { st->print("nmethod entry barrier\n\t"); } } @@ -890,7 +890,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { constant_table.set_table_base_offset(constant_table.calculate_table_base_offset()); } - if (C->stub_function() == NULL) { + if (C->stub_function() == nullptr) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->nmethod_entry_barrier(&_masm); } @@ -1056,7 +1056,7 @@ uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, boo bool src12 = Immediate::is_uimm12(src_offset); bool dst12 = Immediate::is_uimm12(dst_offset); - const char *mnemo = NULL; + const char *mnemo = nullptr; unsigned long opc = 0; // Memory->Memory Spill. Use Z_R0 to hold the value. @@ -1199,7 +1199,7 @@ uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, boo #if !defined(PRODUCT) void MachSpillCopyNode::format(PhaseRegAlloc *ra_, outputStream *os) const { if (ra_ && ra_->node_regs_max_index() > 0) { - implementation(NULL, ra_, false, os); + implementation(nullptr, ra_, false, os); } else { if (req() == 2 && in(1)) { os->print("N%d = N%d\n", _idx, in(1)->_idx); @@ -1217,11 +1217,11 @@ void MachSpillCopyNode::format(PhaseRegAlloc *ra_, outputStream *os) const { #endif void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - implementation(&cbuf, ra_, false, NULL); + implementation(&cbuf, ra_, false, nullptr); } uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { - return implementation(NULL, ra_, true, NULL); + return implementation(nullptr, ra_, true, nullptr); } //============================================================================= @@ -1341,51 +1341,9 @@ void MachUEPNode::format(PhaseRegAlloc *ra_, outputStream *os) const { #endif void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { + // This is Unverified Entry Point C2_MacroAssembler _masm(&cbuf); - const int ic_miss_offset = 2; - - // Inline_cache contains a klass. - Register ic_klass = as_Register(Matcher::inline_cache_reg_encode()); - // ARG1 is the receiver oop. - Register R2_receiver = Z_ARG1; - int klass_offset = oopDesc::klass_offset_in_bytes(); - AddressLiteral icmiss(SharedRuntime::get_ic_miss_stub()); - Register R1_ic_miss_stub_addr = Z_R1_scratch; - - // Null check of receiver. - // This is the null check of the receiver that actually should be - // done in the caller. It's here because in case of implicit null - // checks we get it for free. - assert(!MacroAssembler::needs_explicit_null_check(oopDesc::klass_offset_in_bytes()), - "second word in oop should not require explicit null check."); - if (!ImplicitNullChecks) { - Label valid; - if (VM_Version::has_CompareBranch()) { - __ z_cgij(R2_receiver, 0, Assembler::bcondNotEqual, valid); - } else { - __ z_ltgr(R2_receiver, R2_receiver); - __ z_bre(valid); - } - // The ic_miss_stub will handle the null pointer exception. - __ load_const_optimized(R1_ic_miss_stub_addr, icmiss); - __ z_br(R1_ic_miss_stub_addr); - __ bind(valid); - } - - // Check whether this method is the proper implementation for the class of - // the receiver (ic miss check). - { - Label valid; - // Compare cached class against klass from receiver. - // This also does an implicit null check! - __ compare_klass_ptr(ic_klass, klass_offset, R2_receiver, false); - __ z_bre(valid); - // The inline cache points to the wrong method. Call the - // ic_miss_stub to find the proper method. - __ load_const_optimized(R1_ic_miss_stub_addr, icmiss); - __ z_br(R1_ic_miss_stub_addr); - __ bind(valid); - } + __ ic_check(CodeEntryAlignment); } uint MachUEPNode::size(PhaseRegAlloc *ra_) const { @@ -1446,7 +1404,7 @@ int HandlerImpl::emit_exception_handler(CodeBuffer &cbuf) { C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_exception_handler()); - if (base == NULL) { + if (base == nullptr) { return 0; // CodeBuffer::expand failed } @@ -1467,7 +1425,7 @@ int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_deopt_handler()); - if (base == NULL) { + if (base == nullptr) { return 0; // CodeBuffer::expand failed } @@ -1513,7 +1471,7 @@ bool Matcher::match_rule_supported(int opcode) { return true; // Per default match rules are supported. } -bool Matcher::match_rule_supported_superword(int opcode, int vlen, BasicType bt) { +bool Matcher::match_rule_supported_auto_vectorization(int opcode, int vlen, BasicType bt) { return match_rule_supported_vector(opcode, vlen, bt); } @@ -1533,11 +1491,11 @@ bool Matcher::vector_needs_partial_operations(Node* node, const TypeVect* vt) { } const RegMask* Matcher::predicate_reg_mask(void) { - return NULL; + return nullptr; } const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { - return NULL; + return nullptr; } // Vector calling convention not yet implemented. @@ -1574,7 +1532,7 @@ int Matcher::min_vector_size(const BasicType bt) { return max_vector_size(bt); // Same as max. } -int Matcher::superword_max_vector_size(const BasicType bt) { +int Matcher::max_vector_size_auto_vectorization(const BasicType bt) { return Matcher::max_vector_size(bt); } @@ -1602,7 +1560,7 @@ bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) { MachOper* Matcher::pd_specialize_generic_vector_operand(MachOper* original_opnd, uint ideal_reg, bool is_temp) { ShouldNotReachHere(); // generic vector operands not supported - return NULL; + return nullptr; } bool Matcher::is_reg2reg_move(MachNode* m) { @@ -1948,12 +1906,12 @@ encode %{ C2_MacroAssembler _masm(&cbuf); Label* p = $lbl$$label; - // 'p' is `NULL' when this encoding class is used only to + // 'p' is `nullptr' when this encoding class is used only to // determine the size of the encoded instruction. // Use a bound dummy label in that case. Label d; __ bind(d); - Label& l = (NULL == p) ? d : *(p); + Label& l = (nullptr == p) ? d : *(p); __ z_brul(l); %} @@ -1961,12 +1919,12 @@ encode %{ C2_MacroAssembler _masm(&cbuf); Label* p = $lbl$$label; - // 'p' is `NULL' when this encoding class is used only to + // 'p' is `nullptr' when this encoding class is used only to // determine the size of the encoded instruction. // Use a bound dummy label in that case. Label d; __ bind(d); - Label& l = (NULL == p) ? d : *(p); + Label& l = (nullptr == p) ? d : *(p); __ z_bru(l); %} @@ -1974,12 +1932,12 @@ encode %{ C2_MacroAssembler _masm(&cbuf); Label* p = $lbl$$label; - // 'p' is `NULL' when this encoding class is used only to + // 'p' is `nullptr' when this encoding class is used only to // determine the size of the encoded instruction. // Use a bound dummy label in that case. Label d; __ bind(d); - Label& l = (NULL == p) ? d : *(p); + Label& l = (nullptr == p) ? d : *(p); __ z_brcl((Assembler::branch_condition)$cmp$$cmpcode, l); %} @@ -1987,12 +1945,12 @@ encode %{ C2_MacroAssembler _masm(&cbuf); Label* p = $lbl$$label; - // 'p' is `NULL' when this encoding class is used only to + // 'p' is `nullptr' when this encoding class is used only to // determine the size of the encoded instruction. // Use a bound dummy label in that case. Label d; __ bind(d); - Label& l = (NULL == p) ? d : *(p); + Label& l = (nullptr == p) ? d : *(p); __ z_brc((Assembler::branch_condition)$cmp$$cmpcode, l); %} @@ -2000,12 +1958,12 @@ encode %{ C2_MacroAssembler _masm(&cbuf); Label* p = $lbl$$label; - // 'p' is `NULL' when this encoding class is used only to + // 'p' is `nullptr' when this encoding class is used only to // determine the size of the encoded instruction. // Use a bound dummy label in that case. Label d; __ bind(d); - Label& l = (NULL == p) ? d : *(p); + Label& l = (nullptr == p) ? d : *(p); Assembler::branch_condition cc = (Assembler::branch_condition)$cmp$$cmpcode; unsigned long instr = $primary; if (instr == CRJ_ZOPC) { @@ -2024,12 +1982,12 @@ encode %{ C2_MacroAssembler _masm(&cbuf); Label* p = $lbl$$label; - // 'p' is `NULL' when this encoding class is used only to + // 'p' is `nullptr' when this encoding class is used only to // determine the size of the encoded instruction. // Use a bound dummy label in that case. Label d; __ bind(d); - Label& l = (NULL == p) ? d : *(p); + Label& l = (nullptr == p) ? d : *(p); unsigned long instr = $primary; if (instr == CR_ZOPC) { @@ -2050,12 +2008,12 @@ encode %{ C2_MacroAssembler _masm(&cbuf); Label* p = $lbl$$label; - // 'p' is `NULL' when this encoding class is used only to + // 'p' is `nullptr' when this encoding class is used only to // determine the size of the encoded instruction. // Use a bound dummy label in that case. Label d; __ bind(d); - Label& l = (NULL == p) ? d : *(p); + Label& l = (nullptr == p) ? d : *(p); Assembler::branch_condition cc = (Assembler::branch_condition)$cmp$$cmpcode; unsigned long instr = $primary; @@ -2075,12 +2033,12 @@ encode %{ C2_MacroAssembler _masm(&cbuf); Label* p = $lbl$$label; - // 'p' is `NULL' when this encoding class is used only to + // 'p' is `nullptr' when this encoding class is used only to // determine the size of the encoded instruction. // Use a bound dummy label in that case. Label d; __ bind(d); - Label& l = (NULL == p) ? d : *(p); + Label& l = (nullptr == p) ? d : *(p); unsigned long instr = $primary; if (instr == CHI_ZOPC) { @@ -2112,7 +2070,7 @@ encode %{ assert((__ offset() & 2) == 0, "misaligned z_enc_java_to_runtime_call"); address call_addr = __ call_c_opt((address)$meth$$method); - if (call_addr == NULL) { + if (call_addr == nullptr) { Compile::current()->env()->record_out_of_memory_failure(); return; } @@ -2143,11 +2101,11 @@ encode %{ static_call_Relocation::spec(method_index)); } } - assert(__ inst_mark() != NULL, "emit_call_reloc must set_inst_mark()"); + assert(__ inst_mark() != nullptr, "emit_call_reloc must set_inst_mark()"); if (_method) { // Emit stub for static call. - address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); - if (stub == NULL) { + address stub = CompiledDirectCall::emit_to_interp_stub(cbuf); + if (stub == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -2162,7 +2120,7 @@ encode %{ int vtable_index = this->_vtable_index; if (vtable_index == -4) { Register ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode()); - address virtual_call_oop_addr = NULL; + address virtual_call_oop_addr = nullptr; AddressLiteral empty_ic((address) Universe::non_oop_word()); virtual_call_oop_addr = __ pc(); @@ -2929,7 +2887,7 @@ operand immP8() %{ // POINTER specific values //----------------------------------- -// Pointer Immediate: NULL +// Pointer Immediate: nullptr operand immP0() %{ predicate(n->get_ptr() == 0); match(ConP); @@ -2966,7 +2924,7 @@ operand immN8() %{ interface(CONST_INTER); %} -// Narrow NULL Pointer Immediate +// Narrow Null Pointer Immediate operand immN0() %{ predicate(n->get_narrowcon() == 0); match(ConN); @@ -3383,7 +3341,7 @@ operand inline_cache_regP(iRegP reg) %{ // Operands to remove register moves in unscaled mode. // Match read/write registers with an EncodeP node if neither shift nor add are required. operand iRegP2N(iRegP reg) %{ - predicate(CompressedOops::shift() == 0 && _leaf->as_EncodeP()->in(0) == NULL); + predicate(CompressedOops::shift() == 0 && _leaf->as_EncodeP()->in(0) == nullptr); constraint(ALLOC_IN_RC(z_memory_ptr_reg)); match(EncodeP reg); format %{ "$reg" %} @@ -3391,8 +3349,8 @@ operand iRegP2N(iRegP reg) %{ %} operand iRegN2P(iRegN reg) %{ - predicate(CompressedOops::base() == NULL && CompressedOops::shift() == 0 && - _leaf->as_DecodeN()->in(0) == NULL); + predicate(CompressedOops::base() == nullptr && CompressedOops::shift() == 0 && + _leaf->as_DecodeN()->in(0) == nullptr); constraint(ALLOC_IN_RC(z_memory_ptr_reg)); match(DecodeN reg); format %{ "$reg" %} @@ -4236,7 +4194,7 @@ instruct loadConL_pcrelTOC(iRegL dst, immL src) %{ format %{ "LGRL $dst,[pcrelTOC]\t # load long $src from table" %} ins_encode %{ address long_address = __ long_constant($src$$constant); - if (long_address == NULL) { + if (long_address == nullptr) { Compile::current()->env()->record_out_of_memory_failure(); return; } @@ -4292,14 +4250,14 @@ instruct loadConP_pcrelTOC(iRegP dst, immP src) %{ } else if (constant_reloc == relocInfo::metadata_type) { AddressLiteral a = __ constant_metadata_address((Metadata *)$src$$constant); address const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); - if (const_toc_addr == NULL) { + if (const_toc_addr == nullptr) { Compile::current()->env()->record_out_of_memory_failure(); return; } __ load_long_pcrelative($dst$$Register, const_toc_addr); } else { // Non-oop pointers, e.g. card mark base, heap top. address long_address = __ long_constant((jlong)$src$$constant); - if (long_address == NULL) { + if (long_address == nullptr) { Compile::current()->env()->record_out_of_memory_failure(); return; } @@ -4314,7 +4272,7 @@ instruct loadConP0(iRegP dst, immP0 src, flagsReg cr) %{ match(Set dst src); effect(KILL cr); size(4); - format %{ "XGR $dst,$dst\t # NULL ptr" %} + format %{ "XGR $dst,$dst\t # null pointer" %} opcode(XGR_ZOPC); ins_encode(z_rreform(dst, dst)); ins_pipe(pipe_class_dummy); @@ -4660,7 +4618,7 @@ instruct loadConNKlass(iRegN dst, immNKlass src) %{ instruct decodeLoadN(iRegP dst, memory mem) %{ match(Set dst (DecodeN (LoadN mem))); - predicate(false && (CompressedOops::base()==NULL)&&(CompressedOops::shift()==0)); + predicate(false && (CompressedOops::base()==nullptr)&&(CompressedOops::shift()==0)); ins_cost(MEMORY_REF_COST); size(Z_DISP3_SIZE); format %{ "DecodeLoadN $dst,$mem\t # (cOop Load+Decode)" %} @@ -4671,7 +4629,7 @@ instruct decodeLoadN(iRegP dst, memory mem) %{ instruct decodeLoadNKlass(iRegP dst, memory mem) %{ match(Set dst (DecodeNKlass (LoadNKlass mem))); - predicate(false && (CompressedKlassPointers::base()==NULL)&&(CompressedKlassPointers::shift()==0)); + predicate(false && (CompressedKlassPointers::base()==nullptr)&&(CompressedKlassPointers::shift()==0)); ins_cost(MEMORY_REF_COST); size(Z_DISP3_SIZE); format %{ "DecodeLoadNKlass $dst,$mem\t # (load/decode NKlass)" %} @@ -4699,7 +4657,7 @@ instruct decodeLoadConNKlass(iRegP dst, immNKlass src) %{ instruct decodeN(iRegP dst, iRegN src, flagsReg cr) %{ match(Set dst (DecodeN src)); effect(KILL cr); - predicate(CompressedOops::base() == NULL || !ExpandLoadingBaseDecode); + predicate(CompressedOops::base() == nullptr || !ExpandLoadingBaseDecode); ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST + BRANCH_COST); // TODO: s390 port size(VARIABLE_SIZE); format %{ "decodeN $dst,$src\t # (decode cOop)" %} @@ -4723,7 +4681,7 @@ instruct decodeN_NN(iRegP dst, iRegN src, flagsReg cr) %{ effect(KILL cr); predicate((n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull || n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant) && - (CompressedOops::base()== NULL || !ExpandLoadingBaseDecode_NN)); + (CompressedOops::base()== nullptr || !ExpandLoadingBaseDecode_NN)); ins_cost(MEMORY_REF_COST+2 * DEFAULT_COST); // TODO: s390 port size(VARIABLE_SIZE); format %{ "decodeN $dst,$src\t # (decode cOop NN)" %} @@ -4749,7 +4707,7 @@ instruct decodeN_NN(iRegP dst, iRegN src, flagsReg cr) %{ effect(KILL cr); predicate(false); // TODO: s390 port size(VARIABLE_SIZE); - format %{ "decodeN $dst = ($src == 0) ? NULL : ($src << 3) + $base + pow2_offset\t # (decode cOop)" %} + format %{ "decodeN $dst = ($src == 0) ? nullptr : ($src << 3) + $base + pow2_offset\t # (decode cOop)" %} ins_encode %{ __ oop_decoder($dst$$Register, $src$$Register, true, $base$$Register, (jlong)MacroAssembler::get_oop_base_pow2_offset((uint64_t)(intptr_t)CompressedOops::base())); @@ -4774,7 +4732,7 @@ instruct decodeN_NN(iRegP dst, iRegN src, flagsReg cr) %{ // Decoder for heapbased mode peeling off loading the base. instruct decodeN_Ex(iRegP dst, iRegN src, flagsReg cr) %{ match(Set dst (DecodeN src)); - predicate(CompressedOops::base() != NULL && ExpandLoadingBaseDecode); + predicate(CompressedOops::base() != nullptr && ExpandLoadingBaseDecode); ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST + BRANCH_COST); // TODO: s390 port size(VARIABLE_SIZE); expand %{ @@ -4790,7 +4748,7 @@ instruct decodeN_NN_Ex(iRegP dst, iRegN src, flagsReg cr) %{ match(Set dst (DecodeN src)); predicate((n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull || n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant) && - CompressedOops::base() != NULL && ExpandLoadingBaseDecode_NN); + CompressedOops::base() != nullptr && ExpandLoadingBaseDecode_NN); ins_cost(MEMORY_REF_COST+2 * DEFAULT_COST); // TODO: s390 port size(VARIABLE_SIZE); expand %{ @@ -6069,7 +6027,7 @@ instruct addP_reg_reg_imm12(iRegP dst, memoryRegP src1, iRegL src2, uimmL12 con) instruct addP_regN_reg_imm12(iRegP dst, iRegP_N2P src1, iRegL src2, uimmL12 con) %{ match(Set dst (AddP (AddP src1 src2) con)); - predicate( PreferLAoverADD && CompressedOops::base() == NULL && CompressedOops::shift() == 0); + predicate( PreferLAoverADD && CompressedOops::base() == nullptr && CompressedOops::shift() == 0); ins_cost(DEFAULT_COST_LOW); size(4); format %{ "LA $dst,$con($src1,$src2)\t # ptr d12(x,b)" %} @@ -6091,7 +6049,7 @@ instruct addP_reg_reg_imm20(iRegP dst, memoryRegP src1, iRegL src2, immL20 con) instruct addP_regN_reg_imm20(iRegP dst, iRegP_N2P src1, iRegL src2, immL20 con) %{ match(Set dst (AddP (AddP src1 src2) con)); - predicate( PreferLAoverADD && CompressedOops::base() == NULL && CompressedOops::shift() == 0); + predicate( PreferLAoverADD && CompressedOops::base() == nullptr && CompressedOops::shift() == 0); ins_cost(DEFAULT_COST); // TODO: s390 port size(FIXED_SIZE); format %{ "LAY $dst,$con($src1,$src2)\t # ptr d20(x,b)" %} @@ -8427,7 +8385,7 @@ instruct compP_reg_imm0(flagsReg cr, iRegP_N2P op1, immP0 op2) %{ // Don't use LTGFR which performs sign extend. instruct compP_decode_reg_imm0(flagsReg cr, iRegN op1, immP0 op2) %{ match(Set cr (CmpP (DecodeN op1) op2)); - predicate(CompressedOops::base() == NULL && CompressedOops::shift() == 0); + predicate(CompressedOops::base() == nullptr && CompressedOops::shift() == 0); ins_cost(DEFAULT_COST_LOW); size(2); format %{ "LTR $op1, $op1\t # ptr" %} @@ -9843,24 +9801,10 @@ instruct string_equalsL(iRegP str1, iRegP str2, iRegI cnt, iRegI result, roddReg ins_pipe(pipe_class_dummy); %} -instruct string_equalsU(iRegP str1, iRegP str2, iRegI cnt, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{ - match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(TEMP oddReg, TEMP evenReg, KILL cr); // R0, R1 are killed, too. - predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU || ((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::none); - ins_cost(300); - format %{ "String Equals char[] $str1,$str2,$cnt -> $result" %} - ins_encode %{ - __ array_equals(false, $str1$$Register, $str2$$Register, - $cnt$$Register, $oddReg$$Register, $evenReg$$Register, - $result$$Register, false /* byte */); - %} - ins_pipe(pipe_class_dummy); -%} - instruct string_equals_imm(iRegP str1, iRegP str2, uimmI8 cnt, iRegI result, flagsReg cr) %{ match(Set result (StrEquals (Binary str1 str2) cnt)); effect(KILL cr); // R0 is killed, too. - predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::LL || ((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU); + predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::LL); ins_cost(100); format %{ "String Equals byte[] $str1,$str2,$cnt -> $result" %} ins_encode %{ diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index ed1795cfa33..11e1e617d8e 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -26,8 +26,8 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" #include "code/debugInfoRec.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" +#include "code/compiledIC.hpp" #include "compiler/oopMap.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "gc/shared/gcLocker.hpp" @@ -35,7 +35,6 @@ #include "interpreter/interp_masm.hpp" #include "memory/resourceArea.hpp" #include "nativeInst_s390.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/klass.inline.hpp" #include "prims/methodHandles.hpp" #include "registerSaver_s390.hpp" @@ -1500,17 +1499,15 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, unsigned int wrapper_FrameDone; unsigned int wrapper_CRegsSet; Label handle_pending_exception; - Label ic_miss; //--------------------------------------------------------------------- // Unverified entry point (UEP) //--------------------------------------------------------------------- - wrapper_UEPStart = __ offset(); // check ic: object class <-> cached class - if (!method_is_static) __ nmethod_UEP(ic_miss); - // Fill with nops (alignment of verified entry point). - __ align(CodeEntryAlignment); + if (!method_is_static) { + wrapper_UEPStart = __ ic_check(CodeEntryAlignment /* end_alignment */); + } //--------------------------------------------------------------------- // Verified entry point (VEP) @@ -2026,13 +2023,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ restore_return_pc(); __ z_br(Z_R1_scratch); - //--------------------------------------------------------------------- - // Handler for a cache miss (out-of-line) - //--------------------------------------------------------------------- - __ call_ic_miss_handler(ic_miss, 0x77, 0, Z_R1_scratch); __ flush(); - - ////////////////////////////////////////////////////////////////////// // end of code generation ////////////////////////////////////////////////////////////////////// @@ -2318,9 +2309,6 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm Label skip_fixup; { Label ic_miss; - const int klass_offset = oopDesc::klass_offset_in_bytes(); - const int holder_klass_offset = in_bytes(CompiledICHolder::holder_klass_offset()); - const int holder_metadata_offset = in_bytes(CompiledICHolder::holder_metadata_offset()); // Out-of-line call to ic_miss handler. __ call_ic_miss_handler(ic_miss, 0x11, 0, Z_R1_scratch); @@ -2329,27 +2317,11 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm __ align(CodeEntryAlignment); c2i_unverified_entry = __ pc(); - // Check the pointers. - if (!ImplicitNullChecks || MacroAssembler::needs_explicit_null_check(klass_offset)) { - __ z_ltgr(Z_ARG1, Z_ARG1); - __ z_bre(ic_miss); - } - __ verify_oop(Z_ARG1, FILE_AND_LINE); - - // Check ic: object class <-> cached class - // Compress cached class for comparison. That's more efficient. - if (UseCompressedClassPointers) { - __ z_lg(Z_R11, holder_klass_offset, Z_method); // Z_R11 is overwritten a few instructions down anyway. - __ compare_klass_ptr(Z_R11, klass_offset, Z_ARG1, false); // Cached class can't be zero. - } else { - __ z_clc(klass_offset, sizeof(void *)-1, Z_ARG1, holder_klass_offset, Z_method); - } - __ z_brne(ic_miss); // Cache miss: call runtime to handle this. - + __ ic_check(2); + __ z_lg(Z_method, Address(Z_inline_cache, CompiledICData::speculated_method_offset())); // This def MUST MATCH code in gen_c2i_adapter! const Register code = Z_R11; - __ z_lg(Z_method, holder_metadata_offset, Z_method); __ load_and_test_long(Z_R0, method_(code)); __ z_brne(ic_miss); // Cache miss: call runtime to handle this. diff --git a/src/hotspot/cpu/s390/templateTable_s390.cpp b/src/hotspot/cpu/s390/templateTable_s390.cpp index 62d62a9842f..02b9405ad31 100644 --- a/src/hotspot/cpu/s390/templateTable_s390.cpp +++ b/src/hotspot/cpu/s390/templateTable_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2023 SAP SE. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2868,7 +2868,7 @@ void TemplateTable::jvmti_post_field_mod(Register cache, __ z_lgr(fieldEntry, cache); if (is_static) { - // Life is simple. NULL the object pointer. + // Life is simple. Null the object pointer. __ clear_reg(obj, true, false); // Don't set CC. } else { // Life is harder. The stack holds the value on top, followed by @@ -3914,20 +3914,15 @@ void TemplateTable::_new() { __ z_cli(0, tmp, JVM_CONSTANT_Class); __ z_brne(slow_case); - __ z_sllg(offset, offset, LogBytesPerWord); // Convert to to offset. + __ z_sllg(offset, offset, LogBytesPerWord); // Convert to offset. // Get InstanceKlass. Register iklass = cpool; __ load_resolved_klass_at_offset(cpool, offset, iklass); - // Make sure klass is initialized & doesn't have finalizer. - // Make sure klass is fully initialized. - const int state_offset = in_bytes(InstanceKlass::init_state_offset()); - if (Immediate::is_uimm12(state_offset)) { - __ z_cli(state_offset, iklass, InstanceKlass::fully_initialized); - } else { - __ z_cliy(state_offset, iklass, InstanceKlass::fully_initialized); - } - __ z_brne(slow_case); + // make sure klass is initialized + assert(VM_Version::supports_fast_class_init_checks(), + "Optimization requires support for fast class initialization checks"); + __ clinit_barrier(iklass, Z_thread, nullptr /*L_fast_path*/, &slow_case); // Get instance_size in InstanceKlass (scaled to a count of bytes). Register Rsize = offset; diff --git a/src/hotspot/cpu/s390/vm_version_s390.hpp b/src/hotspot/cpu/s390/vm_version_s390.hpp index 93d5b11c473..7ac60a10ae7 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.hpp +++ b/src/hotspot/cpu/s390/vm_version_s390.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2022 SAP SE. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -567,7 +567,6 @@ class VM_Version: public Abstract_VM_Version { static unsigned long z_SIGSEGV(); static void initialize_cpu_information(void); - static bool profile_all_receivers_at_type_check() { return false; } }; #endif // CPU_S390_VM_VERSION_S390_HPP diff --git a/src/hotspot/cpu/s390/vtableStubs_s390.cpp b/src/hotspot/cpu/s390/vtableStubs_s390.cpp index 5a79369ceab..573c23d7967 100644 --- a/src/hotspot/cpu/s390/vtableStubs_s390.cpp +++ b/src/hotspot/cpu/s390/vtableStubs_s390.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2021 SAP SE. All rights reserved. + * Copyright (c) 2016, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,10 +25,10 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "code/compiledIC.hpp" #include "code/vtableStubs.hpp" #include "interp_masm_s390.hpp" #include "memory/resourceArea.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/klassVtable.hpp" @@ -197,12 +197,12 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { __ load_klass(rcvr_klass, Z_ARG1); // Receiver subtype check against REFC. - __ z_lg(interface, Address(Z_method, CompiledICHolder::holder_klass_offset())); + __ z_lg(interface, Address(Z_method, CompiledICData::itable_refc_klass_offset())); __ lookup_interface_method(rcvr_klass, interface, noreg, noreg, Z_R1, no_such_interface, /*return_method=*/ false); // Get Method* and entrypoint for compiler - __ z_lg(interface, Address(Z_method, CompiledICHolder::holder_metadata_offset())); + __ z_lg(interface, Address(Z_method, CompiledICData::itable_defc_klass_offset())); __ lookup_interface_method(rcvr_klass, interface, itable_index, Z_method, Z_R1, no_such_interface, /*return_method=*/ true); diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 63d6ec9b00f..9482537d84f 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -1089,7 +1089,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { break; case 0x62: // EVEX_4bytes - assert(VM_Version::supports_evex(), "shouldn't have EVEX prefix"); + assert(VM_Version::cpu_supports_evex(), "shouldn't have EVEX prefix"); assert(ip == inst+1, "no prefixes allowed"); // no EVEX collisions, all instructions that have 0x62 opcodes // have EVEX versions and are subopcodes of 0x66 diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 7b907218f35..8b512fac6bc 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -816,8 +816,8 @@ class Assembler : public AbstractAssembler { void check_relocation(RelocationHolder const& rspec, int format); #endif - void emit_data(jint data, relocInfo::relocType rtype, int format); - void emit_data(jint data, RelocationHolder const& rspec, int format); + void emit_data(jint data, relocInfo::relocType rtype, int format = 0); + void emit_data(jint data, RelocationHolder const& rspec, int format = 0); void emit_data64(jlong data, relocInfo::relocType rtype, int format = 0); void emit_data64(jlong data, RelocationHolder const& rspec, int format = 0); diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index ff0726840d3..3b7a3cec2d8 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -72,7 +72,6 @@ static jlong *double_signflip_pool = double_quadword(&fp_signmask_pool[4*2], (jl NEEDS_CLEANUP // remove this definitions ? -const Register IC_Klass = rax; // where the IC klass is cached const Register SYNC_header = rax; // synchronization header const Register SHIFT_count = rcx; // where count for shift operations must be @@ -336,23 +335,7 @@ void LIR_Assembler::osr_entry() { // inline cache check; done before the frame is built. int LIR_Assembler::check_icache() { - Register receiver = FrameMap::receiver_opr->as_register(); - Register ic_klass = IC_Klass; - const int ic_cmp_size = LP64_ONLY(10) NOT_LP64(9); - const bool do_post_padding = VerifyOops || UseCompressedClassPointers; - if (!do_post_padding) { - // insert some nops so that the verified entry point is aligned on CodeEntryAlignment - __ align(CodeEntryAlignment, __ offset() + ic_cmp_size); - } - int offset = __ offset(); - __ inline_cache_check(receiver, IC_Klass); - assert(__ offset() % CodeEntryAlignment == 0 || do_post_padding, "alignment must be correct"); - if (do_post_padding) { - // force alignment after the cache check. - // It's been verified to be aligned if !VerifyOops - __ align(CodeEntryAlignment); - } - return offset; + return __ ic_check(CodeEntryAlignment); } void LIR_Assembler::clinit_barrier(ciMethod* method) { diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index b6a27abf0f3..7088cf33cf6 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1207,9 +1207,10 @@ void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) { __ move(result_reg, result); } +#ifndef _LP64 // _i2l, _i2f, _i2d, _l2i, _l2f, _l2d, _f2i, _f2l, _f2d, _d2i, _d2l, _d2f // _i2b, _i2c, _i2s -LIR_Opr fixed_register_for(BasicType type) { +static LIR_Opr fixed_register_for(BasicType type) { switch (type) { case T_FLOAT: return FrameMap::fpu0_float_opr; case T_DOUBLE: return FrameMap::fpu0_double_opr; @@ -1218,6 +1219,7 @@ LIR_Opr fixed_register_for(BasicType type) { default: ShouldNotReachHere(); return LIR_OprFact::illegalOpr; } } +#endif void LIRGenerator::do_Convert(Convert* x) { #ifdef _LP64 diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index 78361a305ae..0c4544f5bc4 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "c1/c1_MacroAssembler.hpp" #include "c1/c1_Runtime1.hpp" +#include "code/compiledIC.hpp" #include "compiler/compilerDefinitions.inline.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetAssembler.hpp" @@ -34,10 +35,12 @@ #include "oops/arrayOop.hpp" #include "oops/markWord.hpp" #include "runtime/basicLock.hpp" +#include "runtime/globals.hpp" #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/checkedCast.hpp" +#include "utilities/globalDefinitions.hpp" int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register tmp, Label& slow_case) { const int aligned_mask = BytesPerWord -1; @@ -60,9 +63,6 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr jcc(Assembler::notZero, slow_case); } - // Load object header - movptr(hdr, Address(obj, hdr_offset)); - if (LockingMode == LM_LIGHTWEIGHT) { #ifdef _LP64 const Register thread = r15_thread; @@ -73,6 +73,8 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr lightweight_lock(obj, hdr, thread, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { Label done; + // Load object header + movptr(hdr, Address(obj, hdr_offset)); // and mark it as unlocked orptr(hdr, markWord::unlocked_value); // save unlocked object header into the displaced header location on the stack @@ -134,9 +136,14 @@ void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_ verify_oop(obj); if (LockingMode == LM_LIGHTWEIGHT) { - movptr(disp_hdr, Address(obj, hdr_offset)); - andptr(disp_hdr, ~(int32_t)markWord::lock_mask_in_place); - lightweight_unlock(obj, disp_hdr, hdr, slow_case); +#ifdef _LP64 + lightweight_unlock(obj, disp_hdr, r15_thread, hdr, slow_case); +#else + // This relies on the implementation of lightweight_unlock being able to handle + // that the reg_rax and thread Register parameters may alias each other. + get_thread(disp_hdr); + lightweight_unlock(obj, disp_hdr, disp_hdr, hdr, slow_case); +#endif } else if (LockingMode == LM_LEGACY) { // test if object header is pointing to the displaced header, and if so, restore // the displaced header in the object - if the object header is not pointing to @@ -295,30 +302,6 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1, verify_oop(obj); } - - -void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) { - verify_oop(receiver); - // explicit null check not needed since load from [klass_offset] causes a trap - // check against inline cache - assert(!MacroAssembler::needs_explicit_null_check(oopDesc::klass_offset_in_bytes()), "must add explicit null check"); - int start_offset = offset(); - - if (UseCompressedClassPointers) { - load_klass(rscratch1, receiver, rscratch2); - cmpptr(rscratch1, iCache); - } else { - cmpptr(iCache, Address(receiver, oopDesc::klass_offset_in_bytes())); - } - // if icache check fails, then jump to runtime routine - // Note: RECEIVER must still contain the receiver! - jump_cc(Assembler::notEqual, - RuntimeAddress(SharedRuntime::get_ic_miss_stub())); - const int ic_cmp_size = LP64_ONLY(10) NOT_LP64(9); - assert(UseCompressedClassPointers || offset() - start_offset == ic_cmp_size, "check alignment in emit_method_entry"); -} - - void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_bytes) { assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect"); // Make sure there is enough stack space for this method's activation. diff --git a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp index 8b56f464f27..2c24c0c2cfb 100644 --- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp +++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp @@ -38,7 +38,6 @@ #include "interpreter/interpreter.hpp" #include "memory/universe.hpp" #include "nativeInst_x86.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "register_x86.hpp" diff --git a/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp index b9b4e8af02c..6dc8d14064a 100644 --- a/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp +++ b/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,26 +73,74 @@ void C2EntryBarrierStub::emit(C2_MacroAssembler& masm) { __ jmp(continuation(), false /* maybe_short */); } -#ifdef _LP64 -int C2HandleAnonOMOwnerStub::max_size() const { - // Max size of stub has been determined by testing with 0, in which case - // C2CodeStubList::emit() will throw an assertion and report the actual size that - // is needed. - return DEBUG_ONLY(36) NOT_DEBUG(21); +int C2FastUnlockLightweightStub::max_size() const { + return 128; } -void C2HandleAnonOMOwnerStub::emit(C2_MacroAssembler& masm) { - __ bind(entry()); - Register mon = monitor(); - Register t = tmp(); - __ movptr(Address(mon, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), r15_thread); - __ subl(Address(r15_thread, JavaThread::lock_stack_top_offset()), oopSize); +void C2FastUnlockLightweightStub::emit(C2_MacroAssembler& masm) { + assert(_t == rax, "must be"); + + Label restore_held_monitor_count_and_slow_path; + + { // Restore lock-stack and handle the unlock in runtime. + + __ bind(_push_and_slow_path); #ifdef ASSERT - __ movl(t, Address(r15_thread, JavaThread::lock_stack_top_offset())); - __ movptr(Address(r15_thread, t), 0); + // The obj was only cleared in debug. + __ movl(_t, Address(_thread, JavaThread::lock_stack_top_offset())); + __ movptr(Address(_thread, _t), _obj); #endif - __ jmp(continuation()); -} + __ addl(Address(_thread, JavaThread::lock_stack_top_offset()), oopSize); + } + + { // Restore held monitor count and slow path. + + __ bind(restore_held_monitor_count_and_slow_path); + // Restore held monitor count. + __ increment(Address(_thread, JavaThread::held_monitor_count_offset())); + // increment will always result in ZF = 0 (no overflows). + __ jmp(slow_path_continuation()); + } + + { // Handle monitor medium path. + + __ bind(_check_successor); + + Label fix_zf_and_unlocked; + const Register monitor = _mark; + +#ifndef _LP64 + __ jmpb(restore_held_monitor_count_and_slow_path); +#else // _LP64 + // successor null check. + __ cmpptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), NULL_WORD); + __ jccb(Assembler::equal, restore_held_monitor_count_and_slow_path); + + // Release lock. + __ movptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); + + // Fence. + // Instead of MFENCE we use a dummy locked add of 0 to the top-of-stack. + __ lock(); __ addl(Address(rsp, 0), 0); + + // Recheck successor. + __ cmpptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), NULL_WORD); + // Observed a successor after the release -> fence we have handed off the monitor + __ jccb(Assembler::notEqual, fix_zf_and_unlocked); + + // Try to relock, if it fails the monitor has been handed over + // TODO: Caveat, this may fail due to deflation, which does + // not handle the monitor handoff. Currently only works + // due to the responsible thread. + __ xorptr(rax, rax); + __ lock(); __ cmpxchgptr(_thread, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); + __ jccb (Assembler::equal, restore_held_monitor_count_and_slow_path); #endif + __ bind(fix_zf_and_unlocked); + __ xorl(rax, rax); + __ jmp(unlocked_continuation()); + } +} + #undef __ diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 3817c38f4ba..b6ecde62af6 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -33,9 +33,13 @@ #include "opto/output.hpp" #include "opto/opcodes.hpp" #include "opto/subnode.hpp" +#include "runtime/globals.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/checkedCast.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/powerOfTwo.hpp" +#include "utilities/sizes.hpp" #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ @@ -554,6 +558,7 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp RTMLockingCounters* stack_rtm_counters, Metadata* method_data, bool use_rtm, bool profile_rtm) { + assert(LockingMode != LM_LIGHTWEIGHT, "lightweight locking should use fast_lock_lightweight"); // Ensure the register assignments are disjoint assert(tmpReg == rax, ""); @@ -605,7 +610,8 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp if (LockingMode == LM_MONITOR) { // Clear ZF so that we take the slow path at the DONE label. objReg is known to be not 0. testptr(objReg, objReg); - } else if (LockingMode == LM_LEGACY) { + } else { + assert(LockingMode == LM_LEGACY, "must be"); // Attempt stack-locking ... orptr (tmpReg, markWord::unlocked_value); movptr(Address(boxReg, 0), tmpReg); // Anticipate successful CAS @@ -620,10 +626,6 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp // Next instruction set ZFlag == 1 (Success) if difference is less then one page. andptr(tmpReg, (int32_t) (NOT_LP64(0xFFFFF003) LP64_ONLY(7 - (int)os::vm_page_size())) ); movptr(Address(boxReg, 0), tmpReg); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, ""); - lightweight_lock(objReg, tmpReg, thread, scrReg, NO_COUNT); - jmp(COUNT); } jmp(DONE_LABEL); @@ -754,6 +756,7 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp // Xcheck:jni is enabled. void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpReg, bool use_rtm) { + assert(LockingMode != LM_LIGHTWEIGHT, "lightweight locking should use fast_unlock_lightweight"); assert(boxReg == rax, ""); assert_different_registers(objReg, boxReg, tmpReg); @@ -784,23 +787,6 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t } // It's inflated. - if (LockingMode == LM_LIGHTWEIGHT) { - // If the owner is ANONYMOUS, we need to fix it - in an outline stub. - testb(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), (int32_t) ObjectMonitor::ANONYMOUS_OWNER); -#ifdef _LP64 - if (!Compile::current()->output()->in_scratch_emit_size()) { - C2HandleAnonOMOwnerStub* stub = new (Compile::current()->comp_arena()) C2HandleAnonOMOwnerStub(tmpReg, boxReg); - Compile::current()->output()->add_stub(stub); - jcc(Assembler::notEqual, stub->entry()); - bind(stub->continuation()); - } else -#endif - { - // We can't easily implement this optimization on 32 bit because we don't have a thread register. - // Call the slow-path instead. - jcc(Assembler::notEqual, NO_COUNT); - } - } #if INCLUDE_RTM_OPT if (use_rtm) { @@ -922,19 +908,14 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t jmpb (DONE_LABEL); #endif - if (LockingMode != LM_MONITOR) { + if (LockingMode == LM_LEGACY) { bind (Stacked); - if (LockingMode == LM_LIGHTWEIGHT) { - mov(boxReg, tmpReg); - lightweight_unlock(objReg, boxReg, tmpReg, NO_COUNT); - jmp(COUNT); - } else if (LockingMode == LM_LEGACY) { - movptr(tmpReg, Address (boxReg, 0)); // re-fetch - lock(); - cmpxchgptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Uses RAX which is box - } + movptr(tmpReg, Address (boxReg, 0)); // re-fetch + lock(); + cmpxchgptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Uses RAX which is box // Intentional fall-thru into DONE_LABEL } + bind(DONE_LABEL); // ZFlag == 1 count in fast path @@ -955,6 +936,247 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t bind(NO_COUNT); } +void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Register rax_reg, + Register t, Register thread) { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + assert(rax_reg == rax, "Used for CAS"); + assert_different_registers(obj, box, rax_reg, t, thread); + + // Handle inflated monitor. + Label inflated; + // Finish fast lock successfully. ZF value is irrelevant. + Label locked; + // Finish fast lock unsuccessfully. MUST jump with ZF == 0 + Label slow_path; + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(rax_reg, obj, t); + movl(rax_reg, Address(rax_reg, Klass::access_flags_offset())); + testl(rax_reg, JVM_ACC_IS_VALUE_BASED_CLASS); + jcc(Assembler::notZero, slow_path); + } + + const Register mark = t; + + { // Lightweight Lock + + Label push; + + const Register top = box; + + // Load the mark. + movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); + + // Prefetch top. + movl(top, Address(thread, JavaThread::lock_stack_top_offset())); + + // Check for monitor (0b10). + testptr(mark, markWord::monitor_value); + jcc(Assembler::notZero, inflated); + + // Check if lock-stack is full. + cmpl(top, LockStack::end_offset() - 1); + jcc(Assembler::greater, slow_path); + + // Check if recursive. + cmpptr(obj, Address(thread, top, Address::times_1, -oopSize)); + jccb(Assembler::equal, push); + + // Try to lock. Transition lock bits 0b01 => 0b00 + movptr(rax_reg, mark); + orptr(rax_reg, markWord::unlocked_value); + andptr(mark, ~(int32_t)markWord::unlocked_value); + lock(); cmpxchgptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); + jcc(Assembler::notEqual, slow_path); + + bind(push); + // After successful lock, push object on lock-stack. + movptr(Address(thread, top), obj); + addl(Address(thread, JavaThread::lock_stack_top_offset()), oopSize); + jmpb(locked); + } + + { // Handle inflated monitor. + bind(inflated); + + const Register tagged_monitor = mark; + + // CAS owner (null => current thread). + xorptr(rax_reg, rax_reg); + lock(); cmpxchgptr(thread, Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); + jccb(Assembler::equal, locked); + + // Check if recursive. + cmpptr(thread, rax_reg); + jccb(Assembler::notEqual, slow_path); + + // Recursive. + increment(Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + } + + bind(locked); + increment(Address(thread, JavaThread::held_monitor_count_offset())); + // Set ZF = 1 + xorl(rax_reg, rax_reg); + +#ifdef ASSERT + // Check that locked label is reached with ZF set. + Label zf_correct; + jccb(Assembler::zero, zf_correct); + stop("Fast Lock ZF != 1"); +#endif + + bind(slow_path); +#ifdef ASSERT + // Check that slow_path label is reached with ZF not set. + jccb(Assembler::notZero, zf_correct); + stop("Fast Lock ZF != 0"); + bind(zf_correct); +#endif + // C2 uses the value of ZF to determine the continuation. +} + +void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, Register t, Register thread) { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + assert(reg_rax == rax, "Used for CAS"); + assert_different_registers(obj, reg_rax, t); + + // Handle inflated monitor. + Label inflated, inflated_check_lock_stack; + // Finish fast unlock successfully. MUST jump with ZF == 1 + Label unlocked; + + // Assume success. + decrement(Address(thread, JavaThread::held_monitor_count_offset())); + + const Register mark = t; + const Register top = reg_rax; + + Label dummy; + C2FastUnlockLightweightStub* stub = nullptr; + + if (!Compile::current()->output()->in_scratch_emit_size()) { + stub = new (Compile::current()->comp_arena()) C2FastUnlockLightweightStub(obj, mark, reg_rax, thread); + Compile::current()->output()->add_stub(stub); + } + + Label& push_and_slow_path = stub == nullptr ? dummy : stub->push_and_slow_path(); + Label& check_successor = stub == nullptr ? dummy : stub->check_successor(); + + { // Lightweight Unlock + + // Load top. + movl(top, Address(thread, JavaThread::lock_stack_top_offset())); + + // Prefetch mark. + movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); + + // Check if obj is top of lock-stack. + cmpptr(obj, Address(thread, top, Address::times_1, -oopSize)); + // Top of lock stack was not obj. Must be monitor. + jcc(Assembler::notEqual, inflated_check_lock_stack); + + // Pop lock-stack. + DEBUG_ONLY(movptr(Address(thread, top, Address::times_1, -oopSize), 0);) + subl(Address(thread, JavaThread::lock_stack_top_offset()), oopSize); + + // Check if recursive. + cmpptr(obj, Address(thread, top, Address::times_1, -2 * oopSize)); + jcc(Assembler::equal, unlocked); + + // We elide the monitor check, let the CAS fail instead. + + // Try to unlock. Transition lock bits 0b00 => 0b01 + movptr(reg_rax, mark); + andptr(reg_rax, ~(int32_t)markWord::lock_mask); + orptr(mark, markWord::unlocked_value); + lock(); cmpxchgptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); + jcc(Assembler::notEqual, push_and_slow_path); + jmp(unlocked); + } + + + { // Handle inflated monitor. + bind(inflated_check_lock_stack); +#ifdef ASSERT + Label check_done; + subl(top, oopSize); + cmpl(top, in_bytes(JavaThread::lock_stack_base_offset())); + jcc(Assembler::below, check_done); + cmpptr(obj, Address(thread, top)); + jccb(Assembler::notEqual, inflated_check_lock_stack); + stop("Fast Unlock lock on stack"); + bind(check_done); + testptr(mark, markWord::monitor_value); + jccb(Assembler::notZero, inflated); + stop("Fast Unlock not monitor"); +#endif + + bind(inflated); + + // mark contains the tagged ObjectMonitor*. + const Register monitor = mark; + +#ifndef _LP64 + // Check if recursive. + xorptr(reg_rax, reg_rax); + orptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + jcc(Assembler::notZero, check_successor); + + // Check if the entry lists are empty. + movptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); + orptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); + jcc(Assembler::notZero, check_successor); + + // Release lock. + movptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); +#else // _LP64 + Label recursive; + + // Check if recursive. + cmpptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 0); + jccb(Assembler::notEqual, recursive); + + // Check if the entry lists are empty. + movptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); + orptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); + jcc(Assembler::notZero, check_successor); + + // Release lock. + movptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); + jmpb(unlocked); + + // Recursive unlock. + bind(recursive); + decrement(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + xorl(t, t); +#endif + } + + bind(unlocked); + if (stub != nullptr) { + bind(stub->unlocked_continuation()); + } + +#ifdef ASSERT + // Check that unlocked label is reached with ZF set. + Label zf_correct; + jccb(Assembler::zero, zf_correct); + stop("Fast Unlock ZF != 1"); +#endif + + if (stub != nullptr) { + bind(stub->slow_path_continuation()); + } +#ifdef ASSERT + // Check that stub->continuation() label is reached with ZF not set. + jccb(Assembler::notZero, zf_correct); + stop("Fast Unlock ZF != 0"); + bind(zf_correct); +#endif + // C2 uses the value of ZF to determine the continuation. +} + //------------------------------------------------------------------------------------------- // Generic instructions support for use in .ad files C2 code generation @@ -5282,6 +5504,42 @@ void C2_MacroAssembler::vector_mask_compress(KRegister dst, KRegister src, Regis kmov(dst, rtmp2); } +#ifdef _LP64 +void C2_MacroAssembler::vector_compress_expand_avx2(int opcode, XMMRegister dst, XMMRegister src, + XMMRegister mask, Register rtmp, Register rscratch, + XMMRegister permv, XMMRegister xtmp, BasicType bt, + int vec_enc) { + assert(type2aelembytes(bt) >= 4, ""); + assert(opcode == Op_CompressV || opcode == Op_ExpandV, ""); + address compress_perm_table = nullptr; + address expand_perm_table = nullptr; + if (type2aelembytes(bt) == 8) { + compress_perm_table = StubRoutines::x86::compress_perm_table64(); + expand_perm_table = StubRoutines::x86::expand_perm_table64(); + vmovmskpd(rtmp, mask, vec_enc); + } else { + compress_perm_table = StubRoutines::x86::compress_perm_table32(); + expand_perm_table = StubRoutines::x86::expand_perm_table32(); + vmovmskps(rtmp, mask, vec_enc); + } + shlq(rtmp, 5); // for 32 byte permute row. + if (opcode == Op_CompressV) { + lea(rscratch, ExternalAddress(compress_perm_table)); + } else { + lea(rscratch, ExternalAddress(expand_perm_table)); + } + addptr(rtmp, rscratch); + vmovdqu(permv, Address(rtmp)); + vpermps(dst, permv, src, Assembler::AVX_256bit); + vpxor(xtmp, xtmp, xtmp, vec_enc); + // Blend the result with zero vector using permute mask, each column entry + // in a permute table row contains either a valid permute index or a -1 (default) + // value, this can potentially be used as a blending mask after + // compressing/expanding the source vector lanes. + vblendvps(dst, dst, xtmp, permv, vec_enc, false, permv); +} +#endif + void C2_MacroAssembler::vector_compress_expand(int opcode, XMMRegister dst, XMMRegister src, KRegister mask, bool merge, BasicType bt, int vec_enc) { if (opcode == Op_CompressV) { diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index e9e1412957b..26f7fb44aa9 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,10 @@ bool use_rtm, bool profile_rtm); void fast_unlock(Register obj, Register box, Register tmp, bool use_rtm); + void fast_lock_lightweight(Register obj, Register box, Register rax_reg, + Register t, Register thread); + void fast_unlock_lightweight(Register obj, Register reg_rax, Register t, Register thread); + #if INCLUDE_RTM_OPT void rtm_counters_update(Register abort_status, Register rtm_counters); void branch_on_random_using_rdtsc(Register tmp, Register scr, int count, Label& brLabel); @@ -390,6 +394,10 @@ void vector_round_float_avx(XMMRegister dst, XMMRegister src, AddressLiteral float_sign_flip, AddressLiteral new_mxcsr, int vec_enc, Register tmp, XMMRegister xtmp1, XMMRegister xtmp2, XMMRegister xtmp3, XMMRegister xtmp4); + + void vector_compress_expand_avx2(int opcode, XMMRegister dst, XMMRegister src, XMMRegister mask, + Register rtmp, Register rscratch, XMMRegister permv, XMMRegister xtmp, + BasicType bt, int vec_enc); #endif // _LP64 void udivI(Register rax, Register divisor, Register rdx); diff --git a/src/hotspot/cpu/x86/compiledIC_x86.cpp b/src/hotspot/cpu/x86/compiledIC_x86.cpp index 8fc001039fb..95b41f62b6a 100644 --- a/src/hotspot/cpu/x86/compiledIC_x86.cpp +++ b/src/hotspot/cpu/x86/compiledIC_x86.cpp @@ -26,7 +26,6 @@ #include "asm/macroAssembler.inline.hpp" #include "code/codeCache.hpp" #include "code/compiledIC.hpp" -#include "code/icBuffer.hpp" #include "code/nmethod.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" @@ -36,7 +35,7 @@ // ---------------------------------------------------------------------------- #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { +address CompiledDirectCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { // Stub is fixed up when the corresponding call is converted from // calling compiled code to calling interpreted code. // movq rbx, 0 @@ -66,32 +65,25 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) } #undef __ -int CompiledStaticCall::to_interp_stub_size() { +int CompiledDirectCall::to_interp_stub_size() { return NOT_LP64(10) // movl; jmp LP64_ONLY(15); // movq (1+1+8); jmp (1+4) } -int CompiledStaticCall::to_trampoline_stub_size() { +int CompiledDirectCall::to_trampoline_stub_size() { // x86 doesn't use trampolines. return 0; } // Relocation entries for call stub, compiled java to interpreter. -int CompiledStaticCall::reloc_to_interp_stub() { +int CompiledDirectCall::reloc_to_interp_stub() { return 4; // 3 in emit_to_interp_stub + 1 in emit_call } -void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) { +void CompiledDirectCall::set_to_interpreted(const methodHandle& callee, address entry) { address stub = find_stub(); guarantee(stub != nullptr, "stub not found"); - { - ResourceMark rm; - log_trace(inlinecache)("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s", - p2i(instruction_address()), - callee->name_and_sig_as_C_string()); - } - // Creation also verifies the object. NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); @@ -105,7 +97,7 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad set_destination_mt_safe(stub); } -void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) { +void CompiledDirectCall::set_stub_to_clean(static_stub_Relocation* static_stub) { assert(CompiledICLocker::is_safe(static_stub->addr()), "mt unsafe call"); // Reset stub. address stub = static_stub->addr(); @@ -122,7 +114,7 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_ // Non-product mode code #ifndef PRODUCT -void CompiledDirectStaticCall::verify() { +void CompiledDirectCall::verify() { // Verify call. _call->verify(); _call->verify_alignment(); diff --git a/src/hotspot/cpu/x86/icBuffer_x86.cpp b/src/hotspot/cpu/x86/icBuffer_x86.cpp deleted file mode 100644 index af374b57416..00000000000 --- a/src/hotspot/cpu/x86/icBuffer_x86.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/icBuffer.hpp" -#include "gc/shared/collectedHeap.inline.hpp" -#include "interpreter/bytecodes.hpp" -#include "memory/resourceArea.hpp" -#include "nativeInst_x86.hpp" -#include "oops/oop.inline.hpp" - -int InlineCacheBuffer::ic_stub_code_size() { - // Worst case, if destination is not a near call: - // lea rax, lit1 - // lea scratch, lit2 - // jmp scratch - - // Best case - // lea rax, lit1 - // jmp lit2 - - int best = NativeMovConstReg::instruction_size + NativeJump::instruction_size; - int worst = 2 * NativeMovConstReg::instruction_size + 3; - return MAX2(best, worst); -} - - - -void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin, void* cached_value, address entry_point) { - ResourceMark rm; - CodeBuffer code(code_begin, ic_stub_code_size()); - MacroAssembler* masm = new MacroAssembler(&code); - // note: even though the code contains an embedded value, we do not need reloc info - // because - // (1) the value is old (i.e., doesn't matter for scavenges) - // (2) these ICStubs are removed *before* a GC happens, so the roots disappear - // assert(cached_value == nullptr || cached_oop->is_perm(), "must be perm oop"); - masm->lea(rax, AddressLiteral((address) cached_value, relocInfo::metadata_type)); - masm->jump(ExternalAddress(entry_point)); -} - - -address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) { - NativeMovConstReg* move = nativeMovConstReg_at(code_begin); // creation also verifies the object - address jmp = move->next_instruction_address(); - NativeInstruction* ni = nativeInstruction_at(jmp); - if (ni->is_jump()) { - NativeJump* jump = nativeJump_at(jmp); - return jump->jump_destination(); - } else { - assert(ni->is_far_jump(), "unexpected instruction"); - NativeFarJump* jump = nativeFarJump_at(jmp); - return jump->jump_destination(); - } -} - - -void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) { - // creation also verifies the object - NativeMovConstReg* move = nativeMovConstReg_at(code_begin); - // Verifies the jump - address jmp = move->next_instruction_address(); - NativeInstruction* ni = nativeInstruction_at(jmp); - if (ni->is_jump()) { - NativeJump* jump = nativeJump_at(jmp); - } else { - assert(ni->is_far_jump(), "unexpected instruction"); - NativeFarJump* jump = nativeFarJump_at(jmp); - } - void* o = (void*)move->data(); - return o; -} diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index f5f83ae21f4..33570f3155b 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1192,8 +1192,6 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) { const Register thread = lock_reg; get_thread(thread); #endif - // Load object header, prepare for CAS from unlocked to locked. - movptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); lightweight_lock(obj_reg, swap_reg, thread, tmp_reg, slow_case); } else if (LockingMode == LM_LEGACY) { // Load immediate 1 into swap_reg %rax @@ -1311,20 +1309,13 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) { if (LockingMode == LM_LIGHTWEIGHT) { #ifdef _LP64 - const Register thread = r15_thread; + lightweight_unlock(obj_reg, swap_reg, r15_thread, header_reg, slow_case); #else - const Register thread = header_reg; - get_thread(thread); + // This relies on the implementation of lightweight_unlock being able to handle + // that the reg_rax and thread Register parameters may alias each other. + get_thread(swap_reg); + lightweight_unlock(obj_reg, swap_reg, swap_reg, header_reg, slow_case); #endif - // Handle unstructured locking. - Register tmp = swap_reg; - movl(tmp, Address(thread, JavaThread::lock_stack_top_offset())); - cmpptr(obj_reg, Address(thread, tmp, Address::times_1, -oopSize)); - jcc(Assembler::notEqual, slow_case); - // Try to swing header from locked to unlocked. - movptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - andptr(swap_reg, ~(int32_t)markWord::lock_mask_in_place); - lightweight_unlock(obj_reg, swap_reg, header_reg, slow_case); } else if (LockingMode == LM_LEGACY) { // Load the old header from BasicLock structure movptr(header_reg, Address(swap_reg, diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 88296656485..f0e7a08dd5f 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "asm/assembler.hpp" #include "asm/assembler.inline.hpp" +#include "code/compiledIC.hpp" #include "compiler/compiler_globals.hpp" #include "compiler/disassembler.hpp" #include "crc32c.h" @@ -1341,13 +1342,45 @@ void MacroAssembler::ic_call(address entry, jint method_index) { RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); #ifdef _LP64 // Needs full 64-bit immediate for later patching. - mov64(rax, (intptr_t)Universe::non_oop_word()); + mov64(rax, (int64_t)Universe::non_oop_word()); #else movptr(rax, (intptr_t)Universe::non_oop_word()); #endif call(AddressLiteral(entry, rh)); } +int MacroAssembler::ic_check_size() { + return LP64_ONLY(14) NOT_LP64(12); +} + +int MacroAssembler::ic_check(int end_alignment) { + Register receiver = LP64_ONLY(j_rarg0) NOT_LP64(rcx); + Register data = rax; + Register temp = LP64_ONLY(rscratch1) NOT_LP64(rbx); + + // The UEP of a code blob ensures that the VEP is padded. However, the padding of the UEP is placed + // before the inline cache check, so we don't have to execute any nop instructions when dispatching + // through the UEP, yet we can ensure that the VEP is aligned appropriately. That's why we align + // before the inline cache check here, and not after + align(end_alignment, offset() + ic_check_size()); + + int uep_offset = offset(); + + if (UseCompressedClassPointers) { + movl(temp, Address(receiver, oopDesc::klass_offset_in_bytes())); + cmpl(temp, Address(data, CompiledICData::speculated_klass_offset())); + } else { + movptr(temp, Address(receiver, oopDesc::klass_offset_in_bytes())); + cmpptr(temp, Address(data, CompiledICData::speculated_klass_offset())); + } + + // if inline cache check fails, then jump to runtime routine + jump_cc(Assembler::notEqual, RuntimeAddress(SharedRuntime::get_ic_miss_stub())); + assert((offset() % end_alignment) == 0, "Misaligned verified entry point"); + + return uep_offset; +} + void MacroAssembler::emit_static_call_stub() { // Static stub relocation also tags the Method* in the code-stream. mov_metadata(rbx, (Metadata*) nullptr); // Method is zapped till fixup time. @@ -2568,7 +2601,9 @@ void MacroAssembler::movptr(Register dst, Address src) { // src should NEVER be a real pointer. Use AddressLiteral for true pointers void MacroAssembler::movptr(Register dst, intptr_t src) { #ifdef _LP64 - if (is_simm32(src)) { + if (is_uimm32(src)) { + movl(dst, checked_cast(src)); + } else if (is_simm32(src)) { movq(dst, checked_cast(src)); } else { mov64(dst, src); @@ -4085,8 +4120,9 @@ static void restore_xmm_register(MacroAssembler* masm, int offset, XMMRegister r } } -int register_section_sizes(RegSet gp_registers, XMMRegSet xmm_registers, bool save_fpu, - int& gp_area_size, int& fp_area_size, int& xmm_area_size) { +static int register_section_sizes(RegSet gp_registers, XMMRegSet xmm_registers, + bool save_fpu, int& gp_area_size, + int& fp_area_size, int& xmm_area_size) { gp_area_size = align_up(gp_registers.size() * Register::max_slots_per_register * VMRegImpl::stack_slot_size, StackAlignmentInBytes); @@ -4352,7 +4388,7 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, } // Look up the method for a megamorphic invokeinterface call in a single pass over itable: -// - check recv_klass (actual object class) is a subtype of resolved_klass from CompiledICHolder +// - check recv_klass (actual object class) is a subtype of resolved_klass from CompiledICData // - find a holder_klass (class that implements the method) vtable offset and get the method from vtable by index // The target method is determined by . // The receiver klass is in recv_klass. @@ -9875,68 +9911,116 @@ void MacroAssembler::check_stack_alignment(Register sp, const char* msg, unsigne } // Implements lightweight-locking. -// Branches to slow upon failure to lock the object, with ZF cleared. -// Falls through upon success with unspecified ZF. // // obj: the object to be locked -// hdr: the (pre-loaded) header of the object, must be rax +// reg_rax: rax // thread: the thread which attempts to lock obj // tmp: a temporary register -void MacroAssembler::lightweight_lock(Register obj, Register hdr, Register thread, Register tmp, Label& slow) { - assert(hdr == rax, "header must be in rax for cmpxchg"); - assert_different_registers(obj, hdr, thread, tmp); - - // First we need to check if the lock-stack has room for pushing the object reference. - // Note: we subtract 1 from the end-offset so that we can do a 'greater' comparison, instead - // of 'greaterEqual' below, which readily clears the ZF. This makes C2 code a little simpler and - // avoids one branch. - cmpl(Address(thread, JavaThread::lock_stack_top_offset()), LockStack::end_offset() - 1); - jcc(Assembler::greater, slow); - - // Now we attempt to take the fast-lock. - // Clear lock_mask bits (locked state). - andptr(hdr, ~(int32_t)markWord::lock_mask_in_place); - movptr(tmp, hdr); - // Set unlocked_value bit. - orptr(hdr, markWord::unlocked_value); - lock(); - cmpxchgptr(tmp, Address(obj, oopDesc::mark_offset_in_bytes())); +void MacroAssembler::lightweight_lock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow) { + assert(reg_rax == rax, ""); + assert_different_registers(obj, reg_rax, thread, tmp); + + Label push; + const Register top = tmp; + + // Preload the markWord. It is important that this is the first + // instruction emitted as it is part of C1's null check semantics. + movptr(reg_rax, Address(obj, oopDesc::mark_offset_in_bytes())); + + // Load top. + movl(top, Address(thread, JavaThread::lock_stack_top_offset())); + + // Check if the lock-stack is full. + cmpl(top, LockStack::end_offset()); + jcc(Assembler::greaterEqual, slow); + + // Check for recursion. + cmpptr(obj, Address(thread, top, Address::times_1, -oopSize)); + jcc(Assembler::equal, push); + + // Check header for monitor (0b10). + testptr(reg_rax, markWord::monitor_value); + jcc(Assembler::notZero, slow); + + // Try to lock. Transition lock bits 0b01 => 0b00 + movptr(tmp, reg_rax); + andptr(tmp, ~(int32_t)markWord::unlocked_value); + orptr(reg_rax, markWord::unlocked_value); + lock(); cmpxchgptr(tmp, Address(obj, oopDesc::mark_offset_in_bytes())); jcc(Assembler::notEqual, slow); - // If successful, push object to lock-stack. - movl(tmp, Address(thread, JavaThread::lock_stack_top_offset())); - movptr(Address(thread, tmp), obj); - incrementl(tmp, oopSize); - movl(Address(thread, JavaThread::lock_stack_top_offset()), tmp); + // Restore top, CAS clobbers register. + movl(top, Address(thread, JavaThread::lock_stack_top_offset())); + + bind(push); + // After successful lock, push object on lock-stack. + movptr(Address(thread, top), obj); + incrementl(top, oopSize); + movl(Address(thread, JavaThread::lock_stack_top_offset()), top); } // Implements lightweight-unlocking. -// Branches to slow upon failure, with ZF cleared. -// Falls through upon success, with unspecified ZF. // // obj: the object to be unlocked -// hdr: the (pre-loaded) header of the object, must be rax +// reg_rax: rax +// thread: the thread // tmp: a temporary register -void MacroAssembler::lightweight_unlock(Register obj, Register hdr, Register tmp, Label& slow) { - assert(hdr == rax, "header must be in rax for cmpxchg"); - assert_different_registers(obj, hdr, tmp); - - // Mark-word must be lock_mask now, try to swing it back to unlocked_value. - movptr(tmp, hdr); // The expected old value - orptr(tmp, markWord::unlocked_value); - lock(); - cmpxchgptr(tmp, Address(obj, oopDesc::mark_offset_in_bytes())); +// +// x86_32 Note: reg_rax and thread may alias each other due to limited register +// availiability. +void MacroAssembler::lightweight_unlock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow) { + assert(reg_rax == rax, ""); + assert_different_registers(obj, reg_rax, tmp); + LP64_ONLY(assert_different_registers(obj, reg_rax, thread, tmp);) + + Label unlocked, push_and_slow; + const Register top = tmp; + + // Check if obj is top of lock-stack. + movl(top, Address(thread, JavaThread::lock_stack_top_offset())); + cmpptr(obj, Address(thread, top, Address::times_1, -oopSize)); jcc(Assembler::notEqual, slow); - // Pop the lock object from the lock-stack. -#ifdef _LP64 - const Register thread = r15_thread; -#else - const Register thread = rax; - get_thread(thread); -#endif + + // Pop lock-stack. + DEBUG_ONLY(movptr(Address(thread, top, Address::times_1, -oopSize), 0);) subl(Address(thread, JavaThread::lock_stack_top_offset()), oopSize); + + // Check if recursive. + cmpptr(obj, Address(thread, top, Address::times_1, -2 * oopSize)); + jcc(Assembler::equal, unlocked); + + // Not recursive. Check header for monitor (0b10). + movptr(reg_rax, Address(obj, oopDesc::mark_offset_in_bytes())); + testptr(reg_rax, markWord::monitor_value); + jcc(Assembler::notZero, push_and_slow); + +#ifdef ASSERT + // Check header not unlocked (0b01). + Label not_unlocked; + testptr(reg_rax, markWord::unlocked_value); + jcc(Assembler::zero, not_unlocked); + stop("lightweight_unlock already unlocked"); + bind(not_unlocked); +#endif + + // Try to unlock. Transition lock bits 0b00 => 0b01 + movptr(tmp, reg_rax); + orptr(tmp, markWord::unlocked_value); + lock(); cmpxchgptr(tmp, Address(obj, oopDesc::mark_offset_in_bytes())); + jcc(Assembler::equal, unlocked); + + bind(push_and_slow); + // Restore lock-stack and handle the unlock in runtime. + if (thread == reg_rax) { + // On x86_32 we may lose the thread. + get_thread(thread); + } #ifdef ASSERT - movl(tmp, Address(thread, JavaThread::lock_stack_top_offset())); - movptr(Address(thread, tmp), 0); + movl(top, Address(thread, JavaThread::lock_stack_top_offset())); + movptr(Address(thread, top), obj); #endif + addl(Address(thread, JavaThread::lock_stack_top_offset()), oopSize); + jmp(slow); + + bind(unlocked); } diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 4b301684527..4789b63decc 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -896,6 +896,8 @@ class MacroAssembler: public Assembler { // Emit the CompiledIC call idiom void ic_call(address entry, jint method_index = 0); + static int ic_check_size(); + int ic_check(int end_alignment); void emit_static_call_stub(); @@ -2031,8 +2033,8 @@ class MacroAssembler: public Assembler { void check_stack_alignment(Register sp, const char* msg, unsigned bias = 0, Register tmp = noreg); - void lightweight_lock(Register obj, Register hdr, Register thread, Register tmp, Label& slow); - void lightweight_unlock(Register obj, Register hdr, Register tmp, Label& slow); + void lightweight_lock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow); + void lightweight_unlock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow); }; /** diff --git a/src/hotspot/cpu/x86/peephole_x86_64.cpp b/src/hotspot/cpu/x86/peephole_x86_64.cpp index 8c956aeb053..92a29490eda 100644 --- a/src/hotspot/cpu/x86/peephole_x86_64.cpp +++ b/src/hotspot/cpu/x86/peephole_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,8 +33,8 @@ // lea d, [s1 + s2] and // mov d, s1; shl d, s2 into // lea d, [s1 << s2] with s2 = 1, 2, 3 -bool lea_coalesce_helper(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_, - MachNode* (*new_root)(), uint inst0_rule, bool imm) { +static bool lea_coalesce_helper(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_, + MachNode* (*new_root)(), uint inst0_rule, bool imm) { MachNode* inst0 = block->get_node(block_index)->as_Mach(); assert(inst0->rule() == inst0_rule, "sanity"); @@ -136,7 +136,7 @@ bool lea_coalesce_helper(Block* block, int block_index, PhaseCFG* cfg_, PhaseReg // This helper func takes a condition and returns the flags that need to be set for the condition // It uses the same flags as the test instruction, so if the e.g. the overflow bit is required, // this func returns clears_overflow, as that is what the test instruction does and what the downstream path expects -juint map_condition_to_required_test_flags(Assembler::Condition condition) { +static juint map_condition_to_required_test_flags(Assembler::Condition condition) { switch (condition) { case Assembler::Condition::zero: // Same value as equal case Assembler::Condition::notZero: // Same value as notEqual diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index 571160523cb..febc1b2c3b1 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,8 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" +#include "code/compiledIC.hpp" #include "code/debugInfoRec.hpp" -#include "code/icBuffer.hpp" #include "code/nativeInst.hpp" #include "code/vtableStubs.hpp" #include "compiler/oopMap.hpp" @@ -36,7 +36,6 @@ #include "interpreter/interpreter.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/klass.inline.hpp" #include "prims/methodHandles.hpp" #include "runtime/jniHandles.hpp" @@ -944,25 +943,18 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm address c2i_unverified_entry = __ pc(); Label skip_fixup; - Register holder = rax; + Register data = rax; Register receiver = rcx; Register temp = rbx; { - - Label missed; - __ movptr(temp, Address(receiver, oopDesc::klass_offset_in_bytes())); - __ cmpptr(temp, Address(holder, CompiledICHolder::holder_klass_offset())); - __ movptr(rbx, Address(holder, CompiledICHolder::holder_metadata_offset())); - __ jcc(Assembler::notEqual, missed); + __ ic_check(1 /* end_alignment */); + __ movptr(rbx, Address(data, CompiledICData::speculated_method_offset())); // Method might have been compiled since the call site was patched to // interpreted if that is the case treat it as a miss so we can get // the call site corrected. __ cmpptr(Address(rbx, in_bytes(Method::code_offset())), NULL_WORD); __ jcc(Assembler::equal, skip_fixup); - - __ bind(missed); - __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); } address c2i_entry = __ pc(); @@ -1449,23 +1441,12 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // as far as the interpreter and the compiler(s) are concerned. - const Register ic_reg = rax; const Register receiver = rcx; - Label hit; Label exception_pending; __ verify_oop(receiver); - __ cmpptr(ic_reg, Address(receiver, oopDesc::klass_offset_in_bytes())); - __ jcc(Assembler::equal, hit); - - __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); - // verified entry must be aligned for code patching. - // and the first 5 bytes must be in the same cache line - // if we align at 8 then we will be sure 5 bytes are in the same line - __ align(8); - - __ bind(hit); + __ ic_check(8 /* end_alignment */); int vep_offset = ((intptr_t)__ pc()) - start; @@ -1713,8 +1694,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ jcc(Assembler::notEqual, slow_path_lock); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - // Load object header - __ movptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); __ lightweight_lock(obj_reg, swap_reg, thread, lock_reg, slow_path_lock); } __ bind(count_mon); @@ -1872,9 +1851,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ dec_held_monitor_count(); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ movptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ andptr(swap_reg, ~(int32_t)markWord::lock_mask_in_place); - __ lightweight_unlock(obj_reg, swap_reg, lock_reg, slow_path_unlock); + __ lightweight_unlock(obj_reg, swap_reg, thread, lock_reg, slow_path_unlock); __ dec_held_monitor_count(); } diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index faa423bcf8e..c666f982d0f 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ #include "asm/macroAssembler.inline.hpp" #include "code/compiledIC.hpp" #include "code/debugInfoRec.hpp" -#include "code/icBuffer.hpp" #include "code/nativeInst.hpp" #include "code/vtableStubs.hpp" #include "compiler/oopMap.hpp" @@ -42,7 +41,6 @@ #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/klass.inline.hpp" #include "oops/method.inline.hpp" #include "prims/methodHandles.hpp" @@ -1000,20 +998,14 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm address c2i_unverified_entry = __ pc(); Label skip_fixup; - Label ok; - Register holder = rax; + Register data = rax; Register receiver = j_rarg0; Register temp = rbx; { - __ load_klass(temp, receiver, rscratch1); - __ cmpptr(temp, Address(holder, CompiledICHolder::holder_klass_offset())); - __ movptr(rbx, Address(holder, CompiledICHolder::holder_metadata_offset())); - __ jcc(Assembler::equal, ok); - __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); - - __ bind(ok); + __ ic_check(1 /* end_alignment */); + __ movptr(rbx, Address(data, CompiledICData::speculated_method_offset())); // Method might have been compiled since the call site was patched to // interpreted if that is the case treat it as a miss so we can get // the call site corrected. @@ -1450,7 +1442,7 @@ static void gen_continuation_enter(MacroAssembler* masm, __ align(BytesPerWord, __ offset() + NativeCall::displacement_offset); // Emit stub for static call CodeBuffer* cbuf = masm->code_section()->outer(); - address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, __ pc()); + address stub = CompiledDirectCall::emit_to_interp_stub(*cbuf, __ pc()); if (stub == nullptr) { fatal("CodeCache is full at gen_continuation_enter"); } @@ -1487,7 +1479,7 @@ static void gen_continuation_enter(MacroAssembler* masm, // Emit stub for static call CodeBuffer* cbuf = masm->code_section()->outer(); - address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, __ pc()); + address stub = CompiledDirectCall::emit_to_interp_stub(*cbuf, __ pc()); if (stub == nullptr) { fatal("CodeCache is full at gen_continuation_enter"); } @@ -1744,6 +1736,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, in_ByteSize(-1), oop_maps, exception_offset); + if (nm == nullptr) return nm; if (method->is_continuation_enter_intrinsic()) { ContinuationEntry::set_enter_code(nm, interpreted_entry_offset); } else if (method->is_continuation_yield_intrinsic()) { @@ -1882,25 +1875,13 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // restoring them except rbp. rbp is the only callee save register // as far as the interpreter and the compiler(s) are concerned. - - const Register ic_reg = rax; const Register receiver = j_rarg0; - Label hit; Label exception_pending; - assert_different_registers(ic_reg, receiver, rscratch1, rscratch2); + assert_different_registers(receiver, rscratch1, rscratch2); __ verify_oop(receiver); - __ load_klass(rscratch1, receiver, rscratch2); - __ cmpq(ic_reg, rscratch1); - __ jcc(Assembler::equal, hit); - - __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); - - // Verified entry point must be aligned - __ align(8); - - __ bind(hit); + __ ic_check(8 /* end_alignment */); int vep_offset = ((intptr_t)__ pc()) - start; @@ -2189,8 +2170,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ jcc(Assembler::notEqual, slow_path_lock); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - // Load object header - __ movptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); __ lightweight_lock(obj_reg, swap_reg, r15_thread, rscratch1, slow_path_lock); } __ bind(count_mon); @@ -2333,9 +2312,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ dec_held_monitor_count(); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ movptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ andptr(swap_reg, ~(int32_t)markWord::lock_mask_in_place); - __ lightweight_unlock(obj_reg, swap_reg, lock_reg, slow_path_unlock); + __ lightweight_unlock(obj_reg, swap_reg, r15_thread, lock_reg, slow_path_unlock); __ dec_held_monitor_count(); } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index cad9e6475c6..71aafdc1cd3 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -951,6 +951,92 @@ address StubGenerator::generate_fp_mask(const char *stub_name, int64_t mask) { return start; } +address StubGenerator::generate_compress_perm_table(const char *stub_name, int32_t esize) { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", stub_name); + address start = __ pc(); + if (esize == 32) { + // Loop to generate 256 x 8 int compression permute index table. A row is + // accessed using 8 bit index computed using vector mask. An entry in + // a row holds either a valid permute index corresponding to set bit position + // or a -1 (default) value. + for (int mask = 0; mask < 256; mask++) { + int ctr = 0; + for (int j = 0; j < 8; j++) { + if (mask & (1 << j)) { + __ emit_data(j, relocInfo::none); + ctr++; + } + } + for (; ctr < 8; ctr++) { + __ emit_data(-1, relocInfo::none); + } + } + } else { + assert(esize == 64, ""); + // Loop to generate 16 x 4 long compression permute index table. A row is + // accessed using 4 bit index computed using vector mask. An entry in + // a row holds either a valid permute index pair for a quadword corresponding + // to set bit position or a -1 (default) value. + for (int mask = 0; mask < 16; mask++) { + int ctr = 0; + for (int j = 0; j < 4; j++) { + if (mask & (1 << j)) { + __ emit_data(2 * j, relocInfo::none); + __ emit_data(2 * j + 1, relocInfo::none); + ctr++; + } + } + for (; ctr < 4; ctr++) { + __ emit_data64(-1L, relocInfo::none); + } + } + } + return start; +} + +address StubGenerator::generate_expand_perm_table(const char *stub_name, int32_t esize) { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", stub_name); + address start = __ pc(); + if (esize == 32) { + // Loop to generate 256 x 8 int expand permute index table. A row is accessed + // using 8 bit index computed using vector mask. An entry in a row holds either + // a valid permute index (starting from least significant lane) placed at poisition + // corresponding to set bit position or a -1 (default) value. + for (int mask = 0; mask < 256; mask++) { + int ctr = 0; + for (int j = 0; j < 8; j++) { + if (mask & (1 << j)) { + __ emit_data(ctr++, relocInfo::none); + } else { + __ emit_data(-1, relocInfo::none); + } + } + } + } else { + assert(esize == 64, ""); + // Loop to generate 16 x 4 long expand permute index table. A row is accessed + // using 4 bit index computed using vector mask. An entry in a row holds either + // a valid doubleword permute index pair representing a quadword index (starting + // from least significant lane) placed at poisition corresponding to set bit + // position or a -1 (default) value. + for (int mask = 0; mask < 16; mask++) { + int ctr = 0; + for (int j = 0; j < 4; j++) { + if (mask & (1 << j)) { + __ emit_data(2 * ctr, relocInfo::none); + __ emit_data(2 * ctr + 1, relocInfo::none); + ctr++; + } else { + __ emit_data64(-1L, relocInfo::none); + } + } + } + } + return start; +} + address StubGenerator::generate_vector_mask(const char *stub_name, int64_t mask) { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", stub_name); @@ -4095,6 +4181,13 @@ void StubGenerator::generate_compiler_stubs() { StubRoutines::x86::_vector_reverse_byte_perm_mask_int = generate_vector_reverse_byte_perm_mask_int("perm_mask_int"); StubRoutines::x86::_vector_reverse_byte_perm_mask_short = generate_vector_reverse_byte_perm_mask_short("perm_mask_short"); + if (VM_Version::supports_avx2() && !VM_Version::supports_avx512vl()) { + StubRoutines::x86::_compress_perm_table32 = generate_compress_perm_table("compress_perm_table32", 32); + StubRoutines::x86::_compress_perm_table64 = generate_compress_perm_table("compress_perm_table64", 64); + StubRoutines::x86::_expand_perm_table32 = generate_expand_perm_table("expand_perm_table32", 32); + StubRoutines::x86::_expand_perm_table64 = generate_expand_perm_table("expand_perm_table64", 64); + } + if (VM_Version::supports_avx2() && !VM_Version::supports_avx512_vpopcntdq()) { // lut implementation influenced by counting 1s algorithm from section 5-1 of Hackers' Delight. StubRoutines::x86::_vector_popcount_lut = generate_popcount_avx_lut("popcount_lut"); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index 6b7da718498..db43085d37f 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,6 +99,10 @@ class StubGenerator: public StubCodeGenerator { address generate_fp_mask(const char *stub_name, int64_t mask); + address generate_compress_perm_table(const char *stub_name, int32_t esize); + + address generate_expand_perm_table(const char *stub_name, int32_t esize); + address generate_vector_mask(const char *stub_name, int64_t mask); address generate_vector_byte_perm_mask(const char *stub_name); diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.cpp b/src/hotspot/cpu/x86/stubRoutines_x86.cpp index cebf661ae75..bc1cbdbba26 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.cpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,10 @@ address StubRoutines::x86::_join_0_1_base64 = nullptr; address StubRoutines::x86::_join_1_2_base64 = nullptr; address StubRoutines::x86::_join_2_3_base64 = nullptr; address StubRoutines::x86::_decoding_table_base64 = nullptr; +address StubRoutines::x86::_compress_perm_table32 = nullptr; +address StubRoutines::x86::_compress_perm_table64 = nullptr; +address StubRoutines::x86::_expand_perm_table32 = nullptr; +address StubRoutines::x86::_expand_perm_table64 = nullptr; #endif address StubRoutines::x86::_pshuffle_byte_flip_mask_addr = nullptr; @@ -275,7 +279,7 @@ uint32_t _crc32c_pow_2k_table[TILL_CYCLE]; // because _crc32c_pow_2k_table[TILL_ // A. Kadatch and B. Jenkins / Everything we know about CRC but afraid to forget September 3, 2010 8 // Listing 1: Multiplication of normalized polynomials // "a" and "b" occupy D least significant bits. -uint32_t crc32c_multiply(uint32_t a, uint32_t b) { +static uint32_t crc32c_multiply(uint32_t a, uint32_t b) { uint32_t product = 0; uint32_t b_pow_x_table[D + 1]; // b_pow_x_table[k] = (b * x**k) mod P b_pow_x_table[0] = b; @@ -299,7 +303,7 @@ uint32_t crc32c_multiply(uint32_t a, uint32_t b) { #undef P // A. Kadatch and B. Jenkins / Everything we know about CRC but afraid to forget September 3, 2010 9 -void crc32c_init_pow_2k(void) { +static void crc32c_init_pow_2k(void) { // _crc32c_pow_2k_table(0) = // x^(2^k) mod P(x) = x mod P(x) = x // Since we are operating on a reflected values @@ -314,7 +318,7 @@ void crc32c_init_pow_2k(void) { } // x^N mod P(x) -uint32_t crc32c_f_pow_n(uint32_t n) { +static uint32_t crc32c_f_pow_n(uint32_t n) { // result = 1 (polynomial) uint32_t one, result = 0x80000000, i = 0; diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.hpp b/src/hotspot/cpu/x86/stubRoutines_x86.hpp index 6c602324f3e..cfb91c5c083 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.hpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ enum platform_dependent_constants { _continuation_stubs_code_size = 1000 LP64_ONLY(+1000), // AVX512 intrinsics add more code in 64-bit VM, // Windows have more code to save/restore registers - _compiler_stubs_code_size = 20000 LP64_ONLY(+32000) WINDOWS_ONLY(+2000), + _compiler_stubs_code_size = 20000 LP64_ONLY(+39000) WINDOWS_ONLY(+2000), _final_stubs_code_size = 10000 LP64_ONLY(+20000) WINDOWS_ONLY(+2000) ZGC_ONLY(+20000) }; @@ -58,6 +58,10 @@ class x86 { static address _float_sign_flip; static address _double_sign_mask; static address _double_sign_flip; + static address _compress_perm_table32; + static address _compress_perm_table64; + static address _expand_perm_table32; + static address _expand_perm_table64; public: @@ -338,6 +342,10 @@ class x86 { static address base64_decoding_table_addr() { return _decoding_table_base64; } static address base64_AVX2_decode_tables_addr() { return _avx2_decode_tables_base64; } static address base64_AVX2_decode_LUT_tables_addr() { return _avx2_decode_lut_tables_base64; } + static address compress_perm_table32() { return _compress_perm_table32; } + static address compress_perm_table64() { return _compress_perm_table64; } + static address expand_perm_table32() { return _expand_perm_table32; } + static address expand_perm_table64() { return _expand_perm_table64; } #endif static address pshuffle_byte_flip_mask_addr() { return _pshuffle_byte_flip_mask_addr; } static address arrays_hashcode_powers_of_31() { return (address)_arrays_hashcode_powers_of_31; } diff --git a/src/hotspot/cpu/x86/stubRoutines_x86_64.cpp b/src/hotspot/cpu/x86/stubRoutines_x86_64.cpp index 417b32eb4a6..eb6c11d7167 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86_64.cpp @@ -44,4 +44,3 @@ address StubRoutines::x86::_float_sign_mask = nullptr; address StubRoutines::x86::_float_sign_flip = nullptr; address StubRoutines::x86::_double_sign_mask = nullptr; address StubRoutines::x86::_double_sign_flip = nullptr; - diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index df1ea6edd30..2412c053106 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -809,7 +809,8 @@ void VM_Version::get_processor_features() { _stepping = cpu_stepping(); if (cpu_family() > 4) { // it supports CPUID - _features = feature_flags(); + _features = feature_flags(); // These can be changed by VM settings + _cpu_features = _features; // Preserve features // Logical processors are only available on P4s and above, // and only if hyperthreading is available. _logical_processors_per_package = logical_processor_count(); diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index e521a6ee3bc..bf5e052e167 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -640,7 +640,7 @@ class VM_Version : public Abstract_VM_Version { } // - // Feature identification + // Feature identification which can be affected by VM settings // static bool supports_cpuid() { return _features != 0; } static bool supports_cmov() { return (_features & CPU_CMOV) != 0; } @@ -703,6 +703,11 @@ class VM_Version : public Abstract_VM_Version { static bool supports_cet_ss() { return (_features & CPU_CET_SS) != 0; } static bool supports_cet_ibt() { return (_features & CPU_CET_IBT) != 0; } + // + // Feature identification not affected by VM flags + // + static bool cpu_supports_evex() { return (_cpu_features & CPU_AVX512F) != 0; } + // Intel features static bool is_intel_family_core() { return is_intel() && extended_cpu_family() == CPU_FAMILY_INTEL_CORE; } @@ -765,6 +770,10 @@ class VM_Version : public Abstract_VM_Version { return true; } + constexpr static bool supports_recursive_lightweight_locking() { + return true; + } + // For AVX CPUs only. f16c support is disabled if UseAVX == 0. static bool supports_float16() { return supports_f16c() || supports_avx512vl(); diff --git a/src/hotspot/cpu/x86/vtableStubs_x86_32.cpp b/src/hotspot/cpu/x86/vtableStubs_x86_32.cpp index 0e78e0274d7..398f2e37eb5 100644 --- a/src/hotspot/cpu/x86/vtableStubs_x86_32.cpp +++ b/src/hotspot/cpu/x86/vtableStubs_x86_32.cpp @@ -24,10 +24,10 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" +#include "code/compiledIC.hpp" #include "code/vtableStubs.hpp" #include "interp_masm_x86.hpp" #include "memory/resourceArea.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/instanceKlass.hpp" #include "oops/klassVtable.hpp" #include "runtime/sharedRuntime.hpp" @@ -176,21 +176,21 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { #endif /* PRODUCT */ // Entry arguments: - // rax: CompiledICHolder + // rax: CompiledICData // rcx: Receiver // Most registers are in use; we'll use rax, rbx, rcx, rdx, rsi, rdi // (If we need to make rsi, rdi callee-save, do a push/pop here.) const Register recv_klass_reg = rsi; - const Register holder_klass_reg = rax; // declaring interface klass (DECC) + const Register holder_klass_reg = rax; // declaring interface klass (DEFC) const Register resolved_klass_reg = rdi; // resolved interface klass (REFC) const Register temp_reg = rdx; const Register method = rbx; - const Register icholder_reg = rax; + const Register icdata_reg = rax; const Register receiver = rcx; - __ movptr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset())); - __ movptr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset())); + __ movptr(resolved_klass_reg, Address(icdata_reg, CompiledICData::itable_refc_klass_offset())); + __ movptr(holder_klass_reg, Address(icdata_reg, CompiledICData::itable_defc_klass_offset())); Label L_no_such_interface; diff --git a/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp b/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp index f162a651183..158d6f9c692 100644 --- a/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp +++ b/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp @@ -24,10 +24,10 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" +#include "code/compiledIC.hpp" #include "code/vtableStubs.hpp" #include "interp_masm_x86.hpp" #include "memory/resourceArea.hpp" -#include "oops/compiledICHolder.hpp" #include "oops/instanceKlass.hpp" #include "oops/klassVtable.hpp" #include "runtime/sharedRuntime.hpp" @@ -168,21 +168,21 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { #endif // PRODUCT // Entry arguments: - // rax: CompiledICHolder + // rax: CompiledICData // j_rarg0: Receiver // Most registers are in use; we'll use rax, rbx, r10, r11 // (various calling sequences use r[cd]x, r[sd]i, r[89]; stay away from them) const Register recv_klass_reg = r10; - const Register holder_klass_reg = rax; // declaring interface klass (DECC) + const Register holder_klass_reg = rax; // declaring interface klass (DEFC) const Register resolved_klass_reg = r14; // resolved interface klass (REFC) const Register temp_reg = r11; const Register temp_reg2 = r13; const Register method = rbx; - const Register icholder_reg = rax; + const Register icdata_reg = rax; - __ movptr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset())); - __ movptr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset())); + __ movptr(resolved_klass_reg, Address(icdata_reg, CompiledICData::itable_refc_klass_offset())); + __ movptr(holder_klass_reg, Address(icdata_reg, CompiledICData::itable_defc_klass_offset())); Label L_no_such_interface; diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index caa82aab99c..6df02d280bc 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -1312,7 +1312,7 @@ int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) { // That's why we must use the macroassembler to generate a handler. C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_exception_handler()); - if (base == NULL) { + if (base == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return 0; // CodeBuffer::expand failed } @@ -1330,7 +1330,7 @@ int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { // That's why we must use the macroassembler to generate a handler. C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_deopt_handler()); - if (base == NULL) { + if (base == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return 0; // CodeBuffer::expand failed } @@ -1358,7 +1358,7 @@ int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { return offset; } -Assembler::Width widthForType(BasicType bt) { +static Assembler::Width widthForType(BasicType bt) { if (bt == T_BYTE) { return Assembler::B; } else if (bt == T_SHORT) { @@ -1425,6 +1425,8 @@ bool Matcher::match_rule_supported(int opcode) { return false; } break; + case Op_CompressV: + case Op_ExpandV: case Op_PopCountVL: if (UseAVX < 2) { return false; @@ -1659,12 +1661,6 @@ bool Matcher::match_rule_supported(int opcode) { return false; } break; - case Op_CompressV: - case Op_ExpandV: - if (!VM_Version::supports_avx512vl()) { - return false; - } - break; case Op_SqrtF: if (UseSSE < 1) { return false; @@ -1703,7 +1699,7 @@ static inline bool is_pop_count_instr_target(BasicType bt) { (is_non_subword_integral_type(bt) && VM_Version::supports_avx512_vpopcntdq()); } -bool Matcher::match_rule_supported_superword(int opcode, int vlen, BasicType bt) { +bool Matcher::match_rule_supported_auto_vectorization(int opcode, int vlen, BasicType bt) { return match_rule_supported_vector(opcode, vlen, bt); } @@ -1952,13 +1948,12 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { if (is_subword_type(bt) && !VM_Version::supports_avx512_vbmi2()) { return false; } - if (size_in_bits < 128 ) { + if (!is_LP64 && !VM_Version::supports_avx512vl() && size_in_bits < 512) { return false; } - if (size_in_bits < 512 && !VM_Version::supports_avx512vl()) { + if (size_in_bits < 128 ) { return false; } - break; case Op_VectorLongToMask: if (UseAVX < 1 || !is_LP64) { return false; @@ -2186,7 +2181,7 @@ MachOper* Matcher::pd_specialize_generic_vector_operand(MachOper* generic_opnd, } } ShouldNotReachHere(); - return NULL; + return nullptr; } bool Matcher::is_reg2reg_move(MachNode* m) { @@ -2285,7 +2280,7 @@ int Matcher::min_vector_size(const BasicType bt) { return MIN2(size,max_size); } -int Matcher::superword_max_vector_size(const BasicType bt) { +int Matcher::max_vector_size_auto_vectorization(const BasicType bt) { // Limit the max vector size for auto vectorization to 256 bits (32 bytes) // by default on Cascade Lake if (VM_Version::is_default_intel_cascade_lake()) { @@ -2355,7 +2350,7 @@ class FusedPatternMatcher { int _con_op; static int match_next(Node* n, int next_op, int next_op_idx) { - if (n->in(1) == NULL || n->in(2) == NULL) { + if (n->in(1) == nullptr || n->in(2) == nullptr) { return -1; } @@ -2422,7 +2417,7 @@ class FusedPatternMatcher { static bool is_bmi_pattern(Node* n, Node* m) { assert(UseBMI1Instructions, "sanity"); - if (n != NULL && m != NULL) { + if (n != nullptr && m != nullptr) { if (m->Opcode() == Op_LoadI) { FusedPatternMatcher bmii(n, m, Op_ConI); return bmii.match(Op_AndI, -1, Op_SubI, 1, 0) || @@ -7446,7 +7441,7 @@ instruct vround_reg_evex(vec dst, vec src, rRegP tmp, vec xtmp1, vec xtmp2, kReg // --------------------------------- VectorMaskCmp -------------------------------------- instruct vcmpFD(legVec dst, legVec src1, legVec src2, immI8 cond) %{ - predicate(n->bottom_type()->isa_vectmask() == NULL && + predicate(n->bottom_type()->isa_vectmask() == nullptr && Matcher::vector_length_in_bytes(n->in(1)->in(1)) >= 8 && // src1 Matcher::vector_length_in_bytes(n->in(1)->in(1)) <= 32 && // src1 is_floating_point_type(Matcher::vector_element_basic_type(n->in(1)->in(1)))); // src1 T_FLOAT, T_DOUBLE @@ -7466,7 +7461,7 @@ instruct vcmpFD(legVec dst, legVec src1, legVec src2, immI8 cond) %{ instruct evcmpFD64(vec dst, vec src1, vec src2, immI8 cond, kReg ktmp) %{ predicate(Matcher::vector_length_in_bytes(n->in(1)->in(1)) == 64 && // src1 - n->bottom_type()->isa_vectmask() == NULL && + n->bottom_type()->isa_vectmask() == nullptr && is_floating_point_type(Matcher::vector_element_basic_type(n->in(1)->in(1)))); // src1 T_FLOAT, T_DOUBLE match(Set dst (VectorMaskCmp (Binary src1 src2) cond)); effect(TEMP ktmp); @@ -7506,7 +7501,7 @@ instruct evcmpFD(kReg dst, vec src1, vec src2, immI8 cond) %{ %} instruct vcmp_direct(legVec dst, legVec src1, legVec src2, immI8 cond) %{ - predicate(n->bottom_type()->isa_vectmask() == NULL && + predicate(n->bottom_type()->isa_vectmask() == nullptr && !Matcher::is_unsigned_booltest_pred(n->in(2)->get_int()) && Matcher::vector_length_in_bytes(n->in(1)->in(1)) >= 4 && // src1 Matcher::vector_length_in_bytes(n->in(1)->in(1)) <= 32 && // src1 @@ -7526,7 +7521,7 @@ instruct vcmp_direct(legVec dst, legVec src1, legVec src2, immI8 cond) %{ %} instruct vcmp_negate(legVec dst, legVec src1, legVec src2, immI8 cond, legVec xtmp) %{ - predicate(n->bottom_type()->isa_vectmask() == NULL && + predicate(n->bottom_type()->isa_vectmask() == nullptr && !Matcher::is_unsigned_booltest_pred(n->in(2)->get_int()) && Matcher::vector_length_in_bytes(n->in(1)->in(1)) >= 4 && // src1 Matcher::vector_length_in_bytes(n->in(1)->in(1)) <= 32 && // src1 @@ -7547,7 +7542,7 @@ instruct vcmp_negate(legVec dst, legVec src1, legVec src2, immI8 cond, legVec xt %} instruct vcmpu(legVec dst, legVec src1, legVec src2, immI8 cond, legVec xtmp) %{ - predicate(n->bottom_type()->isa_vectmask() == NULL && + predicate(n->bottom_type()->isa_vectmask() == nullptr && Matcher::is_unsigned_booltest_pred(n->in(2)->get_int()) && Matcher::vector_length_in_bytes(n->in(1)->in(1)) >= 4 && // src1 Matcher::vector_length_in_bytes(n->in(1)->in(1)) <= 32 && // src1 @@ -7574,7 +7569,7 @@ instruct vcmpu(legVec dst, legVec src1, legVec src2, immI8 cond, legVec xtmp) %{ %} instruct vcmp64(vec dst, vec src1, vec src2, immI8 cond, kReg ktmp) %{ - predicate((n->bottom_type()->isa_vectmask() == NULL && + predicate((n->bottom_type()->isa_vectmask() == nullptr && Matcher::vector_length_in_bytes(n->in(1)->in(1)) == 64) && // src1 is_integral_type(Matcher::vector_element_basic_type(n->in(1)->in(1)))); // src1 match(Set dst (VectorMaskCmp (Binary src1 src2) cond)); @@ -7790,7 +7785,7 @@ instruct blendvp(vec dst, vec src, vec mask, rxmm0 tmp) %{ instruct vblendvpI(legVec dst, legVec src1, legVec src2, legVec mask) %{ predicate(UseAVX > 0 && !EnableX86ECoreOpts && - n->in(2)->bottom_type()->isa_vectmask() == NULL && + n->in(2)->bottom_type()->isa_vectmask() == nullptr && Matcher::vector_length_in_bytes(n) <= 32 && is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorBlend (Binary src1 src2) mask)); @@ -7804,7 +7799,7 @@ instruct vblendvpI(legVec dst, legVec src1, legVec src2, legVec mask) %{ instruct vblendvpFD(legVec dst, legVec src1, legVec src2, legVec mask) %{ predicate(UseAVX > 0 && !EnableX86ECoreOpts && - n->in(2)->bottom_type()->isa_vectmask() == NULL && + n->in(2)->bottom_type()->isa_vectmask() == nullptr && Matcher::vector_length_in_bytes(n) <= 32 && !is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorBlend (Binary src1 src2) mask)); @@ -7818,7 +7813,7 @@ instruct vblendvpFD(legVec dst, legVec src1, legVec src2, legVec mask) %{ instruct vblendvp(legVec dst, legVec src1, legVec src2, legVec mask, legVec vtmp) %{ predicate(UseAVX > 0 && EnableX86ECoreOpts && - n->in(2)->bottom_type()->isa_vectmask() == NULL && + n->in(2)->bottom_type()->isa_vectmask() == nullptr && Matcher::vector_length_in_bytes(n) <= 32); match(Set dst (VectorBlend (Binary src1 src2) mask)); format %{ "vector_blend $dst,$src1,$src2,$mask\t! using $vtmp as TEMP" %} @@ -7834,7 +7829,7 @@ instruct vblendvp(legVec dst, legVec src1, legVec src2, legVec mask, legVec vtmp instruct evblendvp64(vec dst, vec src1, vec src2, vec mask, kReg ktmp) %{ predicate(Matcher::vector_length_in_bytes(n) == 64 && - n->in(2)->bottom_type()->isa_vectmask() == NULL); + n->in(2)->bottom_type()->isa_vectmask() == nullptr); match(Set dst (VectorBlend (Binary src1 src2) mask)); format %{ "vector_blend $dst,$src1,$src2,$mask\t! using k2 as TEMP" %} effect(TEMP ktmp); @@ -8051,7 +8046,7 @@ instruct ktest_ge8(rFlagsRegU cr, kReg src1, kReg src2) %{ //------------------------------------- LoadMask -------------------------------------------- instruct loadMask(legVec dst, legVec src) %{ - predicate(n->bottom_type()->isa_vectmask() == NULL && !VM_Version::supports_avx512vlbw()); + predicate(n->bottom_type()->isa_vectmask() == nullptr && !VM_Version::supports_avx512vlbw()); match(Set dst (VectorLoadMask src)); effect(TEMP dst); format %{ "vector_loadmask_byte $dst, $src\n\t" %} @@ -8091,7 +8086,7 @@ instruct loadMask_evex(kReg dst, vec src, vec xtmp) %{ //------------------------------------- StoreMask -------------------------------------------- instruct vstoreMask1B(vec dst, vec src, immI_1 size) %{ - predicate(Matcher::vector_length(n) < 64 && n->in(1)->bottom_type()->isa_vectmask() == NULL); + predicate(Matcher::vector_length(n) < 64 && n->in(1)->bottom_type()->isa_vectmask() == nullptr); match(Set dst (VectorStoreMask src size)); format %{ "vector_store_mask $dst, $src \t! elem size is $size byte[s]" %} ins_encode %{ @@ -8109,7 +8104,7 @@ instruct vstoreMask1B(vec dst, vec src, immI_1 size) %{ %} instruct vstoreMask2B(vec dst, vec src, vec xtmp, immI_2 size) %{ - predicate(Matcher::vector_length(n) <= 16 && n->in(1)->bottom_type()->isa_vectmask() == NULL); + predicate(Matcher::vector_length(n) <= 16 && n->in(1)->bottom_type()->isa_vectmask() == nullptr); match(Set dst (VectorStoreMask src size)); effect(TEMP_DEF dst, TEMP xtmp); format %{ "vector_store_mask $dst, $src \t! elem size is $size byte[s]" %} @@ -8132,7 +8127,7 @@ instruct vstoreMask2B(vec dst, vec src, vec xtmp, immI_2 size) %{ %} instruct vstoreMask4B(vec dst, vec src, vec xtmp, immI_4 size) %{ - predicate(UseAVX <= 2 && Matcher::vector_length(n) <= 8 && n->in(1)->bottom_type()->isa_vectmask() == NULL); + predicate(UseAVX <= 2 && Matcher::vector_length(n) <= 8 && n->in(1)->bottom_type()->isa_vectmask() == nullptr); match(Set dst (VectorStoreMask src size)); format %{ "vector_store_mask $dst, $src \t! elem size is $size byte[s]" %} effect(TEMP_DEF dst, TEMP xtmp); @@ -8192,7 +8187,7 @@ instruct storeMask8B_avx(vec dst, vec src, immI_8 size, vec vtmp) %{ %} instruct vstoreMask4B_evex_novectmask(vec dst, vec src, immI_4 size) %{ - predicate(UseAVX > 2 && n->in(1)->bottom_type()->isa_vectmask() == NULL); + predicate(UseAVX > 2 && n->in(1)->bottom_type()->isa_vectmask() == nullptr); match(Set dst (VectorStoreMask src size)); format %{ "vector_store_mask $dst, $src \t! elem size is $size byte[s]" %} ins_encode %{ @@ -8208,7 +8203,7 @@ instruct vstoreMask4B_evex_novectmask(vec dst, vec src, immI_4 size) %{ %} instruct vstoreMask8B_evex_novectmask(vec dst, vec src, immI_8 size) %{ - predicate(UseAVX > 2 && n->in(1)->bottom_type()->isa_vectmask() == NULL); + predicate(UseAVX > 2 && n->in(1)->bottom_type()->isa_vectmask() == nullptr); match(Set dst (VectorStoreMask src size)); format %{ "vector_store_mask $dst, $src \t! elem size is $size byte[s]" %} ins_encode %{ @@ -9045,7 +9040,7 @@ instruct vmask_tolong_evex(rRegL dst, kReg mask, rFlagsReg cr) %{ %} instruct vmask_tolong_bool(rRegL dst, vec mask, vec xtmp, rFlagsReg cr) %{ - predicate(n->in(1)->bottom_type()->isa_vectmask() == NULL); + predicate(n->in(1)->bottom_type()->isa_vectmask() == nullptr); match(Set dst (VectorMaskToLong mask)); format %{ "vector_tolong_bool $dst, $mask \t! using $xtmp as TEMP" %} effect(TEMP_DEF dst, TEMP xtmp, KILL cr); @@ -9061,7 +9056,7 @@ instruct vmask_tolong_bool(rRegL dst, vec mask, vec xtmp, rFlagsReg cr) %{ %} instruct vmask_tolong_avx(rRegL dst, vec mask, immI size, vec xtmp, rFlagsReg cr) %{ - predicate(n->in(1)->in(1)->bottom_type()->isa_vectmask() == NULL); + predicate(n->in(1)->in(1)->bottom_type()->isa_vectmask() == nullptr); match(Set dst (VectorMaskToLong (VectorStoreMask mask size))); format %{ "vector_tolong_avx $dst, $mask \t! using $xtmp as TEMP" %} effect(TEMP_DEF dst, TEMP xtmp, KILL cr); @@ -9094,7 +9089,7 @@ instruct vmask_truecount_evex(rRegI dst, kReg mask, rRegL tmp, rFlagsReg cr) %{ %} instruct vmask_truecount_bool(rRegI dst, vec mask, rRegL tmp, vec xtmp, rFlagsReg cr) %{ - predicate(n->in(1)->bottom_type()->isa_vectmask() == NULL); + predicate(n->in(1)->bottom_type()->isa_vectmask() == nullptr); match(Set dst (VectorMaskTrueCount mask)); effect(TEMP_DEF dst, TEMP tmp, TEMP xtmp, KILL cr); format %{ "vector_truecount_bool $dst, $mask \t! using $tmp, $xtmp as TEMP" %} @@ -9110,7 +9105,7 @@ instruct vmask_truecount_bool(rRegI dst, vec mask, rRegL tmp, vec xtmp, rFlagsRe %} instruct vmask_truecount_avx(rRegI dst, vec mask, immI size, rRegL tmp, vec xtmp, rFlagsReg cr) %{ - predicate(n->in(1)->in(1)->bottom_type()->isa_vectmask() == NULL); + predicate(n->in(1)->in(1)->bottom_type()->isa_vectmask() == nullptr); match(Set dst (VectorMaskTrueCount (VectorStoreMask mask size))); effect(TEMP_DEF dst, TEMP tmp, TEMP xtmp, KILL cr); format %{ "vector_truecount_avx $dst, $mask \t! using $tmp, $xtmp as TEMP" %} @@ -9144,7 +9139,7 @@ instruct vmask_first_or_last_true_evex(rRegI dst, kReg mask, rRegL tmp, rFlagsRe %} instruct vmask_first_or_last_true_bool(rRegI dst, vec mask, rRegL tmp, vec xtmp, rFlagsReg cr) %{ - predicate(n->in(1)->bottom_type()->isa_vectmask() == NULL); + predicate(n->in(1)->bottom_type()->isa_vectmask() == nullptr); match(Set dst (VectorMaskFirstTrue mask)); match(Set dst (VectorMaskLastTrue mask)); effect(TEMP_DEF dst, TEMP tmp, TEMP xtmp, KILL cr); @@ -9161,7 +9156,7 @@ instruct vmask_first_or_last_true_bool(rRegI dst, vec mask, rRegL tmp, vec xtmp, %} instruct vmask_first_or_last_true_avx(rRegI dst, vec mask, immI size, rRegL tmp, vec xtmp, rFlagsReg cr) %{ - predicate(n->in(1)->in(1)->bottom_type()->isa_vectmask() == NULL); + predicate(n->in(1)->in(1)->bottom_type()->isa_vectmask() == nullptr); match(Set dst (VectorMaskFirstTrue (VectorStoreMask mask size))); match(Set dst (VectorMaskLastTrue (VectorStoreMask mask size))); effect(TEMP_DEF dst, TEMP tmp, TEMP xtmp, KILL cr); @@ -9178,8 +9173,26 @@ instruct vmask_first_or_last_true_avx(rRegI dst, vec mask, immI size, rRegL tmp, %} // --------------------------------- Compress/Expand Operations --------------------------- +#ifdef _LP64 +instruct vcompress_reg_avx(vec dst, vec src, vec mask, rRegI rtmp, rRegL rscratch, vec perm, vec xtmp, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx512vl() && Matcher::vector_length_in_bytes(n) <= 32); + match(Set dst (CompressV src mask)); + match(Set dst (ExpandV src mask)); + effect(TEMP_DEF dst, TEMP perm, TEMP xtmp, TEMP rtmp, TEMP rscratch, KILL cr); + format %{ "vector_compress $dst, $src, $mask \t!using $xtmp, $rtmp, $rscratch and $perm as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen_enc = vector_length_encoding(this); + BasicType bt = Matcher::vector_element_basic_type(this); + __ vector_compress_expand_avx2(opcode, $dst$$XMMRegister, $src$$XMMRegister, $mask$$XMMRegister, $rtmp$$Register, + $rscratch$$Register, $perm$$XMMRegister, $xtmp$$XMMRegister, bt, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} +#endif instruct vcompress_expand_reg_evex(vec dst, vec src, kReg mask) %{ + predicate(VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n) == 64); match(Set dst (CompressV src mask)); match(Set dst (ExpandV src mask)); format %{ "vector_compress_expand $dst, $src, $mask" %} @@ -9998,7 +10011,7 @@ instruct mask_not_imm(kReg dst, kReg src, immI_M1 cnt) %{ %} instruct long_to_maskLE8_avx(vec dst, rRegL src, rRegL rtmp1, rRegL rtmp2, vec xtmp) %{ - predicate(n->bottom_type()->isa_vectmask() == NULL && Matcher::vector_length(n) <= 8); + predicate(n->bottom_type()->isa_vectmask() == nullptr && Matcher::vector_length(n) <= 8); match(Set dst (VectorLongToMask src)); effect(TEMP dst, TEMP rtmp1, TEMP rtmp2, TEMP xtmp); format %{ "long_to_mask_avx $dst, $src\t! using $rtmp1, $rtmp2, $xtmp as TEMP" %} @@ -10013,7 +10026,7 @@ instruct long_to_maskLE8_avx(vec dst, rRegL src, rRegL rtmp1, rRegL rtmp2, vec x instruct long_to_maskGT8_avx(vec dst, rRegL src, rRegL rtmp1, rRegL rtmp2, vec xtmp1, rFlagsReg cr) %{ - predicate(n->bottom_type()->isa_vectmask() == NULL && Matcher::vector_length(n) > 8); + predicate(n->bottom_type()->isa_vectmask() == nullptr && Matcher::vector_length(n) > 8); match(Set dst (VectorLongToMask src)); effect(TEMP dst, TEMP rtmp1, TEMP rtmp2, TEMP xtmp1, KILL cr); format %{ "long_to_mask_avx $dst, $src\t! using $rtmp1, $rtmp2, $xtmp1, as TEMP" %} diff --git a/src/hotspot/cpu/x86/x86_32.ad b/src/hotspot/cpu/x86/x86_32.ad index f2e9c042b24..2fe655a5767 100644 --- a/src/hotspot/cpu/x86/x86_32.ad +++ b/src/hotspot/cpu/x86/x86_32.ad @@ -504,7 +504,7 @@ void emit_cmpfp_fixup(MacroAssembler& _masm) { __ bind(exit); } -void emit_cmpfp3(MacroAssembler& _masm, Register dst) { +static void emit_cmpfp3(MacroAssembler& _masm, Register dst) { Label done; __ movl(dst, -1); __ jcc(Assembler::parity, done); @@ -614,7 +614,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { int framesize = C->output()->frame_size_in_bytes(); int bangsize = C->output()->bang_size_in_bytes(); - __ verified_entry(framesize, C->output()->need_stack_bang(bangsize)?bangsize:0, C->in_24_bit_fp_mode(), C->stub_function() != NULL); + __ verified_entry(framesize, C->output()->need_stack_bang(bangsize)?bangsize:0, C->in_24_bit_fp_mode(), C->stub_function() != nullptr); C->output()->set_frame_complete(cbuf.insts_size()); @@ -1052,7 +1052,7 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, PhaseRegAlloc *ra_, bo if( src_first == dst_first && src_second == dst_second ) return size; // Self copy, no move - if (bottom_type()->isa_vect() != NULL && bottom_type()->isa_vectmask() == NULL) { + if (bottom_type()->isa_vect() != nullptr && bottom_type()->isa_vectmask() == nullptr) { uint ireg = ideal_reg(); assert((src_first_rc != rc_int && dst_first_rc != rc_int), "sanity"); assert((src_first_rc != rc_float && dst_first_rc != rc_float), "sanity"); @@ -1320,12 +1320,12 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, PhaseRegAlloc *ra_, bo #ifndef PRODUCT void MachSpillCopyNode::format(PhaseRegAlloc *ra_, outputStream* st) const { - implementation( NULL, ra_, false, st ); + implementation( nullptr, ra_, false, st ); } #endif void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - implementation( &cbuf, ra_, false, NULL ); + implementation( &cbuf, ra_, false, nullptr ); } uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { @@ -1383,24 +1383,12 @@ void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream* st ) const { void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { MacroAssembler masm(&cbuf); -#ifdef ASSERT - uint insts_size = cbuf.insts_size(); -#endif - masm.cmpptr(rax, Address(rcx, oopDesc::klass_offset_in_bytes())); - masm.jump_cc(Assembler::notEqual, - RuntimeAddress(SharedRuntime::get_ic_miss_stub())); - /* WARNING these NOPs are critical so that verified entry point is properly - aligned for patching by NativeJump::patch_verified_entry() */ - int nops_cnt = 2; - if( !OptoBreakpoint ) // Leave space for int3 - nops_cnt += 1; - masm.nop(nops_cnt); - - assert(cbuf.insts_size() - insts_size == size(ra_), "checking code size of inline cache node"); + masm.ic_check(CodeEntryAlignment); } uint MachUEPNode::size(PhaseRegAlloc *ra_) const { - return OptoBreakpoint ? 11 : 12; + return MachNode::size(ra_); // too many variables; just compute it + // the hard way } @@ -1725,7 +1713,7 @@ encode %{ MacroAssembler _masm(&cbuf); __ check_klass_subtype_slow_path(Resi, Reax, Recx, Redi, - NULL, &miss, + nullptr, &miss, /*set_cond_codes:*/ true); if ($primary) { __ xorptr(Redi, Redi); @@ -1842,8 +1830,8 @@ encode %{ cbuf.shared_stub_to_interp_for(_method, cbuf.insts()->mark_off()); } else { // Emit stubs for static call. - address stub = CompiledStaticCall::emit_to_interp_stub(cbuf, mark); - if (stub == NULL) { + address stub = CompiledDirectCall::emit_to_interp_stub(cbuf, mark); + if (stub == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -3396,7 +3384,7 @@ operand immP() %{ interface(CONST_INTER); %} -// NULL Pointer Immediate +// Null Pointer Immediate operand immP0() %{ predicate( n->get_ptr() == 0 ); match(ConP); @@ -13776,7 +13764,7 @@ instruct cmpFastLockRTM(eFlagsReg cr, eRegP object, eBXRegP box, eAXRegI tmp, eD %} instruct cmpFastLock(eFlagsReg cr, eRegP object, eBXRegP box, eAXRegI tmp, eRegP scr, eRegP thread) %{ - predicate(!Compile::current()->use_rtm()); + predicate(LockingMode != LM_LIGHTWEIGHT && !Compile::current()->use_rtm()); match(Set cr (FastLock object box)); effect(TEMP tmp, TEMP scr, USE_KILL box, TEMP thread); ins_cost(300); @@ -13790,6 +13778,7 @@ instruct cmpFastLock(eFlagsReg cr, eRegP object, eBXRegP box, eAXRegI tmp, eRegP %} instruct cmpFastUnlock(eFlagsReg cr, eRegP object, eAXRegP box, eRegP tmp ) %{ + predicate(LockingMode != LM_LIGHTWEIGHT); match(Set cr (FastUnlock object box)); effect(TEMP tmp, USE_KILL box); ins_cost(300); @@ -13800,6 +13789,32 @@ instruct cmpFastUnlock(eFlagsReg cr, eRegP object, eAXRegP box, eRegP tmp ) %{ ins_pipe(pipe_slow); %} +instruct cmpFastLockLightweight(eFlagsReg cr, eRegP object, eBXRegP box, eAXRegI eax_reg, eRegP tmp, eRegP thread) %{ + predicate(LockingMode == LM_LIGHTWEIGHT); + match(Set cr (FastLock object box)); + effect(TEMP eax_reg, TEMP tmp, USE_KILL box, TEMP thread); + ins_cost(300); + format %{ "FASTLOCK $object,$box\t! kills $box,$eax_reg,$tmp" %} + ins_encode %{ + __ get_thread($thread$$Register); + __ fast_lock_lightweight($object$$Register, $box$$Register, $eax_reg$$Register, $tmp$$Register, $thread$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct cmpFastUnlockLightweight(eFlagsReg cr, eRegP object, eAXRegP eax_reg, eRegP tmp, eRegP thread) %{ + predicate(LockingMode == LM_LIGHTWEIGHT); + match(Set cr (FastUnlock object eax_reg)); + effect(TEMP tmp, USE_KILL eax_reg, TEMP thread); + ins_cost(300); + format %{ "FASTUNLOCK $object,$eax_reg\t! kills $eax_reg,$tmp" %} + ins_encode %{ + __ get_thread($thread$$Register); + __ fast_unlock_lightweight($object$$Register, $eax_reg$$Register, $tmp$$Register, $thread$$Register); + %} + ins_pipe(pipe_slow); +%} + instruct mask_all_evexL_LT32(kReg dst, eRegL src) %{ predicate(Matcher::vector_length(n) <= 32); match(Set dst (MaskAll src)); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 80f281a1bf9..a8136688cde 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -519,7 +519,7 @@ int CallDynamicJavaDirectNode::compute_padding(int current_offset) const } // This could be in MacroAssembler but it's fairly C2 specific -void emit_cmpfp_fixup(MacroAssembler& _masm) { +static void emit_cmpfp_fixup(MacroAssembler& _masm) { Label exit; __ jccb(Assembler::noParity, exit); __ pushf(); @@ -539,7 +539,7 @@ void emit_cmpfp_fixup(MacroAssembler& _masm) { __ bind(exit); } -void emit_cmpfp3(MacroAssembler& _masm, Register dst) { +static void emit_cmpfp3(MacroAssembler& _masm, Register dst) { Label done; __ movl(dst, -1); __ jcc(Assembler::parity, done); @@ -558,10 +558,10 @@ void emit_cmpfp3(MacroAssembler& _masm, Register dst) { // je # // |-jz -> a | b # a & b // | -> a # -void emit_fp_min_max(MacroAssembler& _masm, XMMRegister dst, - XMMRegister a, XMMRegister b, - XMMRegister xmmt, Register rt, - bool min, bool single) { +static void emit_fp_min_max(MacroAssembler& _masm, XMMRegister dst, + XMMRegister a, XMMRegister b, + XMMRegister xmmt, Register rt, + bool min, bool single) { Label nan, zero, below, above, done; @@ -706,7 +706,7 @@ void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const { st->print("# stack alignment check"); #endif } - if (C->stub_function() != NULL && BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) { + if (C->stub_function() != nullptr && BarrierSet::barrier_set()->barrier_set_nmethod() != nullptr) { st->print("\n\t"); st->print("cmpl [r15_thread + #disarmed_guard_value_offset], #disarmed_guard_value\t"); st->print("\n\t"); @@ -741,7 +741,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { __ bind(L_skip_barrier); } - __ verified_entry(framesize, C->output()->need_stack_bang(bangsize)?bangsize:0, false, C->stub_function() != NULL); + __ verified_entry(framesize, C->output()->need_stack_bang(bangsize)?bangsize:0, false, C->stub_function() != nullptr); C->output()->set_frame_complete(cbuf.insts_size()); @@ -970,7 +970,7 @@ uint MachSpillCopyNode::implementation(CodeBuffer* cbuf, PhaseRegAlloc* ra_, bool do_size, outputStream* st) const { - assert(cbuf != NULL || st != NULL, "sanity"); + assert(cbuf != nullptr || st != nullptr, "sanity"); // Get registers to move OptoReg::Name src_second = ra_->get_reg_second(in(1)); OptoReg::Name src_first = ra_->get_reg_first(in(1)); @@ -989,7 +989,7 @@ uint MachSpillCopyNode::implementation(CodeBuffer* cbuf, // Self copy, no move return 0; } - if (bottom_type()->isa_vect() != NULL && bottom_type()->isa_vectmask() == NULL) { + if (bottom_type()->isa_vect() != nullptr && bottom_type()->isa_vectmask() == nullptr) { uint ireg = ideal_reg(); assert((src_first_rc != rc_int && dst_first_rc != rc_int), "sanity"); assert((ireg == Op_VecS || ireg == Op_VecD || ireg == Op_VecX || ireg == Op_VecY || ireg == Op_VecZ ), "sanity"); @@ -1428,12 +1428,12 @@ uint MachSpillCopyNode::implementation(CodeBuffer* cbuf, #ifndef PRODUCT void MachSpillCopyNode::format(PhaseRegAlloc *ra_, outputStream* st) const { - implementation(NULL, ra_, false, st); + implementation(nullptr, ra_, false, st); } #endif void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - implementation(&cbuf, ra_, false, NULL); + implementation(&cbuf, ra_, false, nullptr); } uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { @@ -1472,40 +1472,19 @@ void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const { if (UseCompressedClassPointers) { st->print_cr("movl rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - st->print_cr("\tdecode_klass_not_null rscratch1, rscratch1"); - st->print_cr("\tcmpq rax, rscratch1\t # Inline cache check"); + st->print_cr("\tcmpl rscratch1, [rax + CompiledICData::speculated_klass_offset()]\t # Inline cache check"); } else { - st->print_cr("\tcmpq rax, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t" - "# Inline cache check"); + st->print_cr("movq rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + st->print_cr("\tcmpq rscratch1, [rax + CompiledICData::speculated_klass_offset()]\t # Inline cache check"); } st->print_cr("\tjne SharedRuntime::_ic_miss_stub"); - st->print_cr("\tnop\t# nops to align entry point"); } #endif void MachUEPNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const { MacroAssembler masm(&cbuf); - uint insts_size = cbuf.insts_size(); - if (UseCompressedClassPointers) { - masm.load_klass(rscratch1, j_rarg0, rscratch2); - masm.cmpptr(rax, rscratch1); - } else { - masm.cmpptr(rax, Address(j_rarg0, oopDesc::klass_offset_in_bytes())); - } - - masm.jump_cc(Assembler::notEqual, RuntimeAddress(SharedRuntime::get_ic_miss_stub())); - - /* WARNING these NOPs are critical so that verified entry point is properly - 4 bytes aligned for patching by NativeJump::patch_verified_entry() */ - int nops_cnt = 4 - ((cbuf.insts_size() - insts_size) & 0x3); - if (OptoBreakpoint) { - // Leave space for int3 - nops_cnt -= 1; - } - nops_cnt &= 0x3; // Do not add nops if code is aligned. - if (nops_cnt > 0) - masm.nop(nops_cnt); + masm.ic_check(InteriorEntryAlignment); } uint MachUEPNode::size(PhaseRegAlloc* ra_) const @@ -1784,7 +1763,7 @@ encode %{ MacroAssembler _masm(&cbuf); __ check_klass_subtype_slow_path(Rrsi, Rrax, Rrcx, Rrdi, - NULL, &miss, + nullptr, &miss, /*set_cond_codes:*/ true); if ($primary) { __ xorptr(Rrdi, Rrdi); @@ -1840,8 +1819,8 @@ encode %{ cbuf.shared_stub_to_interp_for(_method, call_offset); } else { // Emit stubs for static call. - address stub = CompiledStaticCall::emit_to_interp_stub(cbuf, mark); - if (stub == NULL) { + address stub = CompiledDirectCall::emit_to_interp_stub(cbuf, mark); + if (stub == nullptr) { ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -2179,7 +2158,7 @@ operand immP() interface(CONST_INTER); %} -// NULL Pointer Immediate +// Null Pointer Immediate operand immP0() %{ predicate(n->get_ptr() == 0); @@ -2207,7 +2186,7 @@ operand immNKlass() %{ interface(CONST_INTER); %} -// NULL Pointer Immediate +// Null Pointer Immediate operand immN0() %{ predicate(n->get_narrowcon() == 0); match(ConN); @@ -3121,7 +3100,7 @@ operand indPosIndexScaleOffset(any_RegP reg, immL32 off, rRegI idx, immI2 scale) // Indirect Narrow Oop Plus Offset Operand // Note: x86 architecture doesn't support "scale * index + offset" without a base -// we can't free r12 even with CompressedOops::base() == NULL. +// we can't free r12 even with CompressedOops::base() == nullptr. operand indCompressedOopOffset(rRegN reg, immL32 off) %{ predicate(UseCompressedOops && (CompressedOops::shift() == Address::times_8)); constraint(ALLOC_IN_RC(ptr_reg)); @@ -4902,7 +4881,7 @@ instruct loadConF(regF dst, immF con) %{ instruct loadConN0(rRegN dst, immN0 src, rFlagsReg cr) %{ match(Set dst src); effect(KILL cr); - format %{ "xorq $dst, $src\t# compressed NULL ptr" %} + format %{ "xorq $dst, $src\t# compressed null pointer" %} ins_encode %{ __ xorq($dst$$Register, $dst$$Register); %} @@ -4916,7 +4895,7 @@ instruct loadConN(rRegN dst, immN src) %{ format %{ "movl $dst, $src\t# compressed ptr" %} ins_encode %{ address con = (address)$src$$constant; - if (con == NULL) { + if (con == nullptr) { ShouldNotReachHere(); } else { __ set_narrow_oop($dst$$Register, (jobject)$src$$constant); @@ -4932,7 +4911,7 @@ instruct loadConNKlass(rRegN dst, immNKlass src) %{ format %{ "movl $dst, $src\t# compressed klass ptr" %} ins_encode %{ address con = (address)$src$$constant; - if (con == NULL) { + if (con == nullptr) { ShouldNotReachHere(); } else { __ set_narrow_klass($dst$$Register, (Klass*)$src$$constant); @@ -5158,7 +5137,7 @@ instruct storeP(memory mem, any_RegP src) instruct storeImmP0(memory mem, immP0 zero) %{ - predicate(UseCompressedOops && (CompressedOops::base() == NULL) && n->as_Store()->barrier_data() == 0); + predicate(UseCompressedOops && (CompressedOops::base() == nullptr) && n->as_Store()->barrier_data() == 0); match(Set mem (StoreP mem zero)); ins_cost(125); // XXX @@ -5169,7 +5148,7 @@ instruct storeImmP0(memory mem, immP0 zero) ins_pipe(ialu_mem_reg); %} -// Store NULL Pointer, mark word, or other simple pointer constant. +// Store Null Pointer, mark word, or other simple pointer constant. instruct storeImmP(memory mem, immP31 src) %{ predicate(n->as_Store()->barrier_data() == 0); @@ -5210,7 +5189,7 @@ instruct storeNKlass(memory mem, rRegN src) instruct storeImmN0(memory mem, immN0 zero) %{ - predicate(CompressedOops::base() == NULL); + predicate(CompressedOops::base() == nullptr); match(Set mem (StoreN mem zero)); ins_cost(125); // XXX @@ -5229,7 +5208,7 @@ instruct storeImmN(memory mem, immN src) format %{ "movl $mem, $src\t# compressed ptr" %} ins_encode %{ address con = (address)$src$$constant; - if (con == NULL) { + if (con == nullptr) { __ movl($mem$$Address, 0); } else { __ set_narrow_oop($mem$$Address, (jobject)$src$$constant); @@ -5253,7 +5232,7 @@ instruct storeImmNKlass(memory mem, immNKlass src) // Store Integer Immediate instruct storeImmI0(memory mem, immI_0 zero) %{ - predicate(UseCompressedOops && (CompressedOops::base() == NULL)); + predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); match(Set mem (StoreI mem zero)); ins_cost(125); // XXX @@ -5279,7 +5258,7 @@ instruct storeImmI(memory mem, immI src) // Store Long Immediate instruct storeImmL0(memory mem, immL0 zero) %{ - predicate(UseCompressedOops && (CompressedOops::base() == NULL)); + predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); match(Set mem (StoreL mem zero)); ins_cost(125); // XXX @@ -5305,7 +5284,7 @@ instruct storeImmL(memory mem, immL32 src) // Store Short/Char Immediate instruct storeImmC0(memory mem, immI_0 zero) %{ - predicate(UseCompressedOops && (CompressedOops::base() == NULL)); + predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); match(Set mem (StoreC mem zero)); ins_cost(125); // XXX @@ -5332,7 +5311,7 @@ instruct storeImmI16(memory mem, immI16 src) // Store Byte Immediate instruct storeImmB0(memory mem, immI_0 zero) %{ - predicate(UseCompressedOops && (CompressedOops::base() == NULL)); + predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); match(Set mem (StoreB mem zero)); ins_cost(125); // XXX @@ -5358,7 +5337,7 @@ instruct storeImmB(memory mem, immI8 src) // Store CMS card-mark Immediate instruct storeImmCM0_reg(memory mem, immI_0 zero) %{ - predicate(UseCompressedOops && (CompressedOops::base() == NULL)); + predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); match(Set mem (StoreCM mem zero)); ins_cost(125); // XXX @@ -5397,7 +5376,7 @@ instruct storeF(memory mem, regF src) // Store immediate Float value (it is faster than store from XMM register) instruct storeF0(memory mem, immF0 zero) %{ - predicate(UseCompressedOops && (CompressedOops::base() == NULL)); + predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); match(Set mem (StoreF mem zero)); ins_cost(25); // XXX @@ -5436,7 +5415,7 @@ instruct storeD(memory mem, regD src) // Store immediate double 0.0 (it is faster than store from XMM register) instruct storeD0_imm(memory mem, immD0 src) %{ - predicate(!UseCompressedOops || (CompressedOops::base() != NULL)); + predicate(!UseCompressedOops || (CompressedOops::base() != nullptr)); match(Set mem (StoreD mem src)); ins_cost(50); @@ -5449,7 +5428,7 @@ instruct storeD0_imm(memory mem, immD0 src) instruct storeD0(memory mem, immD0 zero) %{ - predicate(UseCompressedOops && (CompressedOops::base() == NULL)); + predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); match(Set mem (StoreD mem zero)); ins_cost(25); // XXX @@ -11680,7 +11659,7 @@ instruct testP_reg(rFlagsReg cr, rRegP src, immP0 zero) // any compare to a zero should be eq/neq. instruct testP_mem(rFlagsReg cr, memory op, immP0 zero) %{ - predicate((!UseCompressedOops || (CompressedOops::base() != NULL)) && + predicate((!UseCompressedOops || (CompressedOops::base() != nullptr)) && n->in(1)->as_Load()->barrier_data() == 0); match(Set cr (CmpP (LoadP op) zero)); @@ -11694,7 +11673,7 @@ instruct testP_mem(rFlagsReg cr, memory op, immP0 zero) instruct testP_mem_reg0(rFlagsReg cr, memory mem, immP0 zero) %{ - predicate(UseCompressedOops && (CompressedOops::base() == NULL) && + predicate(UseCompressedOops && (CompressedOops::base() == nullptr) && n->in(1)->as_Load()->barrier_data() == 0); match(Set cr (CmpP (LoadP mem) zero)); @@ -11777,7 +11756,7 @@ instruct testN_reg(rFlagsReg cr, rRegN src, immN0 zero) %{ instruct testN_mem(rFlagsReg cr, memory mem, immN0 zero) %{ - predicate(CompressedOops::base() != NULL); + predicate(CompressedOops::base() != nullptr); match(Set cr (CmpN (LoadN mem) zero)); ins_cost(500); // XXX @@ -11790,7 +11769,7 @@ instruct testN_mem(rFlagsReg cr, memory mem, immN0 zero) instruct testN_mem_reg0(rFlagsReg cr, memory mem, immN0 zero) %{ - predicate(CompressedOops::base() == NULL); + predicate(CompressedOops::base() == nullptr); match(Set cr (CmpN (LoadN mem) zero)); format %{ "cmpl R12, $mem\t# compressed ptr (R12_heapbase==0)" %} @@ -12404,7 +12383,7 @@ instruct cmpFastLockRTM(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI tmp, %} instruct cmpFastLock(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI tmp, rRegP scr) %{ - predicate(!Compile::current()->use_rtm()); + predicate(LockingMode != LM_LIGHTWEIGHT && !Compile::current()->use_rtm()); match(Set cr (FastLock object box)); effect(TEMP tmp, TEMP scr, USE_KILL box); ins_cost(300); @@ -12417,6 +12396,7 @@ instruct cmpFastLock(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI tmp, rRe %} instruct cmpFastUnlock(rFlagsReg cr, rRegP object, rax_RegP box, rRegP tmp) %{ + predicate(LockingMode != LM_LIGHTWEIGHT); match(Set cr (FastUnlock object box)); effect(TEMP tmp, USE_KILL box); ins_cost(300); @@ -12427,6 +12407,30 @@ instruct cmpFastUnlock(rFlagsReg cr, rRegP object, rax_RegP box, rRegP tmp) %{ ins_pipe(pipe_slow); %} +instruct cmpFastLockLightweight(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI rax_reg, rRegP tmp) %{ + predicate(LockingMode == LM_LIGHTWEIGHT); + match(Set cr (FastLock object box)); + effect(TEMP rax_reg, TEMP tmp, USE_KILL box); + ins_cost(300); + format %{ "fastlock $object,$box\t! kills $box,$rax_reg,$tmp" %} + ins_encode %{ + __ fast_lock_lightweight($object$$Register, $box$$Register, $rax_reg$$Register, $tmp$$Register, r15_thread); + %} + ins_pipe(pipe_slow); +%} + +instruct cmpFastUnlockLightweight(rFlagsReg cr, rRegP object, rax_RegP rax_reg, rRegP tmp) %{ + predicate(LockingMode == LM_LIGHTWEIGHT); + match(Set cr (FastUnlock object rax_reg)); + effect(TEMP tmp, USE_KILL rax_reg); + ins_cost(300); + format %{ "fastunlock $object,$rax_reg\t! kills $rax_reg,$tmp" %} + ins_encode %{ + __ fast_unlock_lightweight($object$$Register, $rax_reg$$Register, $tmp$$Register, r15_thread); + %} + ins_pipe(pipe_slow); +%} + // ============================================================================ // Safepoint Instructions diff --git a/src/hotspot/cpu/zero/compiledIC_zero.cpp b/src/hotspot/cpu/zero/compiledIC_zero.cpp index b0564643af0..24153aeacc5 100644 --- a/src/hotspot/cpu/zero/compiledIC_zero.cpp +++ b/src/hotspot/cpu/zero/compiledIC_zero.cpp @@ -25,7 +25,6 @@ #include "precompiled.hpp" #include "code/codeCache.hpp" #include "code/compiledIC.hpp" -#include "code/icBuffer.hpp" #include "code/nmethod.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" @@ -43,27 +42,27 @@ // ---------------------------------------------------------------------------- -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { +address CompiledDirectCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { ShouldNotReachHere(); // Only needed for COMPILER2. return nullptr; } -int CompiledStaticCall::to_interp_stub_size() { +int CompiledDirectCall::to_interp_stub_size() { ShouldNotReachHere(); // Only needed for COMPILER2. return 0; } // Relocation entries for call stub, compiled java to interpreter. -int CompiledStaticCall::reloc_to_interp_stub() { +int CompiledDirectCall::reloc_to_interp_stub() { ShouldNotReachHere(); // Only needed for COMPILER2. return 0; } -void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) { +void CompiledDirectCall::set_to_interpreted(const methodHandle& callee, address entry) { ShouldNotReachHere(); // Only needed for COMPILER2. } -void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) { +void CompiledDirectCall::set_stub_to_clean(static_stub_Relocation* static_stub) { ShouldNotReachHere(); // Only needed for COMPILER2. } @@ -71,7 +70,7 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_ // Non-product mode code. #ifndef PRODUCT -void CompiledDirectStaticCall::verify() { +void CompiledDirectCall::verify() { ShouldNotReachHere(); // Only needed for COMPILER2. } diff --git a/src/hotspot/cpu/zero/icBuffer_zero.cpp b/src/hotspot/cpu/zero/icBuffer_zero.cpp deleted file mode 100644 index adde916a4c4..00000000000 --- a/src/hotspot/cpu/zero/icBuffer_zero.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007 Red Hat, Inc. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/assembler.inline.hpp" -#include "code/icBuffer.hpp" -#include "gc/shared/collectedHeap.inline.hpp" -#include "interpreter/bytecodes.hpp" -#include "memory/resourceArea.hpp" -#include "nativeInst_zero.hpp" -#include "oops/oop.inline.hpp" - -int InlineCacheBuffer::ic_stub_code_size() { - // NB set this once the functions below are implemented - return 4; -} - -void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin, - void* cached_oop, - address entry_point) { - // NB ic_stub_code_size() must return the size of the code we generate - ShouldNotCallThis(); -} - -address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) { - // NB ic_stub_code_size() must return the size of the code we generate - ShouldNotCallThis(); - return nullptr; -} - -void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) { - ShouldNotCallThis(); - return nullptr; -} diff --git a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp index 4244b5817db..986cee68512 100644 --- a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp +++ b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp @@ -26,10 +26,8 @@ #include "precompiled.hpp" #include "asm/assembler.inline.hpp" #include "code/debugInfoRec.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" -#include "oops/compiledICHolder.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/vframeArray.hpp" diff --git a/src/hotspot/os/aix/attachListener_aix.cpp b/src/hotspot/os/aix/attachListener_aix.cpp index 2e079c9b3a1..51e2b2b3c0a 100644 --- a/src/hotspot/os/aix/attachListener_aix.cpp +++ b/src/hotspot/os/aix/attachListener_aix.cpp @@ -478,14 +478,14 @@ AttachOperation* AttachListener::dequeue() { void AttachListener::vm_start() { char fn[UNIX_PATH_MAX]; - struct stat64 st; + struct stat st; int ret; int n = snprintf(fn, UNIX_PATH_MAX, "%s/.java_pid%d", os::get_temp_directory(), os::current_process_id()); assert(n < (int)UNIX_PATH_MAX, "java_pid file name buffer overflow"); - RESTARTABLE(::stat64(fn, &st), ret); + RESTARTABLE(::stat(fn, &st), ret); if (ret == 0) { ret = ::unlink(fn); if (ret == -1) { @@ -505,8 +505,8 @@ int AttachListener::pd_init() { bool AttachListener::check_socket_file() { int ret; - struct stat64 st; - ret = stat64(AixAttachListener::path(), &st); + struct stat st; + ret = stat(AixAttachListener::path(), &st); if (ret == -1) { // need to restart attach listener. log_debug(attach)("Socket file %s does not exist - Restart Attach Listener", AixAttachListener::path()); @@ -545,14 +545,14 @@ bool AttachListener::is_init_trigger() { } char fn[PATH_MAX + 1]; int ret; - struct stat64 st; + struct stat st; os::snprintf_checked(fn, sizeof(fn), ".attach_pid%d", os::current_process_id()); - RESTARTABLE(::stat64(fn, &st), ret); + RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_trace(attach)("Failed to find attach file: %s, trying alternate", fn); snprintf(fn, sizeof(fn), "%s/.attach_pid%d", os::get_temp_directory(), os::current_process_id()); - RESTARTABLE(::stat64(fn, &st), ret); + RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_debug(attach)("Failed to find attach file: %s", fn); } diff --git a/src/hotspot/os/aix/globals_aix.hpp b/src/hotspot/os/aix/globals_aix.hpp index a047e79b695..fb353348a53 100644 --- a/src/hotspot/os/aix/globals_aix.hpp +++ b/src/hotspot/os/aix/globals_aix.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2018 SAP SE. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,11 +49,12 @@ "Allow VM to run with EXTSHM=ON.") \ \ /* Maximum expected size of the data segment. That correlates with the */ \ - /* to the maximum C Heap consumption we expect. */ \ - /* We need to know this because we need to leave "breathing space" for the */ \ - /* data segment when placing the java heap. If that space is too small, we */ \ - /* reduce our chance of getting a low heap address (needed for compressed */ \ - /* Oops). */ \ + /* maximum C Heap consumption we expect. */ \ + /* We need to leave "breathing space" for the data segment when */ \ + /* placing the java heap. If the MaxExpectedDataSegmentSize setting */ \ + /* is too small, we might run into resource issues creating many native */ \ + /* threads, if it is too large, we reduce our chance of getting a low heap */ \ + /* address (needed for compressed Oops). */ \ product(uintx, MaxExpectedDataSegmentSize, 8*G, \ "Maximum expected Data Segment Size.") \ \ diff --git a/src/hotspot/os/aix/libperfstat_aix.cpp b/src/hotspot/os/aix/libperfstat_aix.cpp index f547b4c78e7..0185d7d041c 100644 --- a/src/hotspot/os/aix/libperfstat_aix.cpp +++ b/src/hotspot/os/aix/libperfstat_aix.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2018 SAP SE. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 SAP SE. All rights reserved. * Copyright (c) 2022, IBM Corp. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -213,12 +213,8 @@ bool libperfstat::get_cpuinfo(cpuinfo_t* pci) { if (-1 == libperfstat::perfstat_cpu_total(nullptr, &psct, sizeof(PERFSTAT_CPU_TOTAL_T_LATEST), 1)) { if (-1 == libperfstat::perfstat_cpu_total(nullptr, &psct, sizeof(perfstat_cpu_total_t_71), 1)) { - if (-1 == libperfstat::perfstat_cpu_total(nullptr, &psct, sizeof(perfstat_cpu_total_t_61), 1)) { - if (-1 == libperfstat::perfstat_cpu_total(nullptr, &psct, sizeof(perfstat_cpu_total_t_53), 1)) { - trcVerbose("perfstat_cpu_total() failed (errno=%d)", errno); - return false; - } - } + trcVerbose("perfstat_cpu_total() failed (errno=%d)", errno); + return false; } } @@ -252,14 +248,8 @@ bool libperfstat::get_partitioninfo(partitioninfo_t* ppi) { if (-1 == libperfstat::perfstat_partition_total(nullptr, &pspt, sizeof(PERFSTAT_PARTITON_TOTAL_T_LATEST), 1)) { if (-1 == libperfstat::perfstat_partition_total(nullptr, &pspt, sizeof(perfstat_partition_total_t_71), 1)) { ame_details = false; - if (-1 == libperfstat::perfstat_partition_total(nullptr, &pspt, sizeof(perfstat_partition_total_t_61), 1)) { - if (-1 == libperfstat::perfstat_partition_total(nullptr, &pspt, sizeof(perfstat_partition_total_t_53), 1)) { - if (-1 == libperfstat::perfstat_partition_total(nullptr, &pspt, sizeof(perfstat_partition_total_t_53_5), 1)) { - trcVerbose("perfstat_partition_total() failed (errno=%d)", errno); - return false; - } - } - } + trcVerbose("perfstat_partition_total() failed (errno=%d)", errno); + return false; } } @@ -324,10 +314,8 @@ bool libperfstat::get_wparinfo(wparinfo_t* pwi) { memset (&pswt, '\0', sizeof(pswt)); if (-1 == libperfstat::perfstat_wpar_total(nullptr, &pswt, sizeof(PERFSTAT_WPAR_TOTAL_T_LATEST), 1)) { - if (-1 == libperfstat::perfstat_wpar_total(nullptr, &pswt, sizeof(perfstat_wpar_total_t_61), 1)) { - trcVerbose("perfstat_wpar_total() failed (errno=%d)", errno); - return false; - } + trcVerbose("perfstat_wpar_total() failed (errno=%d)", errno); + return false; } // WPAR type info. diff --git a/src/hotspot/os/aix/libperfstat_aix.hpp b/src/hotspot/os/aix/libperfstat_aix.hpp index 704c5b41a31..67cae0d08b6 100644 --- a/src/hotspot/os/aix/libperfstat_aix.hpp +++ b/src/hotspot/os/aix/libperfstat_aix.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2018 SAP SE. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 SAP SE. All rights reserved. * Copyright (c) 2022, IBM Corp. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -38,16 +38,8 @@ #include /////////////////////////////////////////////////////////////////////////////////////////////// -// These are excerpts from the AIX 5.3, 6.1, 7.1 libperfstat.h - +// These are excerpts from the AIX 7.1 libperfstat.h - // this is all we need from libperfstat.h and I want to avoid having to include -// -// Note: I define all structures as if I were to include libperfstat.h on an AIX 5.2 -// build machine. -// -// The ratio behind that is that if I would build on an AIX 5.2 build machine, -// include libperfstat.h and hard-link against libperfstat.a, the program should -// work without recompilation on all newer AIX versions. -// #define IDENTIFIER_LENGTH 64 /* length of strings included in the structures */ #define FIRST_CPU "" /* pseudo-name for fist CPU */ @@ -94,169 +86,6 @@ typedef struct { /* Virtual memory utilization */ } perfstat_memory_total_t; -typedef struct { /* global cpu information AIX 5.3 < TL10 */ - int ncpus; /* number of active logical processors */ - int ncpus_cfg; /* number of configured processors */ - char description[IDENTIFIER_LENGTH]; /* processor description (type/official name) */ - u_longlong_t processorHZ; /* processor speed in Hz */ - u_longlong_t user; /* raw total number of clock ticks spent in user mode */ - u_longlong_t sys; /* raw total number of clock ticks spent in system mode */ - u_longlong_t idle; /* raw total number of clock ticks spent idle */ - u_longlong_t wait; /* raw total number of clock ticks spent waiting for I/O */ - u_longlong_t pswitch; /* number of process switches (change in currently running process) */ - u_longlong_t syscall; /* number of system calls executed */ - u_longlong_t sysread; /* number of read system calls executed */ - u_longlong_t syswrite; /* number of write system calls executed */ - u_longlong_t sysfork; /* number of forks system calls executed */ - u_longlong_t sysexec; /* number of execs system calls executed */ - u_longlong_t readch; /* number of characters transferred with read system call */ - u_longlong_t writech; /* number of characters transferred with write system call */ - u_longlong_t devintrs; /* number of device interrupts */ - u_longlong_t softintrs; /* number of software interrupts */ - time_t lbolt; /* number of ticks since last reboot */ - u_longlong_t loadavg[3]; /* (1<. */ - u_longlong_t runque; /* length of the run queue (processes ready) */ - u_longlong_t swpque; /* ength of the swap queue (processes waiting to be paged in) */ - u_longlong_t bread; /* number of blocks read */ - u_longlong_t bwrite; /* number of blocks written */ - u_longlong_t lread; /* number of logical read requests */ - u_longlong_t lwrite; /* number of logical write requests */ - u_longlong_t phread; /* number of physical reads (reads on raw devices) */ - u_longlong_t phwrite; /* number of physical writes (writes on raw devices) */ - u_longlong_t runocc; /* updated whenever runque is updated, i.e. the runqueue is occupied. - * This can be used to compute the simple average of ready processes */ - u_longlong_t swpocc; /* updated whenever swpque is updated. i.e. the swpqueue is occupied. - * This can be used to compute the simple average processes waiting to be paged in */ - u_longlong_t iget; /* number of inode lookups */ - u_longlong_t namei; /* number of vnode lookup from a path name */ - u_longlong_t dirblk; /* number of 512-byte block reads by the directory search routine to locate an entry for a file */ - u_longlong_t msg; /* number of IPC message operations */ - u_longlong_t sema; /* number of IPC semaphore operations */ - u_longlong_t rcvint; /* number of tty receive interrupts */ - u_longlong_t xmtint; /* number of tyy transmit interrupts */ - u_longlong_t mdmint; /* number of modem interrupts */ - u_longlong_t tty_rawinch; /* number of raw input characters */ - u_longlong_t tty_caninch; /* number of canonical input characters (always zero) */ - u_longlong_t tty_rawoutch; /* number of raw output characters */ - u_longlong_t ksched; /* number of kernel processes created */ - u_longlong_t koverf; /* kernel process creation attempts where: - * -the user has forked to their maximum limit - * -the configuration limit of processes has been reached */ - u_longlong_t kexit; /* number of kernel processes that became zombies */ - u_longlong_t rbread; /* number of remote read requests */ - u_longlong_t rcread; /* number of cached remote reads */ - u_longlong_t rbwrt; /* number of remote writes */ - u_longlong_t rcwrt; /* number of cached remote writes */ - u_longlong_t traps; /* number of traps */ - int ncpus_high; /* index of highest processor online */ - u_longlong_t puser; /* raw number of physical processor tics in user mode */ - u_longlong_t psys; /* raw number of physical processor tics in system mode */ - u_longlong_t pidle; /* raw number of physical processor tics idle */ - u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */ - u_longlong_t decrintrs; /* number of decrementer tics interrupts */ - u_longlong_t mpcrintrs; /* number of mpc's received interrupts */ - u_longlong_t mpcsintrs; /* number of mpc's sent interrupts */ - u_longlong_t phantintrs; /* number of phantom interrupts */ - u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */ - u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */ - u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */ - u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */ - u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */ - u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */ - u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */ - u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */ - short iowait; /* number of processes that are asleep waiting for buffered I/O */ - short physio; /* number of processes waiting for raw I/O */ - longlong_t twait; /* number of threads that are waiting for filesystem direct(cio) */ - u_longlong_t hpi; /* number of hypervisor page-ins */ - u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds) */ -} perfstat_cpu_total_t_53; - -typedef struct { /* global cpu information AIX 6.1|5.3 > TL09 */ - int ncpus; /* number of active logical processors */ - int ncpus_cfg; /* number of configured processors */ - char description[IDENTIFIER_LENGTH]; /* processor description (type/official name) */ - u_longlong_t processorHZ; /* processor speed in Hz */ - u_longlong_t user; /* raw total number of clock ticks spent in user mode */ - u_longlong_t sys; /* raw total number of clock ticks spent in system mode */ - u_longlong_t idle; /* raw total number of clock ticks spent idle */ - u_longlong_t wait; /* raw total number of clock ticks spent waiting for I/O */ - u_longlong_t pswitch; /* number of process switches (change in currently running process) */ - u_longlong_t syscall; /* number of system calls executed */ - u_longlong_t sysread; /* number of read system calls executed */ - u_longlong_t syswrite; /* number of write system calls executed */ - u_longlong_t sysfork; /* number of forks system calls executed */ - u_longlong_t sysexec; /* number of execs system calls executed */ - u_longlong_t readch; /* number of characters transferred with read system call */ - u_longlong_t writech; /* number of characters transferred with write system call */ - u_longlong_t devintrs; /* number of device interrupts */ - u_longlong_t softintrs; /* number of software interrupts */ - time_t lbolt; /* number of ticks since last reboot */ - u_longlong_t loadavg[3]; /* (1<. */ - u_longlong_t runque; /* length of the run queue (processes ready) */ - u_longlong_t swpque; /* length of the swap queue (processes waiting to be paged in) */ - u_longlong_t bread; /* number of blocks read */ - u_longlong_t bwrite; /* number of blocks written */ - u_longlong_t lread; /* number of logical read requests */ - u_longlong_t lwrite; /* number of logical write requests */ - u_longlong_t phread; /* number of physical reads (reads on raw devices) */ - u_longlong_t phwrite; /* number of physical writes (writes on raw devices) */ - u_longlong_t runocc; /* updated whenever runque is updated, i.e. the runqueue is occupied. - * This can be used to compute the simple average of ready processes */ - u_longlong_t swpocc; /* updated whenever swpque is updated. i.e. the swpqueue is occupied. - * This can be used to compute the simple average processes waiting to be paged in */ - u_longlong_t iget; /* number of inode lookups */ - u_longlong_t namei; /* number of vnode lookup from a path name */ - u_longlong_t dirblk; /* number of 512-byte block reads by the directory search routine to locate an entry for a file */ - u_longlong_t msg; /* number of IPC message operations */ - u_longlong_t sema; /* number of IPC semaphore operations */ - u_longlong_t rcvint; /* number of tty receive interrupts */ - u_longlong_t xmtint; /* number of tyy transmit interrupts */ - u_longlong_t mdmint; /* number of modem interrupts */ - u_longlong_t tty_rawinch; /* number of raw input characters */ - u_longlong_t tty_caninch; /* number of canonical input characters (always zero) */ - u_longlong_t tty_rawoutch; /* number of raw output characters */ - u_longlong_t ksched; /* number of kernel processes created */ - u_longlong_t koverf; /* kernel process creation attempts where: - * -the user has forked to their maximum limit - * -the configuration limit of processes has been reached */ - u_longlong_t kexit; /* number of kernel processes that became zombies */ - u_longlong_t rbread; /* number of remote read requests */ - u_longlong_t rcread; /* number of cached remote reads */ - u_longlong_t rbwrt; /* number of remote writes */ - u_longlong_t rcwrt; /* number of cached remote writes */ - u_longlong_t traps; /* number of traps */ - int ncpus_high; /* index of highest processor online */ - u_longlong_t puser; /* raw number of physical processor tics in user mode */ - u_longlong_t psys; /* raw number of physical processor tics in system mode */ - u_longlong_t pidle; /* raw number of physical processor tics idle */ - u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */ - u_longlong_t decrintrs; /* number of decrementer tics interrupts */ - u_longlong_t mpcrintrs; /* number of mpc's received interrupts */ - u_longlong_t mpcsintrs; /* number of mpc's sent interrupts */ - u_longlong_t phantintrs; /* number of phantom interrupts */ - u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */ - u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */ - u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */ - u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */ - u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */ - u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */ - u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */ - u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */ - short iowait; /* number of processes that are asleep waiting for buffered I/O */ - short physio; /* number of processes waiting for raw I/O */ - longlong_t twait; /* number of threads that are waiting for filesystem direct(cio) */ - u_longlong_t hpi; /* number of hypervisor page-ins */ - u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds) */ - u_longlong_t puser_spurr; /* number of spurr cycles spent in user mode */ - u_longlong_t psys_spurr; /* number of spurr cycles spent in kernel mode */ - u_longlong_t pidle_spurr; /* number of spurr cycles spent in idle mode */ - u_longlong_t pwait_spurr; /* number of spurr cycles spent in wait mode */ - int spurrflag; /* set if running in spurr mode */ -} perfstat_cpu_total_t_61; - typedef struct { /* global cpu information AIX 7.1 */ int ncpus; /* number of active logical processors */ int ncpus_cfg; /* number of configured processors */ @@ -564,166 +393,6 @@ typedef union { } b; } perfstat_partition_type_t; -typedef struct { /* partition total information AIX 5.3 < TL6 */ - char name[IDENTIFIER_LENGTH]; /* name of the logical partition */ - perfstat_partition_type_t type; /* set of bits describing the partition */ - int lpar_id; /* logical partition identifier */ - int group_id; /* identifier of the LPAR group this partition is a member of */ - int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */ - int online_cpus; /* number of virtual CPUs currently online on the partition */ - int max_cpus; /* maximum number of virtual CPUs this partition can ever have */ - int min_cpus; /* minimum number of virtual CPUs this partition must have */ - u_longlong_t online_memory; /* amount of memory currently online */ - u_longlong_t max_memory; /* maximum amount of memory this partition can ever have */ - u_longlong_t min_memory; /* minimum amount of memory this partition must have */ - int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */ - int max_proc_capacity; /* maximum number of processor units this partition can ever have */ - int min_proc_capacity; /* minimum number of processor units this partition must have */ - int proc_capacity_increment; /* increment value to the entitled capacity */ - int unalloc_proc_capacity; /* number of processor units currently unallocated in the shared processor pool this partition belongs to */ - int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */ - int unalloc_var_proc_capacity_weight; /* number of variable processor capacity weight units currently unallocated in the shared processor pool this partition belongs to */ - int online_phys_cpus_sys; /* number of physical CPUs currently active in the system containing this partition */ - int max_phys_cpus_sys; /* maximum possible number of physical CPUs in the system containing this partition */ - int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */ - u_longlong_t puser; /* raw number of physical processor tics in user mode */ - u_longlong_t psys; /* raw number of physical processor tics in system mode */ - u_longlong_t pidle; /* raw number of physical processor tics idle */ - u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */ - u_longlong_t pool_idle_time; /* number of clock tics a processor in the shared pool was idle */ - u_longlong_t phantintrs; /* number of phantom interrupts received by the partition */ - u_longlong_t invol_virt_cswitch; /* number involuntary virtual CPU context switches */ - u_longlong_t vol_virt_cswitch; /* number voluntary virtual CPU context switches */ - u_longlong_t timebase_last; /* most recently cpu time base */ - u_longlong_t reserved_pages; /* Currently number of 16GB pages. Cannot participate in DR operations */ - u_longlong_t reserved_pagesize; /* Currently 16GB pagesize Cannot participate in DR operations */ -} perfstat_partition_total_t_53_5; - -typedef struct { /* partition total information AIX 5.3 < TL10 */ - char name[IDENTIFIER_LENGTH]; /* name of the logical partition */ - perfstat_partition_type_t type; /* set of bits describing the partition */ - int lpar_id; /* logical partition identifier */ - int group_id; /* identifier of the LPAR group this partition is a member of */ - int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */ - int online_cpus; /* number of virtual CPUs currently online on the partition */ - int max_cpus; /* maximum number of virtual CPUs this partition can ever have */ - int min_cpus; /* minimum number of virtual CPUs this partition must have */ - u_longlong_t online_memory; /* amount of memory currently online */ - u_longlong_t max_memory; /* maximum amount of memory this partition can ever have */ - u_longlong_t min_memory; /* minimum amount of memory this partition must have */ - int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */ - int max_proc_capacity; /* maximum number of processor units this partition can ever have */ - int min_proc_capacity; /* minimum number of processor units this partition must have */ - int proc_capacity_increment; /* increment value to the entitled capacity */ - int unalloc_proc_capacity; /* number of processor units currently unallocated in the shared processor pool this partition belongs to */ - int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */ - int unalloc_var_proc_capacity_weight; /* number of variable processor capacity weight units currently unallocated in the shared processor pool this partition belongs to */ - int online_phys_cpus_sys; /* number of physical CPUs currently active in the system containing this partition */ - int max_phys_cpus_sys; /* maximum possible number of physical CPUs in the system containing this partition */ - int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */ - u_longlong_t puser; /* raw number of physical processor tics in user mode */ - u_longlong_t psys; /* raw number of physical processor tics in system mode */ - u_longlong_t pidle; /* raw number of physical processor tics idle */ - u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */ - u_longlong_t pool_idle_time; /* number of clock tics a processor in the shared pool was idle */ - u_longlong_t phantintrs; /* number of phantom interrupts received by the partition */ - u_longlong_t invol_virt_cswitch; /* number involuntary virtual CPU context switches */ - u_longlong_t vol_virt_cswitch; /* number voluntary virtual CPU context switches */ - u_longlong_t timebase_last; /* most recently cpu time base */ - u_longlong_t reserved_pages; /* Currently number of 16GB pages. Cannot participate in DR operations */ - u_longlong_t reserved_pagesize; /* Currently 16GB pagesize Cannot participate in DR operations */ - u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */ - u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */ - u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */ - u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */ - u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */ - u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */ - u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */ - u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */ - u_longlong_t shcpus_in_sys; /* Number of physical processors allocated for shared processor use */ - u_longlong_t max_pool_capacity; /* Maximum processor capacity of partitions pool */ - u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partitions pool */ - u_longlong_t pool_max_time; /* Summation of maximum time that could be consumed by the pool (nano seconds) */ - u_longlong_t pool_busy_time; /* Summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */ - u_longlong_t pool_scaled_busy_time; /* Scaled summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */ - u_longlong_t shcpu_tot_time; /* Summation of total time across all physical processors allocated for shared processor use (nano seconds) */ - u_longlong_t shcpu_busy_time; /* Summation of busy (non-idle) time accumulated across all shared processor partitions (nano seconds) */ - u_longlong_t shcpu_scaled_busy_time; /* Scaled summation of busy time accumulated across all shared processor partitions (nano seconds) */ - int ams_pool_id; /* AMS pool id of the pool the LPAR belongs to */ - int var_mem_weight; /* variable memory capacity weight */ - u_longlong_t iome; /* I/O memory entitlement of the partition in bytes*/ - u_longlong_t pmem; /* Physical memory currently backing the partition's logical memory in bytes*/ - u_longlong_t hpi; /* number of hypervisor page-ins */ - u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds)*/ - u_longlong_t hypv_pagesize; /* Hypervisor page size in KB*/ -} perfstat_partition_total_t_53; - -typedef struct { /* partition total information AIX 6.1|5.3 > TL09 */ - char name[IDENTIFIER_LENGTH]; /* name of the logical partition */ - perfstat_partition_type_t type; /* set of bits describing the partition */ - int lpar_id; /* logical partition identifier */ - int group_id; /* identifier of the LPAR group this partition is a member of */ - int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */ - int online_cpus; /* number of virtual CPUs currently online on the partition */ - int max_cpus; /* maximum number of virtual CPUs this partition can ever have */ - int min_cpus; /* minimum number of virtual CPUs this partition must have */ - u_longlong_t online_memory; /* amount of memory currently online */ - u_longlong_t max_memory; /* maximum amount of memory this partition can ever have */ - u_longlong_t min_memory; /* minimum amount of memory this partition must have */ - int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */ - int max_proc_capacity; /* maximum number of processor units this partition can ever have */ - int min_proc_capacity; /* minimum number of processor units this partition must have */ - int proc_capacity_increment; /* increment value to the entitled capacity */ - int unalloc_proc_capacity; /* number of processor units currently unallocated in the shared processor pool this partition belongs to */ - int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */ - int unalloc_var_proc_capacity_weight; /* number of variable processor capacity weight units currently unallocated in the shared processor pool this partition belongs to */ - int online_phys_cpus_sys; /* number of physical CPUs currently active in the system containing this partition */ - int max_phys_cpus_sys; /* maximum possible number of physical CPUs in the system containing this partition */ - int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */ - u_longlong_t puser; /* raw number of physical processor tics in user mode */ - u_longlong_t psys; /* raw number of physical processor tics in system mode */ - u_longlong_t pidle; /* raw number of physical processor tics idle */ - u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */ - u_longlong_t pool_idle_time; /* number of clock tics a processor in the shared pool was idle */ - u_longlong_t phantintrs; /* number of phantom interrupts received by the partition */ - u_longlong_t invol_virt_cswitch; /* number involuntary virtual CPU context switches */ - u_longlong_t vol_virt_cswitch; /* number voluntary virtual CPU context switches */ - u_longlong_t timebase_last; /* most recently cpu time base */ - u_longlong_t reserved_pages; /* Currently number of 16GB pages. Cannot participate in DR operations */ - u_longlong_t reserved_pagesize; /* Currently 16GB pagesize Cannot participate in DR operations */ - u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */ - u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */ - u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */ - u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */ - u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */ - u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */ - u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */ - u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */ - u_longlong_t shcpus_in_sys; /* Number of physical processors allocated for shared processor use */ - u_longlong_t max_pool_capacity; /* Maximum processor capacity of partitions pool */ - u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partitions pool */ - u_longlong_t pool_max_time; /* Summation of maximum time that could be consumed by the pool (nano seconds) */ - u_longlong_t pool_busy_time; /* Summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */ - u_longlong_t pool_scaled_busy_time; /* Scaled summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */ - u_longlong_t shcpu_tot_time; /* Summation of total time across all physical processors allocated for shared processor use (nano seconds) */ - u_longlong_t shcpu_busy_time; /* Summation of busy (non-idle) time accumulated across all shared processor partitions (nano seconds) */ - u_longlong_t shcpu_scaled_busy_time; /* Scaled summation of busy time accumulated across all shared processor partitions (nano seconds) */ - int ams_pool_id; /* AMS pool id of the pool the LPAR belongs to */ - int var_mem_weight; /* variable memory capacity weight */ - u_longlong_t iome; /* I/O memory entitlement of the partition in bytes*/ - u_longlong_t pmem; /* Physical memory currently backing the partition's logical memory in bytes*/ - u_longlong_t hpi; /* number of hypervisor page-ins */ - u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds)*/ - u_longlong_t hypv_pagesize; /* Hypervisor page size in KB*/ - uint online_lcpus; /* number of online logical cpus */ - uint smt_thrds; /* number of hardware threads that are running */ - u_longlong_t puser_spurr; /* number of spurr cycles spent in user mode */ - u_longlong_t psys_spurr; /* number of spurr cycles spent in kernel mode */ - u_longlong_t pidle_spurr; /* number of spurr cycles spent in idle mode */ - u_longlong_t pwait_spurr; /* number of spurr cycles spent in wait mode */ - int spurrflag; /* set if running in spurr mode */ -} perfstat_partition_total_t_61; - typedef struct { /* partition total information AIX 7.1 */ char name[IDENTIFIER_LENGTH]; /* name of the logical partition */ perfstat_partition_type_t type; /* set of bits describing the partition */ @@ -941,17 +610,6 @@ typedef union { /* WPAR Type & Flags */ } b; } perfstat_wpar_type_t; -typedef struct { /* Workload partition Information AIX 5.3 & 6.1*/ - char name[MAXCORRALNAMELEN+1]; /* name of the Workload Partition */ - perfstat_wpar_type_t type; /* set of bits describing the wpar */ - cid_t wpar_id; /* workload partition identifier */ - uint online_cpus; /* Number of Virtual CPUs in partition rset or number of virtual CPUs currently online on the Global partition*/ - int cpu_limit; /* CPU limit in 100ths of % - 1..10000 */ - int mem_limit; /* Memory limit in 100ths of % - 1..10000 */ - u_longlong_t online_memory; /* amount of memory currently online in Global Partition */ - int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */ -} perfstat_wpar_total_t_61; - typedef struct { /* Workload partition Information AIX 7.1*/ char name[MAXCORRALNAMELEN+1]; /* name of the Workload Partition */ perfstat_wpar_type_t type; /* set of bits describing the wpar */ @@ -983,7 +641,7 @@ typedef struct { /* WPAR identifier */ -// end: libperfstat.h (AIX 5.2, 5.3, 6.1, 7.1) +// end: libperfstat.h (AIX 7.1) ////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define PERFSTAT_PARTITON_TOTAL_T_LATEST perfstat_partition_total_t_71_1 /* latest perfstat_partition_total_t structure */ diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index adaab8914a7..5d5ea364b66 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -29,7 +29,6 @@ // no precompiled headers #include "classfile/vmSymbols.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "compiler/compileBroker.hpp" #include "interpreter/interpreter.hpp" @@ -117,6 +116,10 @@ #include #include +#ifndef _LARGE_FILES +#error Hotspot on AIX must be compiled with -D_LARGE_FILES +#endif + // Missing prototypes for various system APIs. extern "C" int mread_real_time(timebasestruct_t *t, size_t size_of_timebasestruct_t); @@ -273,6 +276,22 @@ julong os::Aix::available_memory() { } } +jlong os::total_swap_space() { + perfstat_memory_total_t memory_info; + if (libperfstat::perfstat_memory_total(NULL, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { + return -1; + } + return (jlong)(memory_info.pgsp_total * 4 * K); +} + +jlong os::free_swap_space() { + perfstat_memory_total_t memory_info; + if (libperfstat::perfstat_memory_total(NULL, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { + return -1; + } + return (jlong)(memory_info.pgsp_free * 4 * K); +} + julong os::physical_memory() { return Aix::physical_memory(); } @@ -1584,7 +1603,7 @@ static char* reserve_shmated_memory (size_t bytes, char* requested_addr) { // Now attach the shared segment. // Note that we deliberately *don't* pass SHM_RND. The contract of os::attempt_reserve_memory_at() - - // which invokes this function with a request address != NULL - is to map at the specified address + // which invokes this function with a request address != nullptr - is to map at the specified address // excactly, or to fail. If the caller passed us an address that is not usable (aka not a valid segment // boundary), shmat should not round down the address, or think up a completely new one. // (In places where this matters, e.g. when reserving the heap, we take care of passing segment-aligned @@ -1886,6 +1905,10 @@ void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { void os::pd_free_memory(char *addr, size_t bytes, size_t alignment_hint) { } +size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) { + return page_size; +} + void os::numa_make_global(char *addr, size_t bytes) { } @@ -2506,10 +2529,10 @@ int os::open(const char *path, int oflag, int mode) { // IV90804: OPENING A FILE IN AFS WITH O_CLOEXEC FAILS WITH AN EINVAL ERROR APPLIES TO AIX 7100-04 17/04/14 PTF PECHANGE int oflag_with_o_cloexec = oflag | O_CLOEXEC; - int fd = ::open64(path, oflag_with_o_cloexec, mode); + int fd = ::open(path, oflag_with_o_cloexec, mode); if (fd == -1) { // we might fail in the open call when O_CLOEXEC is set, so try again without (see IV90804) - fd = ::open64(path, oflag, mode); + fd = ::open(path, oflag, mode); if (fd == -1) { return -1; } @@ -2517,8 +2540,8 @@ int os::open(const char *path, int oflag, int mode) { // If the open succeeded, the file might still be a directory. { - struct stat64 buf64; - int ret = ::fstat64(fd, &buf64); + struct stat buf64; + int ret = ::fstat(fd, &buf64); int st_mode = buf64.st_mode; if (ret != -1) { @@ -2572,17 +2595,17 @@ int os::open(const char *path, int oflag, int mode) { int os::create_binary_file(const char* path, bool rewrite_existing) { int oflags = O_WRONLY | O_CREAT; oflags |= rewrite_existing ? O_TRUNC : O_EXCL; - return ::open64(path, oflags, S_IREAD | S_IWRITE); + return ::open(path, oflags, S_IREAD | S_IWRITE); } // return current position of file pointer jlong os::current_file_offset(int fd) { - return (jlong)::lseek64(fd, (off64_t)0, SEEK_CUR); + return (jlong)::lseek(fd, (off_t)0, SEEK_CUR); } // move file pointer to the specified offset jlong os::seek_to_file_offset(int fd, jlong offset) { - return (jlong)::lseek64(fd, (off64_t)offset, SEEK_SET); + return (jlong)::lseek(fd, (off_t)offset, SEEK_SET); } // Map a block of memory. @@ -3027,4 +3050,3 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {} void os::jfr_report_memory_info() {} #endif // INCLUDE_JFR - diff --git a/src/hotspot/os/aix/os_perf_aix.cpp b/src/hotspot/os/aix/os_perf_aix.cpp index e1719df48c3..b5ae1a6a725 100644 --- a/src/hotspot/os/aix/os_perf_aix.cpp +++ b/src/hotspot/os/aix/os_perf_aix.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2022, IBM Corp. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, IBM Corp. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,6 +87,7 @@ static bool read_psinfo(const u_longlong_t& pid, psinfo_t& psinfo) { } len = fread(&psinfo, 1, sizeof(psinfo_t), fp); + fclose(fp); return len == sizeof(psinfo_t); } diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 958372e20a5..dbc18794cfe 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ // no precompiled headers #include "classfile/vmSymbols.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "compiler/compileBroker.hpp" #include "compiler/disassembler.hpp" @@ -181,6 +180,32 @@ void os::Bsd::print_uptime_info(outputStream* st) { } } +jlong os::total_swap_space() { +#if defined(__APPLE__) + struct xsw_usage vmusage; + size_t size = sizeof(vmusage); + if (sysctlbyname("vm.swapusage", &vmusage, &size, NULL, 0) != 0) { + return -1; + } + return (jlong)vmusage.xsu_total; +#else + return -1; +#endif +} + +jlong os::free_swap_space() { +#if defined(__APPLE__) + struct xsw_usage vmusage; + size_t size = sizeof(vmusage); + if (sysctlbyname("vm.swapusage", &vmusage, &size, NULL, 0) != 0) { + return -1; + } + return (jlong)vmusage.xsu_avail; +#else + return -1; +#endif +} + julong os::physical_memory() { return Bsd::physical_memory(); } @@ -985,6 +1010,13 @@ void *os::Bsd::dlopen_helper(const char *filename, int mode, char *ebuf, int ebu if (!ieee_handling) { Events::log_dll_message(nullptr, "IEEE subnormal handling check failed before loading %s", filename); log_info(os)("IEEE subnormal handling check failed before loading %s", filename); + if (CheckJNICalls) { + tty->print_cr("WARNING: IEEE subnormal handling check failed before loading %s", filename); + Thread* current = Thread::current(); + if (current->is_Java_thread()) { + JavaThread::cast(current)->print_jni_stack(); + } + } } // Save and restore the floating-point environment around dlopen(). @@ -1038,6 +1070,13 @@ void *os::Bsd::dlopen_helper(const char *filename, int mode, char *ebuf, int ebu } else { Events::log_dll_message(nullptr, "IEEE subnormal handling could not be corrected after loading %s", filename); log_info(os)("IEEE subnormal handling could not be corrected after loading %s", filename); + if (CheckJNICalls) { + tty->print_cr("WARNING: IEEE subnormal handling could not be corrected after loading %s", filename); + Thread* current = Thread::current(); + if (current->is_Java_thread()) { + JavaThread::cast(current)->print_jni_stack(); + } + } assert(false, "fesetenv didn't work"); } } @@ -1229,7 +1268,8 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { } #endif // !__APPLE__ -int _print_dll_info_cb(const char * name, address base_address, address top_address, void * param) { +static int _print_dll_info_cb(const char * name, address base_address, + address top_address, void * param) { outputStream * out = (outputStream *) param; out->print_cr(INTPTR_FORMAT " \t%s", (intptr_t)base_address, name); return 0; @@ -1623,6 +1663,10 @@ void os::pd_free_memory(char *addr, size_t bytes, size_t alignment_hint) { ::madvise(addr, bytes, MADV_DONTNEED); } +size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) { + return page_size; +} + void os::numa_make_global(char *addr, size_t bytes) { } diff --git a/src/hotspot/os/linux/attachListener_linux.cpp b/src/hotspot/os/linux/attachListener_linux.cpp index 41a24c45007..0e98bca0607 100644 --- a/src/hotspot/os/linux/attachListener_linux.cpp +++ b/src/hotspot/os/linux/attachListener_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -184,6 +184,8 @@ int LinuxAttachListener::init() { char initial_path[UNIX_PATH_MAX]; // socket file during setup int listener; // listener socket (file descriptor) + static_assert(sizeof(off_t) == 8, "Expected Large File Support in this file"); + // register function to cleanup if (!_atexit_registered) { _atexit_registered = true; @@ -446,14 +448,14 @@ AttachOperation* AttachListener::dequeue() { void AttachListener::vm_start() { char fn[UNIX_PATH_MAX]; - struct stat64 st; + struct stat st; int ret; int n = snprintf(fn, UNIX_PATH_MAX, "%s/.java_pid%d", os::get_temp_directory(), os::current_process_id()); assert(n < (int)UNIX_PATH_MAX, "java_pid file name buffer overflow"); - RESTARTABLE(::stat64(fn, &st), ret); + RESTARTABLE(::stat(fn, &st), ret); if (ret == 0) { ret = ::unlink(fn); if (ret == -1) { @@ -473,8 +475,8 @@ int AttachListener::pd_init() { bool AttachListener::check_socket_file() { int ret; - struct stat64 st; - ret = stat64(LinuxAttachListener::path(), &st); + struct stat st; + ret = stat(LinuxAttachListener::path(), &st); if (ret == -1) { // need to restart attach listener. log_debug(attach)("Socket file %s does not exist - Restart Attach Listener", LinuxAttachListener::path()); @@ -513,14 +515,14 @@ bool AttachListener::is_init_trigger() { } char fn[PATH_MAX + 1]; int ret; - struct stat64 st; + struct stat st; os::snprintf_checked(fn, sizeof(fn), ".attach_pid%d", os::current_process_id()); - RESTARTABLE(::stat64(fn, &st), ret); + RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_trace(attach)("Failed to find attach file: %s, trying alternate", fn); snprintf(fn, sizeof(fn), "%s/.attach_pid%d", os::get_temp_directory(), os::current_process_id()); - RESTARTABLE(::stat64(fn, &st), ret); + RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_debug(attach)("Failed to find attach file: %s", fn); } diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp index 15a0f7e97c9..068fd53b62d 100644 --- a/src/hotspot/os/linux/globals_linux.hpp +++ b/src/hotspot/os/linux/globals_linux.hpp @@ -130,7 +130,9 @@ develop(bool, DelayThreadStartALot, false, \ "Artificially delay thread starts randomly for testing.") \ \ - + product(bool, UseMadvPopulateWrite, true, DIAGNOSTIC, \ + "Use MADV_POPULATE_WRITE in os::pd_pretouch_memory.") \ + \ // end of RUNTIME_OS_FLAGS diff --git a/src/hotspot/os/linux/hugepages.cpp b/src/hotspot/os/linux/hugepages.cpp index 67645b91aa5..54e6c1adb7a 100644 --- a/src/hotspot/os/linux/hugepages.cpp +++ b/src/hotspot/os/linux/hugepages.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, 2023, Red Hat Inc. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,15 +36,15 @@ #include -StaticHugePageSupport::StaticHugePageSupport() : +ExplicitHugePageSupport::ExplicitHugePageSupport() : _initialized(false), _pagesizes(), _default_hugepage_size(SIZE_MAX), _inconsistent(false) {} -os::PageSizes StaticHugePageSupport::pagesizes() const { +os::PageSizes ExplicitHugePageSupport::pagesizes() const { assert(_initialized, "Not initialized"); return _pagesizes; } -size_t StaticHugePageSupport::default_hugepage_size() const { +size_t ExplicitHugePageSupport::default_hugepage_size() const { assert(_initialized, "Not initialized"); return _default_hugepage_size; } @@ -132,9 +132,9 @@ static os::PageSizes scan_hugepages() { return pagesizes; } -void StaticHugePageSupport::print_on(outputStream* os) { +void ExplicitHugePageSupport::print_on(outputStream* os) { if (_initialized) { - os->print_cr("Static hugepage support:"); + os->print_cr("Explicit hugepage support:"); for (size_t s = _pagesizes.smallest(); s != 0; s = _pagesizes.next_larger(s)) { os->print_cr(" hugepage size: " EXACTFMT, EXACTFMTARGS(s)); } @@ -143,18 +143,18 @@ void StaticHugePageSupport::print_on(outputStream* os) { os->print_cr(" unknown."); } if (_inconsistent) { - os->print_cr(" Support inconsistent. JVM will not use static hugepages."); + os->print_cr(" Support inconsistent. JVM will not use explicit hugepages."); } } -void StaticHugePageSupport::scan_os() { +void ExplicitHugePageSupport::scan_os() { _default_hugepage_size = scan_default_hugepagesize(); if (_default_hugepage_size > 0) { _pagesizes = scan_hugepages(); // See https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt: /proc/meminfo should match // /sys/kernel/mm/hugepages/hugepages-xxxx. However, we may run on a broken kernel (e.g. on WSL) // that only exposes /proc/meminfo but not /sys/kernel/mm/hugepages. In that case, we are not - // sure about the state of hugepage support by the kernel, so we won't use static hugepages. + // sure about the state of hugepage support by the kernel, so we won't use explicit hugepages. if (!_pagesizes.contains(_default_hugepage_size)) { log_info(pagesize)("Unexpected configuration: default pagesize (" SIZE_FORMAT ") " "has no associated directory in /sys/kernel/mm/hugepages..", _default_hugepage_size); @@ -307,18 +307,18 @@ void ShmemTHPSupport::print_on(outputStream* os) { } } -StaticHugePageSupport HugePages::_static_hugepage_support; +ExplicitHugePageSupport HugePages::_explicit_hugepage_support; THPSupport HugePages::_thp_support; ShmemTHPSupport HugePages::_shmem_thp_support; void HugePages::initialize() { - _static_hugepage_support.scan_os(); + _explicit_hugepage_support.scan_os(); _thp_support.scan_os(); _shmem_thp_support.scan_os(); } void HugePages::print_on(outputStream* os) { - _static_hugepage_support.print_on(os); + _explicit_hugepage_support.print_on(os); _thp_support.print_on(os); _shmem_thp_support.print_on(os); } diff --git a/src/hotspot/os/linux/hugepages.hpp b/src/hotspot/os/linux/hugepages.hpp index ce9ab36edcc..2e61fabc5a5 100644 --- a/src/hotspot/os/linux/hugepages.hpp +++ b/src/hotspot/os/linux/hugepages.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, 2023, Red Hat Inc. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,13 +34,13 @@ class outputStream; // Header contains the interface that reads OS information about // available hugepage support: -// - class StaticHugePageSupport - about static (non-THP) hugepages +// - class ExplicitHugePageSupport - about explicit (non-THP) hugepages // - class THPSupport - about transparent huge pages // and: // - class HugePages - a static umbrella wrapper // Information about static (non-thp) hugepages -class StaticHugePageSupport { +class ExplicitHugePageSupport { bool _initialized; // All supported hugepage sizes (sizes for which entries exist @@ -56,7 +56,7 @@ class StaticHugePageSupport { bool _inconsistent; public: - StaticHugePageSupport(); + ExplicitHugePageSupport(); void scan_os(); @@ -122,18 +122,18 @@ class ShmemTHPSupport { // Umbrella static interface class HugePages : public AllStatic { - static StaticHugePageSupport _static_hugepage_support; + static ExplicitHugePageSupport _explicit_hugepage_support; static THPSupport _thp_support; static ShmemTHPSupport _shmem_thp_support; public: - static const StaticHugePageSupport& static_info() { return _static_hugepage_support; } + static const ExplicitHugePageSupport& explicit_hugepage_info() { return _explicit_hugepage_support; } static const THPSupport& thp_info() { return _thp_support; } static const ShmemTHPSupport& shmem_thp_info() { return _shmem_thp_support; } - static size_t default_static_hugepage_size() { return _static_hugepage_support.default_hugepage_size(); } - static bool supports_static_hugepages() { return default_static_hugepage_size() > 0 && !_static_hugepage_support.inconsistent(); } + static size_t default_explicit_hugepage_size() { return _explicit_hugepage_support.default_hugepage_size(); } + static bool supports_explicit_hugepages() { return default_explicit_hugepage_size() > 0 && !_explicit_hugepage_support.inconsistent(); } static bool supports_thp() { return thp_mode() == THPMode::madvise || thp_mode() == THPMode::always; } static THPMode thp_mode() { return _thp_support.mode(); } diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp index ff2220bb33f..d3ba04742d1 100644 --- a/src/hotspot/os/linux/osContainer_linux.cpp +++ b/src/hotspot/os/linux/osContainer_linux.cpp @@ -167,7 +167,7 @@ jlong OSContainer::pids_current() { void OSContainer::print_container_helper(outputStream* st, jlong j, const char* metrics) { st->print("%s: ", metrics); - if (j > 0) { + if (j >= 0) { if (j >= 1024) { st->print_cr(UINT64_FORMAT " k", uint64_t(j) / K); } else { diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 95b55b877a9..e1ef0443885 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -25,7 +25,6 @@ // no precompiled headers #include "classfile/vmSymbols.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "compiler/compileBroker.hpp" #include "compiler/disassembler.hpp" @@ -292,6 +291,34 @@ julong os::Linux::free_memory() { return free_mem; } +jlong os::total_swap_space() { + if (OSContainer::is_containerized()) { + if (OSContainer::memory_limit_in_bytes() > 0) { + return (jlong)(OSContainer::memory_and_swap_limit_in_bytes() - OSContainer::memory_limit_in_bytes()); + } + } + struct sysinfo si; + int ret = sysinfo(&si); + if (ret != 0) { + return -1; + } + return (jlong)(si.totalswap * si.mem_unit); +} + +jlong os::free_swap_space() { + if (OSContainer::is_containerized()) { + // TODO add a good implementation + return -1; + } else { + struct sysinfo si; + int ret = sysinfo(&si); + if (ret != 0) { + return -1; + } + return (jlong)(si.freeswap * si.mem_unit); + } +} + julong os::physical_memory() { jlong phys_mem = 0; if (OSContainer::is_containerized()) { @@ -420,7 +447,7 @@ pid_t os::Linux::gettid() { julong os::Linux::host_swap() { struct sysinfo si; sysinfo(&si); - return (julong)si.totalswap; + return (julong)(si.totalswap * si.mem_unit); } // Most versions of linux have a bug where the number of processors are @@ -1816,6 +1843,13 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) { if (!ieee_handling) { Events::log_dll_message(nullptr, "IEEE subnormal handling check failed before loading %s", filename); log_info(os)("IEEE subnormal handling check failed before loading %s", filename); + if (CheckJNICalls) { + tty->print_cr("WARNING: IEEE subnormal handling check failed before loading %s", filename); + Thread* current = Thread::current(); + if (current->is_Java_thread()) { + JavaThread::cast(current)->print_jni_stack(); + } + } } // Save and restore the floating-point environment around dlopen(). @@ -1870,6 +1904,13 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) { } else { Events::log_dll_message(nullptr, "IEEE subnormal handling could not be corrected after loading %s", filename); log_info(os)("IEEE subnormal handling could not be corrected after loading %s", filename); + if (CheckJNICalls) { + tty->print_cr("WARNING: IEEE subnormal handling could not be corrected after loading %s", filename); + Thread* current = Thread::current(); + if (current->is_Java_thread()) { + JavaThread::cast(current)->print_jni_stack(); + } + } assert(false, "fesetenv didn't work"); } } @@ -2845,6 +2886,8 @@ void os::jvm_path(char *buf, jint buflen) { void linux_wrap_code(char* base, size_t size) { static volatile jint cnt = 0; + static_assert(sizeof(off_t) == 8, "Expected Large File Support in this file"); + if (!UseOprofile) { return; } @@ -2969,6 +3012,15 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec, #define MADV_HUGEPAGE 14 #endif +// Define MADV_POPULATE_WRITE here so we can build HotSpot on old systems. +#define MADV_POPULATE_WRITE_value 23 +#ifndef MADV_POPULATE_WRITE + #define MADV_POPULATE_WRITE MADV_POPULATE_WRITE_value +#else + // Sanity-check our assumed default value if we build with a new enough libc. + static_assert(MADV_POPULATE_WRITE == MADV_POPULATE_WRITE_value); +#endif + // Note that the value for MAP_FIXED_NOREPLACE differs between architectures, but all architectures // supported by OpenJDK share the same flag value. #define MAP_FIXED_NOREPLACE_value 0x100000 @@ -3028,6 +3080,31 @@ void os::pd_free_memory(char *addr, size_t bytes, size_t alignment_hint) { } } +size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) { + const size_t len = pointer_delta(last, first, sizeof(char)) + page_size; + // Use madvise to pretouch on Linux when THP is used, and fallback to the + // common method if unsupported. THP can form right after madvise rather than + // being assembled later. + if (HugePages::thp_mode() == THPMode::always || UseTransparentHugePages) { + int err = 0; + if (UseMadvPopulateWrite && + ::madvise(first, len, MADV_POPULATE_WRITE) == -1) { + err = errno; + } + if (!UseMadvPopulateWrite || err == EINVAL) { // Not to use or not supported + // When using THP we need to always pre-touch using small pages as the + // OS will initially always use small pages. + return os::vm_page_size(); + } else if (err != 0) { + log_info(gc, os)("::madvise(" PTR_FORMAT ", " SIZE_FORMAT ", %d) failed; " + "error='%s' (errno=%d)", p2i(first), len, + MADV_POPULATE_WRITE, os::strerror(err), err); + } + return 0; + } + return page_size; +} + void os::numa_make_global(char *addr, size_t bytes) { Linux::numa_interleave_memory(addr, bytes); } @@ -3747,14 +3824,14 @@ bool os::unguard_memory(char* addr, size_t size) { } static int hugetlbfs_page_size_flag(size_t page_size) { - if (page_size != HugePages::default_static_hugepage_size()) { + if (page_size != HugePages::default_explicit_hugepage_size()) { return (exact_log2(page_size) << MAP_HUGE_SHIFT); } return 0; } static bool hugetlbfs_sanity_check(size_t page_size) { - const os::PageSizes page_sizes = HugePages::static_info().pagesizes(); + const os::PageSizes page_sizes = HugePages::explicit_hugepage_info().pagesizes(); assert(page_sizes.contains(page_size), "Invalid page sizes passed"); // Include the page size flag to ensure we sanity check the correct page size. @@ -3934,8 +4011,8 @@ void os::Linux::large_page_init() { return; } - // Check if the OS supports static hugepages. - if (!UseTransparentHugePages && !HugePages::supports_static_hugepages()) { + // Check if the OS supports explicit hugepages. + if (!UseTransparentHugePages && !HugePages::supports_explicit_hugepages()) { warn_no_large_pages_configured(); UseLargePages = false; return; @@ -3954,12 +4031,12 @@ void os::Linux::large_page_init() { } else { - // In static hugepage mode: - // - os::large_page_size() is the default static hugepage size (/proc/meminfo "Hugepagesize") + // In explicit hugepage mode: + // - os::large_page_size() is the default explicit hugepage size (/proc/meminfo "Hugepagesize") // - os::pagesizes() contains all hugepage sizes the kernel supports, regardless whether there // are pages configured in the pool or not (from /sys/kernel/hugepages/hugepage-xxxx ...) - os::PageSizes all_large_pages = HugePages::static_info().pagesizes(); - const size_t default_large_page_size = HugePages::default_static_hugepage_size(); + os::PageSizes all_large_pages = HugePages::explicit_hugepage_info().pagesizes(); + const size_t default_large_page_size = HugePages::default_explicit_hugepage_size(); // 3) Consistency check and post-processing @@ -4043,7 +4120,7 @@ static bool commit_memory_special(size_t bytes, char* req_addr, bool exec) { assert(UseLargePages, "Should only get here for huge pages"); - assert(!UseTransparentHugePages, "Should only get here for static hugepage mode"); + assert(!UseTransparentHugePages, "Should only get here for explicit hugepage mode"); assert(is_aligned(bytes, page_size), "Unaligned size"); assert(is_aligned(req_addr, page_size), "Unaligned address"); assert(req_addr != nullptr, "Must have a requested address for special mappings"); @@ -4077,7 +4154,7 @@ static char* reserve_memory_special_huge_tlbfs(size_t bytes, size_t page_size, char* req_addr, bool exec) { - const os::PageSizes page_sizes = HugePages::static_info().pagesizes(); + const os::PageSizes page_sizes = HugePages::explicit_hugepage_info().pagesizes(); assert(UseLargePages, "only for Huge TLBFS large pages"); assert(is_aligned(req_addr, alignment), "Must be"); assert(is_aligned(req_addr, page_size), "Must be"); @@ -4156,7 +4233,7 @@ size_t os::large_page_size() { return _large_page_size; } -// static hugepages (hugetlbfs) allow application to commit large page memory +// explicit hugepages (hugetlbfs) allow application to commit large page memory // on demand. // However, when committing memory with hugepages fails, the region // that was supposed to be committed will lose the old reservation @@ -4207,7 +4284,7 @@ char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, bool size_t os::vm_min_address() { // Determined by sysctl vm.mmap_min_addr. It exists as a safety zone to prevent - // NULL pointer dereferences. + // null pointer dereferences. // Most distros set this value to 64 KB. It *can* be zero, but rarely is. Here, // we impose a minimum value if vm.mmap_min_addr is too low, for increased protection. static size_t value = 0; @@ -4335,7 +4412,7 @@ jlong os::Linux::fast_thread_cpu_time(clockid_t clockid) { // the number of bytes written to out_fd is returned if transfer was successful // otherwise, returns -1 that implies an error jlong os::Linux::sendfile(int out_fd, int in_fd, jlong* offset, jlong count) { - return ::sendfile64(out_fd, in_fd, (off64_t*)offset, (size_t)count); + return ::sendfile(out_fd, in_fd, (off_t*)offset, (size_t)count); } // Determine if the vmid is the parent pid for a child in a PID namespace. @@ -4450,6 +4527,9 @@ void os::init(void) { check_pax(); + // Check the availability of MADV_POPULATE_WRITE. + FLAG_SET_DEFAULT(UseMadvPopulateWrite, (::madvise(0, 0, MADV_POPULATE_WRITE) == 0)); + os::Posix::init(); } @@ -5028,14 +5108,14 @@ int os::open(const char *path, int oflag, int mode) { oflag |= O_CLOEXEC; #endif - int fd = ::open64(path, oflag, mode); + int fd = ::open(path, oflag, mode); if (fd == -1) return -1; //If the open succeeded, the file might still be a directory { - struct stat64 buf64; - int ret = ::fstat64(fd, &buf64); - int st_mode = buf64.st_mode; + struct stat buf; + int ret = ::fstat(fd, &buf); + int st_mode = buf.st_mode; if (ret != -1) { if ((st_mode & S_IFMT) == S_IFDIR) { @@ -5072,17 +5152,17 @@ int os::open(const char *path, int oflag, int mode) { int os::create_binary_file(const char* path, bool rewrite_existing) { int oflags = O_WRONLY | O_CREAT; oflags |= rewrite_existing ? O_TRUNC : O_EXCL; - return ::open64(path, oflags, S_IREAD | S_IWRITE); + return ::open(path, oflags, S_IREAD | S_IWRITE); } // return current position of file pointer jlong os::current_file_offset(int fd) { - return (jlong)::lseek64(fd, (off64_t)0, SEEK_CUR); + return (jlong)::lseek(fd, (off_t)0, SEEK_CUR); } // move file pointer to the specified offset jlong os::seek_to_file_offset(int fd, jlong offset) { - return (jlong)::lseek64(fd, (off64_t)offset, SEEK_SET); + return (jlong)::lseek(fd, (off_t)offset, SEEK_SET); } // Map a block of memory. diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 1158392fa49..339cc475b34 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -265,7 +265,7 @@ bool os::dir_is_empty(const char* path) { return result; } -static char* reserve_mmapped_memory(size_t bytes, char* requested_addr) { +static char* reserve_mmapped_memory(size_t bytes, char* requested_addr, MEMFLAGS flag) { char * addr; int flags = MAP_PRIVATE NOT_AIX( | MAP_NORESERVE ) | MAP_ANONYMOUS; if (requested_addr != nullptr) { @@ -280,13 +280,14 @@ static char* reserve_mmapped_memory(size_t bytes, char* requested_addr) { flags, -1, 0); if (addr != MAP_FAILED) { - MemTracker::record_virtual_memory_reserve((address)addr, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)addr, bytes, CALLER_PC, flag); return addr; } return nullptr; } static int util_posix_fallocate(int fd, off_t offset, off_t len) { + static_assert(sizeof(off_t) == 8, "Expected Large File Support in this file"); #ifdef __APPLE__ fstore_t store = { F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, len }; // First we try to get a continuous chunk of disk space @@ -392,7 +393,7 @@ char* os::reserve_memory_aligned(size_t size, size_t alignment, bool exec) { return chop_extra_memory(size, alignment, extra_base, extra_size); } -char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int file_desc) { +char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int file_desc, MEMFLAGS flag) { size_t extra_size = calculate_aligned_extra_size(size, alignment); // For file mapping, we do not call os:map_memory_to_file(size,fd) since: // - we later chop away parts of the mapping using os::release_memory and that could fail if the @@ -400,7 +401,7 @@ char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int file_des // - The memory API os::reserve_memory uses is an implementation detail. It may (and usually is) // mmap but it also may System V shared memory which cannot be uncommitted as a whole, so // chopping off and unmapping excess bits back and front (see below) would not work. - char* extra_base = reserve_mmapped_memory(extra_size, nullptr); + char* extra_base = reserve_mmapped_memory(extra_size, nullptr, flag); if (extra_base == nullptr) { return nullptr; } @@ -752,11 +753,11 @@ void os::dll_unload(void *lib) { } jlong os::lseek(int fd, jlong offset, int whence) { - return (jlong) BSD_ONLY(::lseek) NOT_BSD(::lseek64)(fd, offset, whence); + return (jlong) ::lseek(fd, offset, whence); } int os::ftruncate(int fd, jlong length) { - return BSD_ONLY(::ftruncate) NOT_BSD(::ftruncate64)(fd, length); + return ::ftruncate(fd, length); } const char* os::get_current_directory(char *buf, size_t buflen) { diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp index 8c71516f70b..d872a6dae89 100644 --- a/src/hotspot/os/posix/os_posix.hpp +++ b/src/hotspot/os/posix/os_posix.hpp @@ -31,7 +31,7 @@ // Note: the Posix API aims to capture functionality available on all Posix // compliant platforms, but in practice the implementations may depend on -// non-Posix functionality. For example, the use of lseek64 and ftruncate64. +// non-Posix functionality. // This use of non-Posix API's is made possible by compiling/linking in a mode // that is not restricted to being fully Posix complaint, such as by declaring // -D_GNU_SOURCE. But be aware that in doing so we may enable non-Posix diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index eaadb367315..6a958f8903b 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -340,7 +340,7 @@ static const struct { //////////////////////////////////////////////////////////////////////////////// // sun.misc.Signal and BREAK_SIGNAL support -void jdk_misc_signal_init() { +static void jdk_misc_signal_init() { // Initialize signal structures ::memset((void*)pending_signals, 0, sizeof(pending_signals)); @@ -380,7 +380,7 @@ int os::signal_wait() { //////////////////////////////////////////////////////////////////////////////// // signal chaining support -struct sigaction* get_chained_signal_action(int sig) { +static struct sigaction* get_chained_signal_action(int sig) { struct sigaction *actp = nullptr; if (libjsig_is_loaded) { @@ -1245,7 +1245,7 @@ int os::get_signal_number(const char* signal_name) { return -1; } -void set_signal_handler(int sig) { +static void set_signal_handler(int sig) { // Check for overwrite. struct sigaction oldAct; sigaction(sig, (struct sigaction*)nullptr, &oldAct); @@ -1292,7 +1292,7 @@ void set_signal_handler(int sig) { // install signal handlers for signals that HotSpot needs to // handle in order to support Java-level exception handling. -void install_signal_handlers() { +static void install_signal_handlers() { // signal-chaining typedef void (*signal_setting_t)(); signal_setting_t begin_signal_setting = nullptr; @@ -1723,7 +1723,7 @@ static void SR_handler(int sig, siginfo_t* siginfo, void* context) { errno = old_errno; } -int SR_initialize() { +static int SR_initialize() { struct sigaction act; char *s; // Get signal number to use for suspend/resume diff --git a/src/hotspot/os/windows/attachListener_windows.cpp b/src/hotspot/os/windows/attachListener_windows.cpp index da3b6c56739..7e455cf0a49 100644 --- a/src/hotspot/os/windows/attachListener_windows.cpp +++ b/src/hotspot/os/windows/attachListener_windows.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -248,10 +248,13 @@ Win32AttachOperation* Win32AttachListener::dequeue() { DWORD res = ::WaitForSingleObject(enqueued_ops_semaphore(), INFINITE); // returning from WaitForSingleObject will have decreased // the current count of the semaphore by 1. - guarantee(res == WAIT_OBJECT_0, "wait failed"); + guarantee(res != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); + guarantee(res == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", res); res = ::WaitForSingleObject(mutex(), INFINITE); - guarantee(res == WAIT_OBJECT_0, "wait failed"); + guarantee(res != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); + guarantee(res == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", res); + Win32AttachOperation* op = head(); if (op != nullptr) { @@ -338,6 +341,9 @@ void Win32AttachOperation::complete(jint result, bufferedStream* result_stream) } DWORD res = ::WaitForSingleObject(Win32AttachListener::mutex(), INFINITE); + assert(res != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); + assert(res == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", res); + if (res == WAIT_OBJECT_0) { // put the operation back on the available list diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 1b5c7850bf2..f9c3f23f0a6 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ // no precompiled headers #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" -#include "code/icBuffer.hpp" #include "code/nativeInst.hpp" #include "code/vtableStubs.hpp" #include "compiler/compileBroker.hpp" @@ -840,6 +839,20 @@ julong os::win32::available_memory() { return (julong)ms.ullAvailPhys; } +jlong os::total_swap_space() { + MEMORYSTATUSEX ms; + ms.dwLength = sizeof(ms); + GlobalMemoryStatusEx(&ms); + return (jlong) ms.ullTotalPageFile; +} + +jlong os::free_swap_space() { + MEMORYSTATUSEX ms; + ms.dwLength = sizeof(ms); + GlobalMemoryStatusEx(&ms); + return (jlong) ms.ullAvailPageFile; +} + julong os::physical_memory() { return win32::physical_memory(); } @@ -2469,9 +2482,9 @@ LONG Handle_IDiv_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) { #elif defined(_M_AMD64) PCONTEXT ctx = exceptionInfo->ContextRecord; address pc = (address)ctx->Rip; - guarantee(pc[0] >= Assembler::REX && pc[0] <= Assembler::REX_WRXB && pc[1] == 0xF7 || pc[0] == 0xF7, + guarantee((pc[0] >= Assembler::REX && pc[0] <= Assembler::REX_WRXB && pc[1] == 0xF7) || pc[0] == 0xF7, "not an idiv opcode, pc[0] = 0x%x and pc[1] = 0x%x", pc[0], pc[1]); - guarantee(pc[0] >= Assembler::REX && pc[0] <= Assembler::REX_WRXB && (pc[2] & ~0x7) == 0xF8 || (pc[1] & ~0x7) == 0xF8, + guarantee((pc[0] >= Assembler::REX && pc[0] <= Assembler::REX_WRXB && (pc[2] & ~0x7) == 0xF8) || (pc[1] & ~0x7) == 0xF8, "cannot handle non-register operands, pc[0] = 0x%x, pc[1] = 0x%x and pc[2] = 0x%x", pc[0], pc[1], pc[2]); if (pc[0] == 0xF7) { // set correct result values and continue after idiv instruction @@ -3330,7 +3343,7 @@ char* os::replace_existing_mapping_with_file_mapping(char* base, size_t size, in // Multiple threads can race in this code but it's not possible to unmap small sections of // virtual space to get requested alignment, like posix-like os's. // Windows prevents multiple thread from remapping over each other so this loop is thread-safe. -static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc) { +static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc, MEMFLAGS flag = mtNone) { assert(is_aligned(alignment, os::vm_allocation_granularity()), "Alignment must be a multiple of allocation granularity (page size)"); assert(is_aligned(size, os::vm_allocation_granularity()), @@ -3343,8 +3356,8 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi static const int max_attempts = 20; for (int attempt = 0; attempt < max_attempts && aligned_base == nullptr; attempt ++) { - char* extra_base = file_desc != -1 ? os::map_memory_to_file(extra_size, file_desc) : - os::reserve_memory(extra_size); + char* extra_base = file_desc != -1 ? os::map_memory_to_file(extra_size, file_desc, flag) : + os::reserve_memory(extra_size, false, flag); if (extra_base == nullptr) { return nullptr; } @@ -3360,8 +3373,8 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi // Attempt to map, into the just vacated space, the slightly smaller aligned area. // Which may fail, hence the loop. - aligned_base = file_desc != -1 ? os::attempt_map_memory_to_file_at(aligned_base, size, file_desc) : - os::attempt_reserve_memory_at(aligned_base, size); + aligned_base = file_desc != -1 ? os::attempt_map_memory_to_file_at(aligned_base, size, file_desc, flag) : + os::attempt_reserve_memory_at(aligned_base, size, false, flag); } assert(aligned_base != nullptr, "Did not manage to re-map after %d attempts?", max_attempts); @@ -3374,8 +3387,8 @@ char* os::reserve_memory_aligned(size_t size, size_t alignment, bool exec) { return map_or_reserve_memory_aligned(size, alignment, -1 /* file_desc */); } -char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int fd) { - return map_or_reserve_memory_aligned(size, alignment, fd); +char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int fd, MEMFLAGS flag) { + return map_or_reserve_memory_aligned(size, alignment, fd, flag); } char* os::pd_reserve_memory(size_t bytes, bool exec) { @@ -3796,6 +3809,11 @@ bool os::unguard_memory(char* addr, size_t bytes) { void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { } void os::pd_free_memory(char *addr, size_t bytes, size_t alignment_hint) { } + +size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) { + return page_size; +} + void os::numa_make_global(char *addr, size_t bytes) { } void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { } bool os::numa_topology_changed() { return false; } @@ -5354,7 +5372,8 @@ int PlatformEvent::park(jlong Millis) { phri = new HighResolutionInterval(prd); } rv = ::WaitForSingleObject(_ParkHandle, prd); - assert(rv == WAIT_OBJECT_0 || rv == WAIT_TIMEOUT, "WaitForSingleObject failed"); + assert(rv != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); + assert(rv == WAIT_OBJECT_0 || rv == WAIT_TIMEOUT, "WaitForSingleObject failed with return value: %lu", rv); if (rv == WAIT_TIMEOUT) { Millis -= prd; } @@ -5393,7 +5412,8 @@ void PlatformEvent::park() { // spin attempts by this thread. while (_Event < 0) { DWORD rv = ::WaitForSingleObject(_ParkHandle, INFINITE); - assert(rv == WAIT_OBJECT_0, "WaitForSingleObject failed"); + assert(rv != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); + assert(rv == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", rv); } // Usually we'll find _Event == 0 at this point, but as @@ -5456,16 +5476,25 @@ void Parker::park(bool isAbsolute, jlong time) { JavaThread* thread = JavaThread::current(); // Don't wait if interrupted or already triggered - if (thread->is_interrupted(false) || - WaitForSingleObject(_ParkHandle, 0) == WAIT_OBJECT_0) { + if (thread->is_interrupted(false)) { ResetEvent(_ParkHandle); return; } else { - ThreadBlockInVM tbivm(thread); - OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */); + DWORD rv = WaitForSingleObject(_ParkHandle, 0); + assert(rv != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); + assert(rv == WAIT_OBJECT_0 || rv == WAIT_TIMEOUT, "WaitForSingleObject failed with return value: %lu", rv); + if (rv == WAIT_OBJECT_0) { + ResetEvent(_ParkHandle); + return; + } else { + ThreadBlockInVM tbivm(thread); + OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */); - WaitForSingleObject(_ParkHandle, time); - ResetEvent(_ParkHandle); + rv = WaitForSingleObject(_ParkHandle, time); + assert(rv != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); + assert(rv == WAIT_OBJECT_0 || rv == WAIT_TIMEOUT, "WaitForSingleObject failed with return value: %lu", rv); + ResetEvent(_ParkHandle); + } } } @@ -5541,7 +5570,9 @@ int os::fork_and_exec(const char* cmd) { if (rslt) { // Wait until child process exits. - WaitForSingleObject(pi.hProcess, INFINITE); + DWORD rv = WaitForSingleObject(pi.hProcess, INFINITE); + assert(rv != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); + assert(rv == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", rv); GetExitCodeProcess(pi.hProcess, &exit_code); diff --git a/src/hotspot/os/windows/threadCritical_windows.cpp b/src/hotspot/os/windows/threadCritical_windows.cpp index f781a422484..c85143f8093 100644 --- a/src/hotspot/os/windows/threadCritical_windows.cpp +++ b/src/hotspot/os/windows/threadCritical_windows.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,8 @@ ThreadCritical::ThreadCritical() { if (lock_owner != current_thread) { // Grab the lock before doing anything. DWORD ret = WaitForSingleObject(lock_event, INFINITE); - assert(ret == WAIT_OBJECT_0, "unexpected return value from WaitForSingleObject"); + assert(ret != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); + assert(ret == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", ret); lock_owner = current_thread; } // Atomicity isn't required. Bump the recursion count. diff --git a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp index 5e0086521aa..242042d4247 100644 --- a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp +++ b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp @@ -28,7 +28,6 @@ #include "asm/assembler.inline.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" #include "jvm.h" diff --git a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp index fbd7c4eccd4..4750ed88056 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp +++ b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp @@ -29,7 +29,6 @@ #include "classfile/classLoader.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" #include "jvm.h" diff --git a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp index 37b92bc7ffd..c73e83996ff 100644 --- a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp +++ b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ #include "asm/macroAssembler.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" #include "jvm.h" @@ -351,7 +350,7 @@ frame os::get_sender_for_C_frame(frame* fr) { return frame(fr->sender_sp(), fr->link(), fr->sender_pc()); } -intptr_t* _get_previous_fp() { +static intptr_t* _get_previous_fp() { #if defined(__clang__) || defined(__llvm__) intptr_t **ebp; __asm__("mov %%" SPELL_REG_FP ", %0":"=r"(ebp)); diff --git a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp index 012f85ac0ff..0fc9484ce23 100644 --- a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp +++ b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp @@ -27,7 +27,6 @@ #include "asm/assembler.inline.hpp" #include "atomic_bsd_zero.hpp" #include "classfile/vmSymbols.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" #include "jvm.h" diff --git a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp index 4835eb9405a..3698896abb7 100644 --- a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp @@ -27,7 +27,6 @@ #include "asm/macroAssembler.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "code/nativeInst.hpp" #include "interpreter/interpreter.hpp" diff --git a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp index 86e8ed25618..55127058843 100644 --- a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp +++ b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp @@ -25,7 +25,6 @@ // no precompiled headers #include "asm/assembler.inline.hpp" #include "classfile/vmSymbols.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" #include "jvm.h" diff --git a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp index b570e3b6d7f..0b666f29c31 100644 --- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp +++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp @@ -28,7 +28,6 @@ #include "asm/assembler.inline.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" #include "jvm.h" diff --git a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp index 282467bc9e0..9f13e2bdd2c 100644 --- a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp @@ -27,7 +27,6 @@ #include "asm/macroAssembler.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" -#include "code/icBuffer.hpp" #include "code/nativeInst.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" @@ -39,6 +38,7 @@ #include "prims/jvm_misc.hpp" #include "runtime/arguments.hpp" #include "runtime/frame.inline.hpp" +#include "runtime/globals.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" @@ -406,6 +406,14 @@ static inline void atomic_copy64(const volatile void *src, volatile void *dst) { extern "C" { int SpinPause() { + if (UseZihintpause) { + // PAUSE is encoded as a FENCE instruction with pred=W, succ=0, fm=0, rd=x0, and rs1=x0. + // To do: __asm__ volatile("pause " : : : ); + // Since we're currently not passing '-march=..._zihintpause' to the compiler, + // it will not recognize the "pause" instruction, hence the hard-coded instruction. + __asm__ volatile(".word 0x0100000f " : : : ); + return 1; + } return 0; } diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp index 243c4b850ee..df4a2e347cc 100644 --- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp @@ -49,6 +49,36 @@ #define RISCV_HWPROBE_EXT_ZBA (1 << 3) #define RISCV_HWPROBE_EXT_ZBB (1 << 4) #define RISCV_HWPROBE_EXT_ZBS (1 << 5) +#define RISCV_HWPROBE_EXT_ZICBOZ (1 << 6) +#define RISCV_HWPROBE_EXT_ZBC (1 << 7) +#define RISCV_HWPROBE_EXT_ZBKB (1 << 8) +#define RISCV_HWPROBE_EXT_ZBKC (1 << 9) +#define RISCV_HWPROBE_EXT_ZBKX (1 << 10) +#define RISCV_HWPROBE_EXT_ZKND (1 << 11) +#define RISCV_HWPROBE_EXT_ZKNE (1 << 12) +#define RISCV_HWPROBE_EXT_ZKNH (1 << 13) +#define RISCV_HWPROBE_EXT_ZKSED (1 << 14) +#define RISCV_HWPROBE_EXT_ZKSH (1 << 15) +#define RISCV_HWPROBE_EXT_ZKT (1 << 16) +#define RISCV_HWPROBE_EXT_ZVBB (1 << 17) +#define RISCV_HWPROBE_EXT_ZVBC (1 << 18) +#define RISCV_HWPROBE_EXT_ZVKB (1 << 19) +#define RISCV_HWPROBE_EXT_ZVKG (1 << 20) +#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21) +#define RISCV_HWPROBE_EXT_ZVKNHA (1 << 22) +#define RISCV_HWPROBE_EXT_ZVKNHB (1 << 23) +#define RISCV_HWPROBE_EXT_ZVKSED (1 << 24) +#define RISCV_HWPROBE_EXT_ZVKSH (1 << 25) +#define RISCV_HWPROBE_EXT_ZVKT (1 << 26) +#define RISCV_HWPROBE_EXT_ZFH (1 << 27) +#define RISCV_HWPROBE_EXT_ZFHMIN (1 << 28) +#define RISCV_HWPROBE_EXT_ZIHINTNTL (1 << 29) +#define RISCV_HWPROBE_EXT_ZVFH (1 << 30) +#define RISCV_HWPROBE_EXT_ZVFHMIN (1 << 31) +#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32) +#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33) +#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34) +#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35) #define RISCV_HWPROBE_KEY_CPUPERF_0 5 #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) @@ -145,6 +175,9 @@ void RiscvHwprobe::add_features_from_query_result() { if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBS)) { VM_Version::ext_Zbs.enable_feature(); } + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZFH)) { + VM_Version::ext_Zfh.enable_feature(); + } if (is_valid(RISCV_HWPROBE_KEY_CPUPERF_0)) { VM_Version::unaligned_access.enable_feature( query[RISCV_HWPROBE_KEY_CPUPERF_0].value & RISCV_HWPROBE_MISALIGNED_MASK); diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp index 5230a06e43f..c7d61b33829 100644 --- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp @@ -169,13 +169,13 @@ void VM_Version::os_aux_features() { } VM_Version::VM_MODE VM_Version::parse_satp_mode(const char* vm_mode) { - if (!strcmp(vm_mode, "sv39")) { + if (!strncmp(vm_mode, "sv39", sizeof "sv39" - 1)) { return VM_SV39; - } else if (!strcmp(vm_mode, "sv48")) { + } else if (!strncmp(vm_mode, "sv48", sizeof "sv48" - 1)) { return VM_SV48; - } else if (!strcmp(vm_mode, "sv57")) { + } else if (!strncmp(vm_mode, "sv57", sizeof "sv57" - 1)) { return VM_SV57; - } else if (!strcmp(vm_mode, "sv64")) { + } else if (!strncmp(vm_mode, "sv64", sizeof "sv64" - 1)) { return VM_SV64; } else { return VM_MBARE; @@ -197,7 +197,7 @@ char* VM_Version::os_uarch_additional_features() { if ((p = strchr(buf, ':')) != nullptr) { if (mode == VM_NOTSET) { if (strncmp(buf, "mmu", sizeof "mmu" - 1) == 0) { - mode = VM_Version::parse_satp_mode(p); + mode = VM_Version::parse_satp_mode(p + 2); } } if (ret == nullptr) { @@ -244,6 +244,8 @@ void VM_Version::rivos_features() { ext_Zfh.enable_feature(); + ext_Zacas.enable_feature(); + ext_Zicboz.enable_feature(); ext_Zicsr.enable_feature(); ext_Zifencei.enable_feature(); ext_Zic64b.enable_feature(); diff --git a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp index 033ea14ead6..5aa65e705d9 100644 --- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp @@ -28,7 +28,6 @@ // no precompiled headers #include "asm/assembler.inline.hpp" #include "classfile/vmSymbols.hpp" -#include "code/icBuffer.hpp" #include "code/nativeInst.hpp" #include "code/vtableStubs.hpp" #include "compiler/disassembler.hpp" diff --git a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp index b211330409d..4dcaedf71da 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ #include "asm/macroAssembler.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" #include "jvm.h" @@ -165,7 +164,7 @@ frame os::get_sender_for_C_frame(frame* fr) { return frame(fr->sender_sp(), fr->link(), fr->sender_pc()); } -intptr_t* _get_previous_fp() { +static intptr_t* _get_previous_fp() { #if defined(__clang__) intptr_t **ebp; __asm__ __volatile__ ("mov %%" SPELL_REG_FP ", %0":"=r"(ebp):); diff --git a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp index 1ce73588524..d593c46d15d 100644 --- a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp +++ b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp @@ -27,7 +27,6 @@ #include "asm/assembler.inline.hpp" #include "atomic_linux_zero.hpp" #include "classfile/vmSymbols.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" #include "jvm.h" diff --git a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp index 46f718a9cd0..78e98609b6b 100644 --- a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp +++ b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp @@ -27,7 +27,6 @@ #include "asm/macroAssembler.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "code/nativeInst.hpp" #include "interpreter/interpreter.hpp" diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp index 4e18334315a..7e0814c014b 100644 --- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp +++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp @@ -25,7 +25,6 @@ // no precompiled headers #include "asm/macroAssembler.hpp" #include "classfile/vmSymbols.hpp" -#include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" #include "jvm.h" diff --git a/src/hotspot/share/adlc/main.cpp b/src/hotspot/share/adlc/main.cpp index 6d921cf5e7b..4d1c5491044 100644 --- a/src/hotspot/share/adlc/main.cpp +++ b/src/hotspot/share/adlc/main.cpp @@ -216,7 +216,6 @@ int main(int argc, char *argv[]) AD.addInclude(AD._CPP_file, "code/nativeInst.hpp"); AD.addInclude(AD._CPP_file, "code/vmreg.inline.hpp"); AD.addInclude(AD._CPP_file, "gc/shared/collectedHeap.inline.hpp"); - AD.addInclude(AD._CPP_file, "oops/compiledICHolder.hpp"); AD.addInclude(AD._CPP_file, "oops/compressedOops.hpp"); AD.addInclude(AD._CPP_file, "oops/markWord.hpp"); AD.addInclude(AD._CPP_file, "oops/method.hpp"); diff --git a/src/hotspot/share/asm/assembler.hpp b/src/hotspot/share/asm/assembler.hpp index 7b7dbd4ede7..a533b963844 100644 --- a/src/hotspot/share/asm/assembler.hpp +++ b/src/hotspot/share/asm/assembler.hpp @@ -359,6 +359,7 @@ class AbstractAssembler : public ResourceObj { } static bool is_uimm12(uint64_t x) { return is_uimm(x, 12); } + static bool is_uimm32(uint64_t x) { return is_uimm(x, 32); } // Accessors CodeSection* code_section() const { return _code_section; } diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index 7a0a31abf59..5b1e113f15d 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "asm/codeBuffer.hpp" +#include "code/compiledIC.hpp" #include "code/oopRecorder.inline.hpp" #include "compiler/disassembler.hpp" #include "logging/log.hpp" diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index 9ef1ed1f37c..48476bedfe2 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -209,7 +209,7 @@ class CodeSection { } void set_locs_point(address pc) { assert(pc >= locs_point(), "relocation addr may not decrease"); - assert(allocates2(pc), "relocation addr must be in this section"); + assert(allocates2(pc), "relocation addr " INTPTR_FORMAT " must be in this section from " INTPTR_FORMAT " to " INTPTR_FORMAT, p2i(pc), p2i(_start), p2i(_limit)); _locs_point = pc; } diff --git a/src/hotspot/share/asm/codeBuffer.inline.hpp b/src/hotspot/share/asm/codeBuffer.inline.hpp index 838447ad882..06ec9174b34 100644 --- a/src/hotspot/share/asm/codeBuffer.inline.hpp +++ b/src/hotspot/share/asm/codeBuffer.inline.hpp @@ -48,7 +48,7 @@ bool emit_shared_stubs_to_interp(CodeBuffer* cb, SharedStubToInterpRequests* sha shared_stub_to_interp_requests->sort(by_shared_method); MacroAssembler masm(cb); for (int i = 0; i < shared_stub_to_interp_requests->length();) { - address stub = __ start_a_stub(CompiledStaticCall::to_interp_stub_size()); + address stub = __ start_a_stub(CompiledDirectCall::to_interp_stub_size()); if (stub == nullptr) { return false; } diff --git a/src/hotspot/share/c1/c1_Canonicalizer.cpp b/src/hotspot/share/c1/c1_Canonicalizer.cpp index dab11d4f70e..0dbf29300d1 100644 --- a/src/hotspot/share/c1/c1_Canonicalizer.cpp +++ b/src/hotspot/share/c1/c1_Canonicalizer.cpp @@ -469,9 +469,11 @@ void Canonicalizer::do_CompareOp (CompareOp* x) { void Canonicalizer::do_IfOp(IfOp* x) { - // Caution: do not use do_Op2(x) here for now since - // we map the condition to the op for now! - move_const_to_right(x); + // Currently, Canonicalizer is only used by GraphBuilder, + // and IfOp is not created by GraphBuilder but only later + // when eliminating conditional expressions with CE_Eliminator, + // so this method will not be called. + ShouldNotReachHere(); } diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index 6e5fb99242c..396c83c6ab9 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -523,7 +523,7 @@ inline bool BlockListBuilder::is_successor(BlockBegin* block, BlockBegin* sux) { #ifndef PRODUCT -int compare_depth_first(BlockBegin** a, BlockBegin** b) { +static int compare_depth_first(BlockBegin** a, BlockBegin** b) { return (*a)->depth_first_number() - (*b)->depth_first_number(); } diff --git a/src/hotspot/share/c1/c1_LIRAssembler.cpp b/src/hotspot/share/c1/c1_LIRAssembler.cpp index 1744aa44481..51fb851d00c 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.cpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -606,13 +606,14 @@ void LIR_Assembler::emit_op0(LIR_Op0* op) { Unimplemented(); break; - case lir_std_entry: + case lir_std_entry: { // init offsets offsets()->set_value(CodeOffsets::OSR_Entry, _masm->offset()); - _masm->align(CodeEntryAlignment); if (needs_icache(compilation()->method())) { - check_icache(); + int offset = check_icache(); + offsets()->set_value(CodeOffsets::Entry, offset); } + _masm->align(CodeEntryAlignment); offsets()->set_value(CodeOffsets::Verified_Entry, _masm->offset()); _masm->verified_entry(compilation()->directive()->BreakAtExecuteOption); if (needs_clinit_barrier_on_entry(compilation()->method())) { @@ -621,6 +622,7 @@ void LIR_Assembler::emit_op0(LIR_Op0* op) { build_frame(); offsets()->set_value(CodeOffsets::Frame_Complete, _masm->offset()); break; + } case lir_osr_entry: offsets()->set_value(CodeOffsets::OSR_Entry, _masm->offset()); @@ -841,8 +843,6 @@ void LIR_Assembler::verify_oop_map(CodeEmitInfo* info) { if (v.is_oop()) { VMReg r = v.reg(); if (!r->is_stack()) { - stringStream st; - st.print("bad oop %s at %d", r->as_Register()->name(), _masm->offset()); _masm->verify_oop(r->as_Register()); } else { _masm->verify_stack_oop(r->reg2stack() * VMRegImpl::stack_slot_size); diff --git a/src/hotspot/share/c1/c1_LinearScan.cpp b/src/hotspot/share/c1/c1_LinearScan.cpp index 9e9195a0d60..a4d955e52a0 100644 --- a/src/hotspot/share/c1/c1_LinearScan.cpp +++ b/src/hotspot/share/c1/c1_LinearScan.cpp @@ -1446,12 +1446,12 @@ int LinearScan::interval_cmp(Interval** a, Interval** b) { } } -#ifndef PRODUCT -int interval_cmp(Interval* const& l, Interval* const& r) { +#ifdef ASSERT +static int interval_cmp(Interval* const& l, Interval* const& r) { return l->from() - r->from(); } -bool find_interval(Interval* interval, IntervalArray* intervals) { +static bool find_interval(Interval* interval, IntervalArray* intervals) { bool found; int idx = intervals->find_sorted(interval, found); @@ -2303,11 +2303,11 @@ void assert_no_register_values(GrowableArray* values) { } } -void assert_equal(Location l1, Location l2) { +static void assert_equal(Location l1, Location l2) { assert(l1.where() == l2.where() && l1.type() == l2.type() && l1.offset() == l2.offset(), ""); } -void assert_equal(ScopeValue* v1, ScopeValue* v2) { +static void assert_equal(ScopeValue* v1, ScopeValue* v2) { if (v1->is_location()) { assert(v2->is_location(), ""); assert_equal(((LocationValue*)v1)->location(), ((LocationValue*)v2)->location()); @@ -2328,12 +2328,12 @@ void assert_equal(ScopeValue* v1, ScopeValue* v2) { } } -void assert_equal(MonitorValue* m1, MonitorValue* m2) { +static void assert_equal(MonitorValue* m1, MonitorValue* m2) { assert_equal(m1->owner(), m2->owner()); assert_equal(m1->basic_lock(), m2->basic_lock()); } -void assert_equal(IRScopeDebugInfo* d1, IRScopeDebugInfo* d2) { +static void assert_equal(IRScopeDebugInfo* d1, IRScopeDebugInfo* d2) { assert(d1->scope() == d2->scope(), "not equal"); assert(d1->bci() == d2->bci(), "not equal"); @@ -2375,7 +2375,7 @@ void assert_equal(IRScopeDebugInfo* d1, IRScopeDebugInfo* d2) { } } -void check_stack_depth(CodeEmitInfo* info, int stack_end) { +static void check_stack_depth(CodeEmitInfo* info, int stack_end) { if (info->stack()->bci() != SynchronizationEntryBCI && !info->scope()->method()->is_native()) { Bytecodes::Code code = info->scope()->method()->java_code_at_bci(info->stack()->bci()); switch (code) { diff --git a/src/hotspot/share/c1/c1_MacroAssembler.hpp b/src/hotspot/share/c1/c1_MacroAssembler.hpp index 6a8304bd405..1e193ce0869 100644 --- a/src/hotspot/share/c1/c1_MacroAssembler.hpp +++ b/src/hotspot/share/c1/c1_MacroAssembler.hpp @@ -38,7 +38,6 @@ class C1_MacroAssembler: public MacroAssembler { //---------------------------------------------------- void explicit_null_check(Register base); - void inline_cache_check(Register receiver, Register iCache); void build_frame(int frame_size_in_bytes, int bang_size_in_bytes); void remove_frame(int frame_size_in_bytes); diff --git a/src/hotspot/share/c1/c1_Optimizer.cpp b/src/hotspot/share/c1/c1_Optimizer.cpp index 50009f9425a..dd428a5895b 100644 --- a/src/hotspot/share/c1/c1_Optimizer.cpp +++ b/src/hotspot/share/c1/c1_Optimizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -335,7 +335,7 @@ void Optimizer::eliminate_conditional_expressions() { } // This removes others' relation to block, but doesn't empty block's lists -void disconnect_from_graph(BlockBegin* block) { +static void disconnect_from_graph(BlockBegin* block) { for (int p = 0; p < block->number_of_preds(); p++) { BlockBegin* pred = block->pred_at(p); int idx; @@ -714,6 +714,8 @@ class NullCheckEliminator: public ValueVisitor { void handle_Phi (Phi* x); void handle_ProfileCall (ProfileCall* x); void handle_ProfileReturnType (ProfileReturnType* x); + void handle_Constant (Constant* x); + void handle_IfOp (IfOp* x); }; @@ -728,7 +730,7 @@ class NullCheckEliminator: public ValueVisitor { // that in for safety, otherwise should think more about it. void NullCheckVisitor::do_Phi (Phi* x) { nce()->handle_Phi(x); } void NullCheckVisitor::do_Local (Local* x) {} -void NullCheckVisitor::do_Constant (Constant* x) { /* FIXME: handle object constants */ } +void NullCheckVisitor::do_Constant (Constant* x) { nce()->handle_Constant(x); } void NullCheckVisitor::do_LoadField (LoadField* x) { nce()->handle_AccessField(x); } void NullCheckVisitor::do_StoreField (StoreField* x) { nce()->handle_AccessField(x); } void NullCheckVisitor::do_ArrayLength (ArrayLength* x) { nce()->handle_ArrayLength(x); } @@ -739,7 +741,7 @@ void NullCheckVisitor::do_ArithmeticOp (ArithmeticOp* x) { if (x->can_trap( void NullCheckVisitor::do_ShiftOp (ShiftOp* x) {} void NullCheckVisitor::do_LogicOp (LogicOp* x) {} void NullCheckVisitor::do_CompareOp (CompareOp* x) {} -void NullCheckVisitor::do_IfOp (IfOp* x) {} +void NullCheckVisitor::do_IfOp (IfOp* x) { nce()->handle_IfOp(x); } void NullCheckVisitor::do_Convert (Convert* x) {} void NullCheckVisitor::do_NullCheck (NullCheck* x) { nce()->handle_NullCheck(x); } void NullCheckVisitor::do_TypeCast (TypeCast* x) {} @@ -882,7 +884,9 @@ void NullCheckEliminator::iterate_one(BlockBegin* block) { // visiting instructions which are references in other blocks or // visiting instructions more than once. mark_visitable(instr); - if (instr->is_pinned() || instr->can_trap() || (instr->as_NullCheck() != nullptr)) { + if (instr->is_pinned() || instr->can_trap() || (instr->as_NullCheck() != nullptr) + || (instr->as_Constant() != nullptr && instr->as_Constant()->type()->is_object()) + || (instr->as_IfOp() != nullptr)) { mark_visited(instr); instr->input_values_do(this); instr->visit(&_visitor); @@ -1198,6 +1202,28 @@ void NullCheckEliminator::handle_ProfileReturnType(ProfileReturnType* x) { x->set_needs_null_check(!set_contains(x->ret())); } +void NullCheckEliminator::handle_Constant(Constant *x) { + ObjectType* ot = x->type()->as_ObjectType(); + if (ot != nullptr && ot->is_loaded()) { + ObjectConstant* oc = ot->as_ObjectConstant(); + if (oc == nullptr || !oc->value()->is_null_object()) { + set_put(x); + if (PrintNullCheckElimination) { + tty->print_cr("Constant %d is non-null", x->id()); + } + } + } +} + +void NullCheckEliminator::handle_IfOp(IfOp *x) { + if (x->type()->is_object() && set_contains(x->tval()) && set_contains(x->fval())) { + set_put(x); + if (PrintNullCheckElimination) { + tty->print_cr("IfOp %d is non-null", x->id()); + } + } +} + void Optimizer::eliminate_null_checks() { ResourceMark rm; diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index c2bfec3dfeb..f6e02594b5c 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -1664,9 +1664,9 @@ void FileMapInfo::close() { /* * Same as os::map_memory() but also pretouches if AlwaysPreTouch is enabled. */ -char* map_memory(int fd, const char* file_name, size_t file_offset, - char *addr, size_t bytes, bool read_only, - bool allow_exec, MEMFLAGS flags = mtNone) { +static char* map_memory(int fd, const char* file_name, size_t file_offset, + char *addr, size_t bytes, bool read_only, + bool allow_exec, MEMFLAGS flags = mtNone) { char* mem = os::map_memory(fd, file_name, file_offset, addr, bytes, AlwaysPreTouch ? false : read_only, allow_exec, flags); @@ -2156,7 +2156,7 @@ bool FileMapInfo::map_heap_region_impl() { if (_heap_pointers_need_patching) { char* bitmap_base = map_bitmap_region(); - if (bitmap_base == NULL) { + if (bitmap_base == nullptr) { log_info(cds)("CDS heap cannot be used because bitmap region cannot be mapped"); dealloc_heap_region(); unmap_region(MetaspaceShared::hp); diff --git a/src/hotspot/share/ci/ciField.cpp b/src/hotspot/share/ci/ciField.cpp index 0d4487fdf2f..0eddd87200a 100644 --- a/src/hotspot/share/ci/ciField.cpp +++ b/src/hotspot/share/ci/ciField.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ #include "oops/oop.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/handles.inline.hpp" -#include "runtime/reflectionUtils.hpp" +#include "runtime/reflection.hpp" // ciField // diff --git a/src/hotspot/share/ci/ciMethodData.cpp b/src/hotspot/share/ci/ciMethodData.cpp index dc7082c15ca..5abb342d031 100644 --- a/src/hotspot/share/ci/ciMethodData.cpp +++ b/src/hotspot/share/ci/ciMethodData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/klass.inline.hpp" +#include "oops/methodData.inline.hpp" #include "runtime/deoptimization.hpp" #include "utilities/copy.hpp" @@ -87,8 +88,18 @@ class PrepareExtraDataClosure : public CleanExtraDataClosure { // Preparation finished iff all Methods* were already cached. return true; } - // Holding locks through safepoints is bad practice. - MutexUnlocker mu(_mdo->extra_data_lock()); + // We are currently holding the extra_data_lock and ensuring + // no safepoint breaks the lock. + _mdo->check_extra_data_locked(); + + // We now want to cache some method data. This could cause a safepoint. + // We temporarily release the lock and allow safepoints, and revert that + // at the end of the scope. This is safe, since we currently do not hold + // any extra_method_data: finish is called only after clean_extra_data, + // and the outer scope that first aquired the lock should not hold any + // extra_method_data while cleaning is performed, as the offsets can change. + MutexUnlocker mu(_mdo->extra_data_lock(), Mutex::_no_safepoint_check_flag); + for (int i = 0; i < _uncached_methods.length(); ++i) { if (has_safepointed()) { // The metadata in the growable array might contain stale @@ -123,7 +134,10 @@ void ciMethodData::prepare_metadata() { void ciMethodData::load_remaining_extra_data() { MethodData* mdo = get_MethodData(); - MutexLocker ml(mdo->extra_data_lock()); + + // Lock to read ProfileData, and ensure lock is not unintentionally broken by a safepoint + MutexLocker ml(mdo->extra_data_lock(), Mutex::_no_safepoint_check_flag); + // Deferred metadata cleaning due to concurrent class unloading. prepare_metadata(); // After metadata preparation, there is no stale metadata, @@ -562,6 +576,9 @@ void ciMethodData::set_argument_type(int bci, int i, ciKlass* k) { VM_ENTRY_MARK; MethodData* mdo = get_MethodData(); if (mdo != nullptr) { + // Lock to read ProfileData, and ensure lock is not broken by a safepoint + MutexLocker ml(mdo->extra_data_lock(), Mutex::_no_safepoint_check_flag); + ProfileData* data = mdo->bci_to_data(bci); if (data != nullptr) { if (data->is_CallTypeData()) { @@ -586,6 +603,9 @@ void ciMethodData::set_return_type(int bci, ciKlass* k) { VM_ENTRY_MARK; MethodData* mdo = get_MethodData(); if (mdo != nullptr) { + // Lock to read ProfileData, and ensure lock is not broken by a safepoint + MutexLocker ml(mdo->extra_data_lock(), Mutex::_no_safepoint_check_flag); + ProfileData* data = mdo->bci_to_data(bci); if (data != nullptr) { if (data->is_CallTypeData()) { diff --git a/src/hotspot/share/classfile/altHashing.cpp b/src/hotspot/share/classfile/altHashing.cpp index 158a8a232a7..1d43d6ebf1e 100644 --- a/src/hotspot/share/classfile/altHashing.cpp +++ b/src/hotspot/share/classfile/altHashing.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,7 +120,7 @@ static void halfsiphash_init64(uint32_t v[4], uint64_t seed) { v[1] ^= 0xee; } -uint32_t halfsiphash_finish32(uint32_t v[4], int rounds) { +static uint32_t halfsiphash_finish32(uint32_t v[4], int rounds) { v[2] ^= 0xff; halfsiphash_rounds(v, rounds); return (v[1] ^ v[3]); diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index 43aa82b67f8..9ce49b71734 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -134,7 +134,8 @@ ClassPathEntry* ClassLoader::_last_module_path_entry = nullptr; #endif // helper routines -bool string_starts_with(const char* str, const char* str_to_find) { +#if INCLUDE_CDS +static bool string_starts_with(const char* str, const char* str_to_find) { size_t str_len = strlen(str); size_t str_to_find_len = strlen(str_to_find); if (str_to_find_len > str_len) { @@ -142,6 +143,7 @@ bool string_starts_with(const char* str, const char* str_to_find) { } return (strncmp(str, str_to_find, str_to_find_len) == 0); } +#endif static const char* get_jimage_version_string() { static char version_string[10] = ""; @@ -1009,8 +1011,8 @@ const char* ClassLoader::file_name_for_class_name(const char* class_name, return file_name; } -ClassPathEntry* find_first_module_cpe(ModuleEntry* mod_entry, - const GrowableArray* const module_list) { +static ClassPathEntry* find_first_module_cpe(ModuleEntry* mod_entry, + const GrowableArray* const module_list) { int num_of_entries = module_list->length(); const Symbol* class_module_name = mod_entry->name(); @@ -1355,7 +1357,7 @@ void ClassLoader::initialize(TRAPS) { setup_bootstrap_search_path(THREAD); } -char* lookup_vm_resource(JImageFile *jimage, const char *jimage_version, const char *path) { +static char* lookup_vm_resource(JImageFile *jimage, const char *jimage_version, const char *path) { jlong size; JImageLocationRef location = (*JImageFindResource)(jimage, "java.base", jimage_version, path, &size); if (location == 0) diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index e9a72195ecf..0e0e6b77d70 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -843,10 +843,10 @@ OopHandle ClassLoaderData::add_handle(Handle h) { void ClassLoaderData::remove_handle(OopHandle h) { assert(!is_unloading(), "Do not remove a handle for a CLD that is unloading"); - oop* ptr = h.ptr_raw(); - if (ptr != nullptr) { - assert(_handles.owner_of(ptr), "Got unexpected handle " PTR_FORMAT, p2i(ptr)); - NativeAccess<>::oop_store(ptr, oop(nullptr)); + if (!h.is_empty()) { + assert(_handles.owner_of(h.ptr_raw()), + "Got unexpected handle " PTR_FORMAT, p2i(h.ptr_raw())); + h.replace(oop(nullptr)); } } @@ -1008,7 +1008,11 @@ void ClassLoaderData::print_on(outputStream* out) const { _holder.print_on(out); out->print_cr(""); } - out->print_cr(" - class loader " INTPTR_FORMAT, p2i(_class_loader.ptr_raw())); + if (!_unloading) { + out->print_cr(" - class loader " INTPTR_FORMAT, p2i(_class_loader.peek())); + } else { + out->print_cr(" - class loader "); + } out->print_cr(" - metaspace " INTPTR_FORMAT, p2i(_metaspace)); out->print_cr(" - unloading %s", _unloading ? "true" : "false"); out->print_cr(" - class mirror holder %s", _has_class_mirror_holder ? "true" : "false"); diff --git a/src/hotspot/share/classfile/loaderConstraints.cpp b/src/hotspot/share/classfile/loaderConstraints.cpp index 4206fc10d4f..99d0c07ed42 100644 --- a/src/hotspot/share/classfile/loaderConstraints.cpp +++ b/src/hotspot/share/classfile/loaderConstraints.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -296,8 +296,8 @@ void LoaderConstraintTable::purge_loader_constraints() { _loader_constraint_table->unlink(&purge); } -void log_ldr_constraint_msg(Symbol* class_name, const char* reason, - ClassLoaderData* loader1, ClassLoaderData* loader2) { +static void log_ldr_constraint_msg(Symbol* class_name, const char* reason, + ClassLoaderData* loader1, ClassLoaderData* loader2) { LogTarget(Info, class, loader, constraints) lt; if (lt.is_enabled()) { ResourceMark rm; @@ -387,7 +387,7 @@ bool LoaderConstraintTable::add_entry(Symbol* class_name, } else if (pp1 == nullptr) { pp2->extend_loader_constraint(class_name, loader1, klass); } else if (pp2 == nullptr) { - pp1->extend_loader_constraint(class_name, loader1, klass); + pp1->extend_loader_constraint(class_name, loader2, klass); } else { merge_loader_constraints(class_name, pp1, pp2, klass); } diff --git a/src/hotspot/share/classfile/modules.cpp b/src/hotspot/share/classfile/modules.cpp index bd4be93b868..4664d9565d3 100644 --- a/src/hotspot/share/classfile/modules.cpp +++ b/src/hotspot/share/classfile/modules.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -259,7 +259,7 @@ static void define_javabase_module(Handle module_handle, jstring version, jstrin } // Caller needs ResourceMark. -void throw_dup_pkg_exception(const char* module_name, PackageEntry* package, TRAPS) { +static void throw_dup_pkg_exception(const char* module_name, PackageEntry* package, TRAPS) { const char* package_name = package->name()->as_C_string(); if (package->module()->is_named()) { THROW_MSG(vmSymbols::java_lang_IllegalStateException(), diff --git a/src/hotspot/share/classfile/placeholders.cpp b/src/hotspot/share/classfile/placeholders.cpp index 1bb5f878704..a6a86473ea7 100644 --- a/src/hotspot/share/classfile/placeholders.cpp +++ b/src/hotspot/share/classfile/placeholders.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -198,8 +198,8 @@ void PlaceholderEntry::set_supername(Symbol* supername) { // All threads examining the placeholder table must hold the // SystemDictionary_lock, so we don't need special precautions // on store ordering here. -PlaceholderEntry* add_entry(Symbol* class_name, ClassLoaderData* loader_data, - Symbol* supername){ +static PlaceholderEntry* add_entry(Symbol* class_name, ClassLoaderData* loader_data, + Symbol* supername){ assert_locked_or_safepoint(SystemDictionary_lock); assert(class_name != nullptr, "adding nullptr obj"); @@ -213,7 +213,7 @@ PlaceholderEntry* add_entry(Symbol* class_name, ClassLoaderData* loader_data, } // Remove a placeholder object. -void remove_entry(Symbol* class_name, ClassLoaderData* loader_data) { +static void remove_entry(Symbol* class_name, ClassLoaderData* loader_data) { assert_locked_or_safepoint(SystemDictionary_lock); PlaceholderKey key(class_name, loader_data); diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index 9e96340d82b..be2971288ef 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,7 +122,7 @@ volatile bool _alt_hash = false; static bool _rehashed = false; static uint64_t _alt_hash_seed = 0; -unsigned int hash_string(const jchar* s, int len, bool useAlt) { +static unsigned int hash_string(const jchar* s, int len, bool useAlt) { return useAlt ? AltHashing::halfsiphash_32(_alt_hash_seed, s, len) : java_lang_String::hash_code(s, len); diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index e635c825633..f2a88f00e0d 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -212,13 +212,13 @@ void SystemDictionary::set_platform_loader(ClassLoaderData *cld) { // ---------------------------------------------------------------------------- // Parallel class loading check -bool is_parallelCapable(Handle class_loader) { +static bool is_parallelCapable(Handle class_loader) { if (class_loader.is_null()) return true; return java_lang_ClassLoader::parallelCapable(class_loader()); } // ---------------------------------------------------------------------------- // ParallelDefineClass flag does not apply to bootclass loader -bool is_parallelDefine(Handle class_loader) { +static bool is_parallelDefine(Handle class_loader) { if (class_loader.is_null()) return false; if (AllowParallelDefineClass && java_lang_ClassLoader::parallelCapable(class_loader())) { return true; @@ -280,7 +280,7 @@ Symbol* SystemDictionary::class_name_symbol(const char* name, Symbol* exception, #ifdef ASSERT // Used to verify that class loading succeeded in adding k to the dictionary. -void verify_dictionary_entry(Symbol* class_name, InstanceKlass* k) { +static void verify_dictionary_entry(Symbol* class_name, InstanceKlass* k) { MutexLocker mu(SystemDictionary_lock); ClassLoaderData* loader_data = k->class_loader_data(); Dictionary* dictionary = loader_data->dictionary(); @@ -1111,14 +1111,13 @@ InstanceKlass* SystemDictionary::load_shared_lambda_proxy_class(InstanceKlass* i if (loaded_ik != nullptr) { assert(shared_nest_host->is_same_class_package(ik), "lambda proxy class and its nest host must be in the same package"); + // The lambda proxy class and its nest host have the same class loader and class loader data, + // as verified in SystemDictionaryShared::add_lambda_proxy_class() + assert(shared_nest_host->class_loader() == class_loader(), "mismatched class loader"); + assert(shared_nest_host->class_loader_data() == class_loader_data(class_loader), "mismatched class loader data"); + ik->set_nest_host(shared_nest_host); } - // The lambda proxy class and its nest host have the same class loader and class loader data, - // as verified in SystemDictionaryShared::add_lambda_proxy_class() - assert(shared_nest_host->class_loader() == class_loader(), "mismatched class loader"); - assert(shared_nest_host->class_loader_data() == class_loader_data(class_loader), "mismatched class loader data"); - ik->set_nest_host(shared_nest_host); - return loaded_ik; } diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 29748352684..44d7da5c4a4 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1348,7 +1348,7 @@ void SystemDictionaryShared::update_shared_entry(InstanceKlass* k, int id) { info->_id = id; } -const char* class_loader_name_for_shared(Klass* k) { +static const char* class_loader_name_for_shared(Klass* k) { assert(k != nullptr, "Sanity"); assert(k->is_shared(), "Must be"); assert(k->is_instance_klass(), "Must be"); diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp index 6c2eecf7ae7..6e72b4cbac3 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.cpp +++ b/src/hotspot/share/classfile/vmIntrinsics.cpp @@ -222,7 +222,6 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { case vmIntrinsics::_compareToLU: case vmIntrinsics::_compareToUL: case vmIntrinsics::_equalsL: - case vmIntrinsics::_equalsU: case vmIntrinsics::_equalsC: case vmIntrinsics::_vectorizedHashCode: case vmIntrinsics::_getCharStringU: @@ -532,7 +531,6 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { if (!SpecialStringIndexOf) return true; break; case vmIntrinsics::_equalsL: - case vmIntrinsics::_equalsU: if (!SpecialStringEquals) return true; break; case vmIntrinsics::_vectorizedHashCode: diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index c9bc4acbeff..6104fb5683b 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -402,7 +402,6 @@ class methodHandle; do_signature(indexOfI_signature, "([BI[BII)I") \ do_signature(indexOfChar_signature, "([BIII)I") \ do_intrinsic(_equalsL, java_lang_StringLatin1,equals_name, equalsB_signature, F_S) \ - do_intrinsic(_equalsU, java_lang_StringUTF16, equals_name, equalsB_signature, F_S) \ \ do_intrinsic(_isDigit, java_lang_CharacterDataLatin1, isDigit_name, int_bool_signature, F_R) \ do_name( isDigit_name, "isDigit") \ @@ -596,8 +595,8 @@ class methodHandle; do_intrinsic(_notifyJvmtiVThreadEnd, java_lang_VirtualThread, notifyJvmtiEnd_name, void_method_signature, F_RN) \ do_intrinsic(_notifyJvmtiVThreadMount, java_lang_VirtualThread, notifyJvmtiMount_name, bool_void_signature, F_RN) \ do_intrinsic(_notifyJvmtiVThreadUnmount, java_lang_VirtualThread, notifyJvmtiUnmount_name, bool_void_signature, F_RN) \ - do_intrinsic(_notifyJvmtiVThreadHideFrames, java_lang_VirtualThread, notifyJvmtiHideFrames_name, bool_void_signature, F_RN) \ - do_intrinsic(_notifyJvmtiVThreadDisableSuspend, java_lang_VirtualThread, notifyJvmtiDisableSuspend_name, bool_void_signature, F_RN) \ + do_intrinsic(_notifyJvmtiVThreadHideFrames, java_lang_VirtualThread, notifyJvmtiHideFrames_name, bool_void_signature, F_SN) \ + do_intrinsic(_notifyJvmtiVThreadDisableSuspend, java_lang_VirtualThread, notifyJvmtiDisableSuspend_name, bool_void_signature, F_SN) \ \ /* support for UnsafeConstants */ \ do_class(jdk_internal_misc_UnsafeConstants, "jdk/internal/misc/UnsafeConstants") \ diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 5a2c9456468..d24e29c288d 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ #include "precompiled.hpp" #include "code/codeBlob.hpp" #include "code/codeCache.hpp" -#include "code/icBuffer.hpp" #include "code/relocInfo.hpp" #include "code/vtableStubs.hpp" #include "compiler/disassembler.hpp" @@ -236,9 +235,9 @@ const ImmutableOopMap* CodeBlob::oop_map_for_return_address(address return_addre return _oop_maps->find_map_at_offset((intptr_t) return_address - (intptr_t) code_begin()); } -void CodeBlob::print_code() { +void CodeBlob::print_code_on(outputStream* st) { ResourceMark m; - Disassembler::decode(this, tty); + Disassembler::decode(this, st); } //---------------------------------------------------------------------------------------------------- @@ -649,11 +648,6 @@ void CodeBlob::dump_for_addr(address addr, outputStream* st, bool verbose) const st->print_cr(INTPTR_FORMAT " is pointing to an (unnamed) stub routine", p2i(addr)); return; } - // the InlineCacheBuffer is using stubs generated into a buffer blob - if (InlineCacheBuffer::contains(addr)) { - st->print_cr(INTPTR_FORMAT " is pointing into InlineCacheBuffer", p2i(addr)); - return; - } VtableStub* v = VtableStubs::stub_containing(addr); if (v != nullptr) { st->print_cr(INTPTR_FORMAT " is at entry_point+%d in a vtable stub", p2i(addr), (int)(addr - v->entry_point())); diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 6aae1acd84a..56caa906ecb 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -240,7 +240,7 @@ class CodeBlob { virtual void print_on(outputStream* st) const; virtual void print_value_on(outputStream* st) const; void dump_for_addr(address addr, outputStream* st, bool verbose) const; - void print_code(); + void print_code_on(outputStream* st); // Print to stream, any comments associated with offset. virtual void print_block_comment(outputStream* stream, address block_begin) const { diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index bf8c1d84e71..cdc9f3f50dc 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -29,7 +29,6 @@ #include "code/compiledIC.hpp" #include "code/dependencies.hpp" #include "code/dependencyContext.hpp" -#include "code/icBuffer.hpp" #include "code/nmethod.hpp" #include "code/pcDesc.hpp" #include "compiler/compilationPolicy.hpp" @@ -913,23 +912,6 @@ void CodeCache::verify_clean_inline_caches() { #endif } -void CodeCache::verify_icholder_relocations() { -#ifdef ASSERT - // make sure that we aren't leaking icholders - int count = 0; - FOR_ALL_HEAPS(heap) { - FOR_ALL_BLOBS(cb, *heap) { - CompiledMethod *nm = cb->as_compiled_method_or_null(); - if (nm != nullptr) { - count += nm->verify_icholder_relocations(); - } - } - } - assert(count + InlineCacheBuffer::pending_icholder_count() + CompiledICHolder::live_not_claimed_count() == - CompiledICHolder::live_count(), "must agree"); -#endif -} - // Defer freeing of concurrently cleaned ExceptionCache entries until // after a global handshake operation. void CodeCache::release_exception_cache(ExceptionCache* entry) { diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 103268c8ffc..d1c91727bf1 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -294,7 +294,6 @@ class CodeCache : AllStatic { } static void verify_clean_inline_caches(); - static void verify_icholder_relocations(); // Deoptimization private: diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp index c5063560ee5..250ef063a2a 100644 --- a/src/hotspot/share/code/compiledIC.cpp +++ b/src/hotspot/share/code/compiledIC.cpp @@ -26,27 +26,19 @@ #include "code/codeBehaviours.hpp" #include "code/codeCache.hpp" #include "code/compiledIC.hpp" -#include "code/icBuffer.hpp" #include "code/nmethod.hpp" #include "code/vtableStubs.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/linkResolver.hpp" -#include "memory/metadataFactory.hpp" -#include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" +#include "oops/compressedKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/method.inline.hpp" -#include "oops/oop.inline.hpp" -#include "oops/symbol.hpp" +#include "runtime/atomic.hpp" #include "runtime/continuationEntry.hpp" #include "runtime/handles.inline.hpp" -#include "runtime/icache.hpp" -#include "runtime/safepoint.hpp" +#include "runtime/interfaceSupport.inline.hpp" #include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" #include "sanitizers/leak.hpp" -#include "utilities/events.hpp" // Every time a compiled IC is changed or its type is being accessed, @@ -75,191 +67,175 @@ bool CompiledICLocker::is_safe(address code) { return CompiledICProtectionBehaviour::current()->is_safe(cm); } -//----------------------------------------------------------------------------- -// Low-level access to an inline cache. Private, since they might not be -// MT-safe to use. +CompiledICData::CompiledICData() + : _speculated_method(), + _speculated_klass(), + _itable_defc_klass(), + _itable_refc_klass(), + _is_initialized() {} -void* CompiledIC::cached_value() const { - assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); - assert (!is_optimized(), "an optimized virtual call does not have a cached metadata"); - - if (!is_in_transition_state()) { - void* data = get_data(); - // If we let the metadata value here be initialized to zero... - assert(data != nullptr || Universe::non_oop_word() == nullptr, - "no raw nulls in CompiledIC metadatas, because of patching races"); - return (data == (void*)Universe::non_oop_word()) ? nullptr : data; +// Inline cache callsite info is initialized once the first time it is resolved +void CompiledICData::initialize(CallInfo* call_info, Klass* receiver_klass) { + _speculated_method = call_info->selected_method(); + if (UseCompressedClassPointers) { + _speculated_klass = (uintptr_t)CompressedKlassPointers::encode_not_null(receiver_klass); } else { - return InlineCacheBuffer::cached_value_for((CompiledIC *)this); + _speculated_klass = (uintptr_t)receiver_klass; } + if (call_info->call_kind() == CallInfo::itable_call) { + _itable_defc_klass = call_info->resolved_method()->method_holder(); + _itable_refc_klass = call_info->resolved_klass(); + } + _is_initialized = true; } +bool CompiledICData::is_speculated_klass_unloaded() const { + return is_initialized() && _speculated_klass == 0; +} -void CompiledIC::internal_set_ic_destination(address entry_point, bool is_icstub, void* cache, bool is_icholder) { - assert(entry_point != nullptr, "must set legal entry point"); - assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); - assert (!is_optimized() || cache == nullptr, "an optimized virtual call does not have a cached metadata"); - assert (cache == nullptr || cache != (Metadata*)badOopVal, "invalid metadata"); - - assert(!is_icholder || is_icholder_entry(entry_point), "must be"); - - // Don't use ic_destination for this test since that forwards - // through ICBuffer instead of returning the actual current state of - // the CompiledIC. - if (is_icholder_entry(_call->destination())) { - // When patching for the ICStub case the cached value isn't - // overwritten until the ICStub copied into the CompiledIC during - // the next safepoint. Make sure that the CompiledICHolder* is - // marked for release at this point since it won't be identifiable - // once the entry point is overwritten. - InlineCacheBuffer::queue_for_release((CompiledICHolder*)get_data()); +void CompiledICData::clean_metadata() { + if (!is_initialized() || is_speculated_klass_unloaded()) { + return; } - if (TraceCompiledIC) { - tty->print(" "); - print_compiled_ic(); - tty->print(" changing destination to " INTPTR_FORMAT, p2i(entry_point)); - if (!is_optimized()) { - tty->print(" changing cached %s to " INTPTR_FORMAT, is_icholder ? "icholder" : "metadata", p2i((address)cache)); - } - if (is_icstub) { - tty->print(" (icstub)"); - } - tty->cr(); + // GC cleaning doesn't need to change the state of the inline cache, + // only nuke stale speculated metadata if it gets unloaded. If the + // inline cache is monomorphic, the unverified entries will miss, and + // subsequent miss handlers will upgrade the callsite to megamorphic, + // which makes sense as it obviously is megamorphic then. + if (!speculated_klass()->is_loader_alive()) { + Atomic::store(&_speculated_klass, (uintptr_t)0); + Atomic::store(&_speculated_method, (Method*)nullptr); } -#ifdef ASSERT - { - CodeBlob* cb = CodeCache::find_blob(_call->instruction_address()); - assert(cb != nullptr && cb->is_compiled(), "must be compiled"); - } -#endif - _call->set_destination_mt_safe(entry_point); + assert(_speculated_method == nullptr || _speculated_method->method_holder()->is_loader_alive(), + "Speculated method is not unloaded despite class being unloaded"); +} - if (is_optimized() || is_icstub) { - // Optimized call sites don't have a cache value and ICStub call - // sites only change the entry point. Changing the value in that - // case could lead to MT safety issues. - assert(cache == nullptr, "must be null"); +void CompiledICData::metadata_do(MetadataClosure* cl) { + if (!is_initialized()) { return; } - if (cache == nullptr) cache = Universe::non_oop_word(); - - set_data((intptr_t)cache); -} - - -void CompiledIC::set_ic_destination(ICStub* stub) { - internal_set_ic_destination(stub->code_begin(), true, nullptr, false); + if (!is_speculated_klass_unloaded()) { + cl->do_metadata(_speculated_method); + cl->do_metadata(speculated_klass()); + } + if (_itable_refc_klass != nullptr) { + cl->do_metadata(_itable_refc_klass); + } + if (_itable_defc_klass != nullptr) { + cl->do_metadata(_itable_defc_klass); + } } +Klass* CompiledICData::speculated_klass() const { + if (is_speculated_klass_unloaded()) { + return nullptr; + } - -address CompiledIC::ic_destination() const { - assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); - if (!is_in_transition_state()) { - return _call->destination(); + if (UseCompressedClassPointers) { + return CompressedKlassPointers::decode_not_null((narrowKlass)_speculated_klass); } else { - return InlineCacheBuffer::ic_destination_for((CompiledIC *)this); + return (Klass*)_speculated_klass; } } +//----------------------------------------------------------------------------- +// High-level access to an inline cache. Guaranteed to be MT-safe. -bool CompiledIC::is_in_transition_state() const { - assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); - return InlineCacheBuffer::contains(_call->destination());; +CompiledICData* CompiledIC::data() const { + return _data; } +CompiledICData* data_from_reloc_iter(RelocIterator* iter) { + assert(iter->type() == relocInfo::virtual_call_type, "wrong reloc. info"); + + virtual_call_Relocation* r = iter->virtual_call_reloc(); + NativeMovConstReg* value = nativeMovConstReg_at(r->cached_value()); + + return (CompiledICData*)value->data(); +} -bool CompiledIC::is_icholder_call() const { +CompiledIC::CompiledIC(RelocIterator* iter) + : _method(iter->code()), + _data(data_from_reloc_iter(iter)), + _call(nativeCall_at(iter->addr())) +{ + assert(_method != nullptr, "must pass compiled method"); + assert(_method->contains(iter->addr()), "must be in compiled method"); assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); - return !_is_optimized && is_icholder_entry(ic_destination()); } -// Returns native address of 'call' instruction in inline-cache. Used by -// the InlineCacheBuffer when it needs to find the stub. -address CompiledIC::stub_address() const { - assert(is_in_transition_state(), "should only be called when we are in a transition state"); - return _call->destination(); +CompiledIC* CompiledIC_before(CompiledMethod* nm, address return_addr) { + address call_site = nativeCall_before(return_addr)->instruction_address(); + return CompiledIC_at(nm, call_site); } -// Clears the IC stub if the compiled IC is in transition state -void CompiledIC::clear_ic_stub() { - if (is_in_transition_state()) { - ICStub* stub = ICStub::from_destination_address(stub_address()); - stub->clear(); - } +CompiledIC* CompiledIC_at(CompiledMethod* nm, address call_site) { + RelocIterator iter(nm, call_site, call_site + 1); + iter.next(); + return CompiledIC_at(&iter); } -//----------------------------------------------------------------------------- -// High-level access to an inline cache. Guaranteed to be MT-safe. +CompiledIC* CompiledIC_at(Relocation* call_reloc) { + address call_site = call_reloc->addr(); + CompiledMethod* cm = CodeCache::find_blob(call_reloc->addr())->as_compiled_method(); + return CompiledIC_at(cm, call_site); +} -void CompiledIC::initialize_from_iter(RelocIterator* iter) { - assert(iter->addr() == _call->instruction_address(), "must find ic_call"); +CompiledIC* CompiledIC_at(RelocIterator* reloc_iter) { + CompiledIC* c_ic = new CompiledIC(reloc_iter); + c_ic->verify(); + return c_ic; +} - if (iter->type() == relocInfo::virtual_call_type) { - virtual_call_Relocation* r = iter->virtual_call_reloc(); - _is_optimized = false; - _value = _call->get_load_instruction(r); - } else { - assert(iter->type() == relocInfo::opt_virtual_call_type, "must be a virtual call"); - _is_optimized = true; - _value = nullptr; +void CompiledIC::ensure_initialized(CallInfo* call_info, Klass* receiver_klass) { + if (!_data->is_initialized()) { + _data->initialize(call_info, receiver_klass); } } -CompiledIC::CompiledIC(CompiledMethod* cm, NativeCall* call) - : _method(cm) -{ - _call = _method->call_wrapper_at((address) call); - address ic_call = _call->instruction_address(); - - assert(ic_call != nullptr, "ic_call address must be set"); - assert(cm != nullptr, "must pass compiled method"); - assert(cm->contains(ic_call), "must be in compiled method"); - - // Search for the ic_call at the given address. - RelocIterator iter(cm, ic_call, ic_call+1); - bool ret = iter.next(); - assert(ret == true, "relocInfo must exist at this address"); - assert(iter.addr() == ic_call, "must find ic_call"); - - initialize_from_iter(&iter); +void CompiledIC::set_to_clean() { + log_debug(inlinecache)("IC@" INTPTR_FORMAT ": set to clean", p2i(_call->instruction_address())); + _call->set_destination_mt_safe(SharedRuntime::get_resolve_virtual_call_stub()); } -CompiledIC::CompiledIC(RelocIterator* iter) - : _method(iter->code()) -{ - _call = _method->call_wrapper_at(iter->addr()); - address ic_call = _call->instruction_address(); +void CompiledIC::set_to_monomorphic() { + assert(data()->is_initialized(), "must be initialized"); + Method* method = data()->speculated_method(); + CompiledMethod* code = method->code(); + address entry; + bool to_compiled = code != nullptr && code->is_in_use() && !code->is_unloading(); + + if (to_compiled) { + entry = code->entry_point(); + } else { + entry = method->get_c2i_unverified_entry(); + } - CompiledMethod* nm = iter->code(); - assert(ic_call != nullptr, "ic_call address must be set"); - assert(nm != nullptr, "must pass compiled method"); - assert(nm->contains(ic_call), "must be in compiled method"); + log_trace(inlinecache)("IC@" INTPTR_FORMAT ": monomorphic to %s: %s", + p2i(_call->instruction_address()), + to_compiled ? "compiled" : "interpreter", + method->print_value_string()); - initialize_from_iter(iter); + _call->set_destination_mt_safe(entry); } -// This function may fail for two reasons: either due to running out of vtable -// stubs, or due to running out of IC stubs in an attempted transition to a -// transitional state. The needs_ic_stub_refill value will be set if the failure -// was due to running out of IC stubs, in which case the caller will refill IC -// stubs and retry. -bool CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecode, - bool& needs_ic_stub_refill, TRAPS) { - assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); - assert(!is_optimized(), "cannot set an optimized virtual call to megamorphic"); - assert(is_call_to_compiled() || is_call_to_interpreted(), "going directly to megamorphic?"); +void CompiledIC::set_to_megamorphic(CallInfo* call_info) { + assert(data()->is_initialized(), "must be initialized"); address entry; - if (call_info->call_kind() == CallInfo::itable_call) { - assert(bytecode == Bytecodes::_invokeinterface, ""); + if (call_info->call_kind() == CallInfo::direct_call) { + // C1 sometimes compiles a callsite before the target method is loaded, resulting in + // dynamically bound callsites that should really be statically bound. However, the + // target method might not have a vtable or itable. We just wait for better code to arrive + return; + } else if (call_info->call_kind() == CallInfo::itable_call) { int itable_index = call_info->itable_index(); entry = VtableStubs::find_itable_stub(itable_index); if (entry == nullptr) { - return false; + return; } #ifdef ASSERT int index = call_info->resolved_method()->itable_index(); @@ -267,401 +243,151 @@ bool CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecod InstanceKlass* k = call_info->resolved_method()->method_holder(); assert(k->verify_itable_index(itable_index), "sanity check"); #endif //ASSERT - CompiledICHolder* holder = new CompiledICHolder(call_info->resolved_method()->method_holder(), - call_info->resolved_klass(), false); - holder->claim(); - if (!InlineCacheBuffer::create_transition_stub(this, holder, entry)) { - delete holder; - needs_ic_stub_refill = true; - return false; - } - // LSan appears unable to follow malloc-based memory consistently when embedded as an immediate - // in generated machine code. So we have to ignore it. - LSAN_IGNORE_OBJECT(holder); } else { - assert(call_info->call_kind() == CallInfo::vtable_call, "either itable or vtable"); + assert(call_info->call_kind() == CallInfo::vtable_call, "what else?"); // Can be different than selected_method->vtable_index(), due to package-private etc. int vtable_index = call_info->vtable_index(); assert(call_info->resolved_klass()->verify_vtable_index(vtable_index), "sanity check"); entry = VtableStubs::find_vtable_stub(vtable_index); if (entry == nullptr) { - return false; + return; } - if (!InlineCacheBuffer::create_transition_stub(this, nullptr, entry)) { - needs_ic_stub_refill = true; - return false; - } - } - - { - ResourceMark rm; - assert(call_info->selected_method() != nullptr, "Unexpected null selected method"); - log_trace(inlinecache)("IC@" INTPTR_FORMAT ": to megamorphic %s entry: " INTPTR_FORMAT, - p2i(instruction_address()), call_info->selected_method()->print_value_string(), p2i(entry)); } - // We can't check this anymore. With lazy deopt we could have already - // cleaned this IC entry before we even return. This is possible if - // we ran out of space in the inline cache buffer trying to do the - // set_next and we safepointed to free up space. This is a benign - // race because the IC entry was complete when we safepointed so - // cleaning it immediately is harmless. - // assert(is_megamorphic(), "sanity check"); - return true; -} - + log_trace(inlinecache)("IC@" INTPTR_FORMAT ": to megamorphic %s entry: " INTPTR_FORMAT, + p2i(_call->instruction_address()), call_info->selected_method()->print_value_string(), p2i(entry)); -// true if destination is megamorphic stub -bool CompiledIC::is_megamorphic() const { - assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); - assert(!is_optimized(), "an optimized call cannot be megamorphic"); - - // Cannot rely on cached_value. It is either an interface or a method. - return VtableStubs::entry_point(ic_destination()) != nullptr; + _call->set_destination_mt_safe(entry); + assert(is_megamorphic(), "sanity check"); } -bool CompiledIC::is_call_to_compiled() const { - assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); - - CodeBlob* cb = CodeCache::find_blob(ic_destination()); - bool is_monomorphic = (cb != nullptr && cb->is_compiled()); - // Check that the cached_value is a klass for non-optimized monomorphic calls - // This assertion is invalid for compiler1: a call that does not look optimized (no static stub) can be used - // for calling directly to vep without using the inline cache (i.e., cached_value == nullptr). - // For JVMCI this occurs because CHA is only used to improve inlining so call sites which could be optimized - // virtuals because there are no currently loaded subclasses of a type are left as virtual call sites. -#ifdef ASSERT - CodeBlob* caller = CodeCache::find_blob(instruction_address()); - bool is_c1_or_jvmci_method = caller->is_compiled_by_c1() || caller->is_compiled_by_jvmci(); - assert( is_c1_or_jvmci_method || - !is_monomorphic || - is_optimized() || - (cached_metadata() != nullptr && cached_metadata()->is_klass()), "sanity check"); -#endif // ASSERT - return is_monomorphic; -} +void CompiledIC::update(CallInfo* call_info, Klass* receiver_klass) { + // If this is the first time we fix the inline cache, we ensure it's initialized + ensure_initialized(call_info, receiver_klass); + if (is_megamorphic()) { + // Terminal state for the inline cache + return; + } -bool CompiledIC::is_call_to_interpreted() const { - assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); - // Call to interpreter if destination is either calling to a stub (if it - // is optimized), or calling to an I2C blob - bool is_call_to_interpreted = false; - if (!is_optimized()) { - CodeBlob* cb = CodeCache::find_blob(ic_destination()); - is_call_to_interpreted = (cb != nullptr && cb->is_adapter_blob()); - assert(!is_call_to_interpreted || (is_icholder_call() && cached_icholder() != nullptr), "sanity check"); + if (is_speculated_klass(receiver_klass)) { + // If the speculated class matches the receiver klass, we can speculate that will + // continue to be the case with a monomorphic inline cache + set_to_monomorphic(); } else { - // Check if we are calling into our own codeblob (i.e., to a stub) - address dest = ic_destination(); -#ifdef ASSERT - { - _call->verify_resolve_call(dest); - } -#endif /* ASSERT */ - is_call_to_interpreted = _call->is_call_to_interpreted(dest); + // If the dynamic type speculation fails, we try to transform to a megamorphic state + // for the inline cache using stubs to dispatch in tables + set_to_megamorphic(call_info); } - return is_call_to_interpreted; } -bool CompiledIC::set_to_clean(bool in_use) { - assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); - if (TraceInlineCacheClearing) { - tty->print_cr("IC@" INTPTR_FORMAT ": set to clean", p2i(instruction_address())); - print(); - } - log_trace(inlinecache)("IC@" INTPTR_FORMAT ": set to clean", p2i(instruction_address())); - - address entry = _call->get_resolve_call_stub(is_optimized()); - - bool safe_transition = _call->is_safe_for_patching() || !in_use || is_optimized() || SafepointSynchronize::is_at_safepoint(); +bool CompiledIC::is_clean() const { + return destination() == SharedRuntime::get_resolve_virtual_call_stub(); +} - if (safe_transition) { - // Kill any leftover stub we might have too - clear_ic_stub(); - if (is_optimized()) { - set_ic_destination(entry); - } else { - set_ic_destination_and_value(entry, (void*)nullptr); - } - } else { - // Unsafe transition - create stub. - if (!InlineCacheBuffer::create_transition_stub(this, nullptr, entry)) { - return false; - } - } - // We can't check this anymore. With lazy deopt we could have already - // cleaned this IC entry before we even return. This is possible if - // we ran out of space in the inline cache buffer trying to do the - // set_next and we safepointed to free up space. This is a benign - // race because the IC entry was complete when we safepointed so - // cleaning it immediately is harmless. - // assert(is_clean(), "sanity check"); - return true; +bool CompiledIC::is_monomorphic() const { + return !is_clean() && !is_megamorphic(); } -bool CompiledIC::is_clean() const { - assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); - bool is_clean = false; - address dest = ic_destination(); - is_clean = dest == _call->get_resolve_call_stub(is_optimized()); - assert(!is_clean || is_optimized() || cached_value() == nullptr, "sanity check"); - return is_clean; +bool CompiledIC::is_megamorphic() const { + return VtableStubs::entry_point(destination()) != nullptr;; } -bool CompiledIC::set_to_monomorphic(CompiledICInfo& info) { - assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); - // Updating a cache to the wrong entry can cause bugs that are very hard - // to track down - if cache entry gets invalid - we just clean it. In - // this way it is always the same code path that is responsible for - // updating and resolving an inline cache - // - // The above is no longer true. SharedRuntime::fixup_callers_callsite will change optimized - // callsites. In addition ic_miss code will update a site to monomorphic if it determines - // that an monomorphic call to the interpreter can now be monomorphic to compiled code. - // - // In both of these cases the only thing being modified is the jump/call target and these - // transitions are mt_safe - - Thread *thread = Thread::current(); - if (info.to_interpreter()) { - // Call to interpreter - if (info.is_optimized() && is_optimized()) { - assert(is_clean(), "unsafe IC path"); - // the call analysis (callee structure) specifies that the call is optimized - // (either because of CHA or the static target is final) - // At code generation time, this call has been emitted as static call - // Call via stub - assert(info.cached_metadata() != nullptr && info.cached_metadata()->is_method(), "sanity check"); - methodHandle method (thread, (Method*)info.cached_metadata()); - _call->set_to_interpreted(method, info); - - { - ResourceMark rm(thread); - log_trace(inlinecache)("IC@" INTPTR_FORMAT ": monomorphic to interpreter: %s", - p2i(instruction_address()), - method->print_value_string()); - } - } else { - // Call via method-klass-holder - CompiledICHolder* holder = info.claim_cached_icholder(); - if (!InlineCacheBuffer::create_transition_stub(this, holder, info.entry())) { - delete holder; - return false; - } - // LSan appears unable to follow malloc-based memory consistently when embedded as an - // immediate in generated machine code. So we have to ignore it. - LSAN_IGNORE_OBJECT(holder); - { - ResourceMark rm(thread); - log_trace(inlinecache)("IC@" INTPTR_FORMAT ": monomorphic to interpreter via icholder ", p2i(instruction_address())); - } - } - } else { - // Call to compiled code - bool static_bound = info.is_optimized() || (info.cached_metadata() == nullptr); -#ifdef ASSERT - CodeBlob* cb = CodeCache::find_blob(info.entry()); - assert (cb != nullptr && cb->is_compiled(), "must be compiled!"); -#endif /* ASSERT */ - - // This is MT safe if we come from a clean-cache and go through a - // non-verified entry point - bool safe = SafepointSynchronize::is_at_safepoint() || - (!is_in_transition_state() && (info.is_optimized() || static_bound || is_clean())); - - if (!safe) { - if (!InlineCacheBuffer::create_transition_stub(this, info.cached_metadata(), info.entry())) { - return false; - } - } else { - if (is_optimized()) { - set_ic_destination(info.entry()); - } else { - set_ic_destination_and_value(info.entry(), info.cached_metadata()); - } - } +bool CompiledIC::is_speculated_klass(Klass* receiver_klass) { + return data()->speculated_klass() == receiver_klass; +} - { - ResourceMark rm(thread); - assert(info.cached_metadata() == nullptr || info.cached_metadata()->is_klass(), "must be"); - log_trace(inlinecache)("IC@" INTPTR_FORMAT ": monomorphic to compiled (rcvr klass = %s) %s", - p2i(instruction_address()), - (info.cached_metadata() != nullptr) ? ((Klass*)info.cached_metadata())->print_value_string() : "nullptr", - (safe) ? "" : " via stub"); - } - } - // We can't check this anymore. With lazy deopt we could have already - // cleaned this IC entry before we even return. This is possible if - // we ran out of space in the inline cache buffer trying to do the - // set_next and we safepointed to free up space. This is a benign - // race because the IC entry was complete when we safepointed so - // cleaning it immediately is harmless. - // assert(is_call_to_compiled() || is_call_to_interpreted(), "sanity check"); - return true; -} - - -// is_optimized: Compiler has generated an optimized call (i.e. fixed, no inline cache) -// static_bound: The call can be static bound. If it isn't also optimized, the property -// wasn't provable at time of compilation. An optimized call will have any necessary -// null check, while a static_bound won't. A static_bound (but not optimized) must -// therefore use the unverified entry point. -void CompiledIC::compute_monomorphic_entry(const methodHandle& method, - Klass* receiver_klass, - bool is_optimized, - bool static_bound, - bool caller_is_nmethod, - CompiledICInfo& info, - TRAPS) { - CompiledMethod* method_code = method->code(); - - address entry = nullptr; - if (method_code != nullptr && method_code->is_in_use() && !method_code->is_unloading()) { - assert(method_code->is_compiled(), "must be compiled"); - // Call to compiled code - // - // Note: the following problem exists with Compiler1: - // - at compile time we may or may not know if the destination is final - // - if we know that the destination is final (is_optimized), we will emit - // an optimized virtual call (no inline cache), and need a Method* to make - // a call to the interpreter - // - if we don't know if the destination is final, we emit a standard - // virtual call, and use CompiledICHolder to call interpreted code - // (no static call stub has been generated) - // - In the case that we here notice the call is static bound we - // convert the call into what looks to be an optimized virtual call, - // but we must use the unverified entry point (since there will be no - // null check on a call when the target isn't loaded). - // This causes problems when verifying the IC because - // it looks vanilla but is optimized. Code in is_call_to_interpreted - // is aware of this and weakens its asserts. - if (is_optimized) { - entry = method_code->verified_entry_point(); - } else { - entry = method_code->entry_point(); - } - } - if (entry != nullptr) { - // Call to near compiled code. - info.set_compiled_entry(entry, is_optimized ? nullptr : receiver_klass, is_optimized); - } else { - if (is_optimized) { - // Use stub entry - info.set_interpreter_entry(method()->get_c2i_entry(), method()); - } else { - // Use icholder entry - assert(method_code == nullptr || method_code->is_compiled(), "must be compiled"); - CompiledICHolder* holder = new CompiledICHolder(method(), receiver_klass); - info.set_icholder_entry(method()->get_c2i_unverified_entry(), holder); - } - } - assert(info.is_optimized() == is_optimized, "must agree"); +// GC support +void CompiledIC::clean_metadata() { + data()->clean_metadata(); } +void CompiledIC::metadata_do(MetadataClosure* cl) { + data()->metadata_do(cl); +} -bool CompiledIC::is_icholder_entry(address entry) { - CodeBlob* cb = CodeCache::find_blob(entry); - if (cb == nullptr) { - return false; - } - if (cb->is_adapter_blob()) { - return true; - } else if (cb->is_vtable_blob()) { - return VtableStubs::is_icholder_entry(entry); - } - return false; +#ifndef PRODUCT +void CompiledIC::print() { + tty->print("Inline cache at " INTPTR_FORMAT ", calling " INTPTR_FORMAT " cached_value " INTPTR_FORMAT, + p2i(instruction_address()), p2i(destination()), p2i(data())); + tty->cr(); } -bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site, const CompiledMethod* cm) { - // This call site might have become stale so inspect it carefully. - address dest = cm->call_wrapper_at(call_site->addr())->destination(); - return is_icholder_entry(dest); +void CompiledIC::verify() { + _call->verify(); } +#endif // ---------------------------------------------------------------------------- -bool CompiledStaticCall::set_to_clean(bool in_use) { +void CompiledDirectCall::set_to_clean() { // in_use is unused but needed to match template function in CompiledMethod assert(CompiledICLocker::is_safe(instruction_address()), "mt unsafe call"); // Reset call site - set_destination_mt_safe(resolve_call_stub()); + RelocIterator iter((nmethod*)nullptr, instruction_address(), instruction_address() + 1); + while (iter.next()) { + switch(iter.type()) { + case relocInfo::static_call_type: + _call->set_destination_mt_safe(SharedRuntime::get_resolve_static_call_stub()); + break; + case relocInfo::opt_virtual_call_type: + _call->set_destination_mt_safe(SharedRuntime::get_resolve_opt_virtual_call_stub()); + break; + default: + ShouldNotReachHere(); + } + } + assert(is_clean(), "should be clean after cleaning"); - // Do not reset stub here: It is too expensive to call find_stub. - // Instead, rely on caller (nmethod::clear_inline_caches) to clear - // both the call and its stub. - return true; + log_debug(inlinecache)("DC@" INTPTR_FORMAT ": set to clean", p2i(_call->instruction_address())); } -bool CompiledStaticCall::is_clean() const { - return destination() == resolve_call_stub(); -} +void CompiledDirectCall::set(const methodHandle& callee_method) { + CompiledMethod* code = callee_method->code(); + CompiledMethod* caller = CodeCache::find_compiled(instruction_address()); -bool CompiledStaticCall::is_call_to_compiled() const { - return CodeCache::contains(destination()); -} + bool to_interp_cont_enter = caller->method()->is_continuation_enter_intrinsic() && + ContinuationEntry::is_interpreted_call(instruction_address()); -bool CompiledDirectStaticCall::is_call_to_interpreted() const { - // It is a call to interpreted, if it calls to a stub. Hence, the destination - // must be in the stub part of the nmethod that contains the call - CompiledMethod* cm = CodeCache::find_compiled(instruction_address()); - return cm->stub_contains(destination()); -} + bool to_compiled = !to_interp_cont_enter && code != nullptr && code->is_in_use() && !code->is_unloading(); -void CompiledStaticCall::set_to_compiled(address entry) { - { - ResourceMark rm; - log_trace(inlinecache)("%s@" INTPTR_FORMAT ": set_to_compiled " INTPTR_FORMAT, - name(), - p2i(instruction_address()), - p2i(entry)); + if (to_compiled) { + _call->set_destination_mt_safe(code->verified_entry_point()); + assert(is_call_to_compiled(), "should be compiled after set to compiled"); + } else { + // Patch call site to C2I adapter if code is deoptimized or unloaded. + // We also need to patch the static call stub to set the rmethod register + // to the callee_method so the c2i adapter knows how to build the frame + set_to_interpreted(callee_method, callee_method->get_c2i_entry()); + assert(is_call_to_interpreted(), "should be interpreted after set to interpreted"); } - // Call to compiled code - assert(CodeCache::contains(entry), "wrong entry point"); - set_destination_mt_safe(entry); + + log_trace(inlinecache)("DC@" INTPTR_FORMAT ": set to %s: %s: " INTPTR_FORMAT, + p2i(_call->instruction_address()), + to_compiled ? "compiled" : "interpreter", + callee_method->print_value_string(), + p2i(_call->destination())); } -void CompiledStaticCall::set(const StaticCallInfo& info) { - assert(CompiledICLocker::is_safe(instruction_address()), "mt unsafe call"); - // Updating a cache to the wrong entry can cause bugs that are very hard - // to track down - if cache entry gets invalid - we just clean it. In - // this way it is always the same code path that is responsible for - // updating and resolving an inline cache - assert(is_clean(), "do not update a call entry - use clean"); - - if (info._to_interpreter) { - // Call to interpreted code - set_to_interpreted(info.callee(), info.entry()); - } else { - set_to_compiled(info.entry()); - } +bool CompiledDirectCall::is_clean() const { + return destination() == SharedRuntime::get_resolve_static_call_stub() || + destination() == SharedRuntime::get_resolve_opt_virtual_call_stub(); } -// Compute settings for a CompiledStaticCall. Since we might have to set -// the stub when calling to the interpreter, we need to return arguments. -void CompiledStaticCall::compute_entry(const methodHandle& m, bool caller_is_nmethod, StaticCallInfo& info) { - CompiledMethod* m_code = m->code(); - info._callee = m; - if (m_code != nullptr && m_code->is_in_use() && !m_code->is_unloading()) { - info._to_interpreter = false; - info._entry = m_code->verified_entry_point(); - } else { - // Callee is interpreted code. In any case entering the interpreter - // puts a converter-frame on the stack to save arguments. - assert(!m->is_method_handle_intrinsic(), "Compiled code should never call interpreter MH intrinsics"); - info._to_interpreter = true; - info._entry = m()->get_c2i_entry(); - } +bool CompiledDirectCall::is_call_to_interpreted() const { + // It is a call to interpreted, if it calls to a stub. Hence, the destination + // must be in the stub part of the nmethod that contains the call + CompiledMethod* cm = CodeCache::find_compiled(instruction_address()); + return cm->stub_contains(destination()); } -void CompiledStaticCall::compute_entry_for_continuation_entry(const methodHandle& m, StaticCallInfo& info) { - if (ContinuationEntry::is_interpreted_call(instruction_address())) { - info._to_interpreter = true; - info._entry = m()->get_c2i_entry(); - } +bool CompiledDirectCall::is_call_to_compiled() const { + CompiledMethod* caller = CodeCache::find_compiled(instruction_address()); + CodeBlob* dest_cb = CodeCache::find_blob(destination()); + return !caller->stub_contains(destination()) && dest_cb->is_compiled(); } -address CompiledDirectStaticCall::find_stub_for(address instruction) { +address CompiledDirectCall::find_stub_for(address instruction) { // Find reloc. information containing this call-site RelocIterator iter((nmethod*)nullptr, instruction); while (iter.next()) { @@ -673,8 +399,6 @@ address CompiledDirectStaticCall::find_stub_for(address instruction) { // from the CompiledIC implementation case relocInfo::opt_virtual_call_type: return iter.opt_virtual_call_reloc()->static_stub(); - case relocInfo::poll_type: - case relocInfo::poll_return_type: // A safepoint can't overlap a call. default: ShouldNotReachHere(); } @@ -683,36 +407,13 @@ address CompiledDirectStaticCall::find_stub_for(address instruction) { return nullptr; } -address CompiledDirectStaticCall::find_stub() { - return CompiledDirectStaticCall::find_stub_for(instruction_address()); +address CompiledDirectCall::find_stub() { + return find_stub_for(instruction_address()); } -address CompiledDirectStaticCall::resolve_call_stub() const { - return SharedRuntime::get_resolve_static_call_stub(); -} - -//----------------------------------------------------------------------------- -// Non-product mode code #ifndef PRODUCT - -void CompiledIC::verify() { - _call->verify(); - assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted() - || is_optimized() || is_megamorphic(), "sanity check"); -} - -void CompiledIC::print() { - print_compiled_ic(); - tty->cr(); -} - -void CompiledIC::print_compiled_ic() { - tty->print("Inline cache at " INTPTR_FORMAT ", calling %s " INTPTR_FORMAT " cached_value " INTPTR_FORMAT, - p2i(instruction_address()), is_call_to_interpreted() ? "interpreted " : "", p2i(ic_destination()), p2i(is_optimized() ? nullptr : cached_value())); -} - -void CompiledDirectStaticCall::print() { - tty->print("static call at " INTPTR_FORMAT " -> ", p2i(instruction_address())); +void CompiledDirectCall::print() { + tty->print("direct call at " INTPTR_FORMAT " to " INTPTR_FORMAT " -> ", p2i(instruction_address()), p2i(destination())); if (is_clean()) { tty->print("clean"); } else if (is_call_to_compiled()) { @@ -723,9 +424,10 @@ void CompiledDirectStaticCall::print() { tty->cr(); } -void CompiledDirectStaticCall::verify_mt_safe(const methodHandle& callee, address entry, - NativeMovConstReg* method_holder, - NativeJump* jump) { +void CompiledDirectCall::verify_mt_safe(const methodHandle& callee, address entry, + NativeMovConstReg* method_holder, + NativeJump* jump) { + _call->verify(); // A generated lambda form might be deleted from the Lambdaform // cache in MethodTypeForm. If a jit compiled lambdaform method // becomes not entrant and the cache access returns null, the new @@ -743,4 +445,4 @@ void CompiledDirectStaticCall::verify_mt_safe(const methodHandle& callee, addres || old_method->is_old(), // may be race patching deoptimized nmethod due to redefinition. "b) MT-unsafe modification of inline cache"); } -#endif // !PRODUCT +#endif diff --git a/src/hotspot/share/code/compiledIC.hpp b/src/hotspot/share/code/compiledIC.hpp index 17586fc57a0..321bf280ed4 100644 --- a/src/hotspot/share/code/compiledIC.hpp +++ b/src/hotspot/share/code/compiledIC.hpp @@ -27,42 +27,19 @@ #include "code/nativeInst.hpp" #include "interpreter/linkResolver.hpp" -#include "oops/compiledICHolder.hpp" #include "runtime/safepointVerifiers.hpp" //----------------------------------------------------------------------------- // The CompiledIC represents a compiled inline cache. // -// In order to make patching of the inline cache MT-safe, we only allow the following -// transitions (when not at a safepoint): -// -// -// [1] --<-- Clean -->--- [1] -// / (null) \ -// / \ /-<-\ -// / [2] \ / \ -// Interpreted ---------> Monomorphic | [3] -// (CompiledICHolder*) (Klass*) | -// \ / \ / -// [4] \ / [4] \->-/ -// \->- Megamorphic -<-/ -// (CompiledICHolder*) -// -// The text in parentheses () refers to the value of the inline cache receiver (mov instruction) -// -// The numbers in square brackets refer to the kind of transition: -// [1]: Initial fixup. Receiver it found from debug information -// [2]: Compilation of a method -// [3]: Recompilation of a method (note: only entry is changed. The Klass* must stay the same) -// [4]: Inline cache miss. We go directly to megamorphic call. -// -// The class automatically inserts transition stubs (using the InlineCacheBuffer) when an MT-unsafe -// transition is made to a stub. +// It's safe to transition from any state to any state. Typically an inline cache starts +// in the clean state, meaning it will resolve the call when called. Then it typically +// transitions to monomorphic, assuming the first dynamic receiver will be the only one +// observed. If that speculation fails, we transition to megamorphic. // class CompiledIC; class CompiledICProtectionBehaviour; class CompiledMethod; -class ICStub; class CompiledICLocker: public StackObj { CompiledMethod* _method; @@ -77,237 +54,105 @@ class CompiledICLocker: public StackObj { static bool is_safe(address code); }; -class CompiledICInfo : public StackObj { - private: - address _entry; // entry point for call - void* _cached_value; // Value of cached_value (either in stub or inline cache) - bool _is_icholder; // Is the cached value a CompiledICHolder* - bool _is_optimized; // it is an optimized virtual call (i.e., can be statically bound) - bool _to_interpreter; // Call it to interpreter - bool _release_icholder; +// A CompiledICData is a helper object for the inline cache implementation. +// It comprises: +// (1) The first receiver klass and its selected method +// (2) Itable call metadata + +class CompiledICData : public CHeapObj { + friend class VMStructs; + friend class JVMCIVMStructs; + + Method* volatile _speculated_method; + uintptr_t volatile _speculated_klass; + Klass* _itable_defc_klass; + Klass* _itable_refc_klass; + bool _is_initialized; + + bool is_speculated_klass_unloaded() const; + public: - address entry() const { return _entry; } - Metadata* cached_metadata() const { assert(!_is_icholder, ""); return (Metadata*)_cached_value; } - CompiledICHolder* claim_cached_icholder() { - assert(_is_icholder, ""); - assert(_cached_value != nullptr, "must be non-null"); - _release_icholder = false; - CompiledICHolder* icholder = (CompiledICHolder*)_cached_value; - icholder->claim(); - return icholder; - } - bool is_optimized() const { return _is_optimized; } - bool to_interpreter() const { return _to_interpreter; } - - void set_compiled_entry(address entry, Klass* klass, bool is_optimized) { - _entry = entry; - _cached_value = (void*)klass; - _to_interpreter = false; - _is_icholder = false; - _is_optimized = is_optimized; - _release_icholder = false; - } + // Constructor + CompiledICData(); - void set_interpreter_entry(address entry, Method* method) { - _entry = entry; - _cached_value = (void*)method; - _to_interpreter = true; - _is_icholder = false; - _is_optimized = true; - _release_icholder = false; - } + // accessors + Klass* speculated_klass() const; + Method* speculated_method() const { return _speculated_method; } + Klass* itable_defc_klass() const { return _itable_defc_klass; } + Klass* itable_refc_klass() const { return _itable_refc_klass; } - void set_icholder_entry(address entry, CompiledICHolder* icholder) { - _entry = entry; - _cached_value = (void*)icholder; - _to_interpreter = true; - _is_icholder = true; - _is_optimized = false; - _release_icholder = true; - } + static ByteSize speculated_method_offset() { return byte_offset_of(CompiledICData, _speculated_method); } + static ByteSize speculated_klass_offset() { return byte_offset_of(CompiledICData, _speculated_klass); } - CompiledICInfo(): _entry(nullptr), _cached_value(nullptr), _is_icholder(false), - _is_optimized(false), _to_interpreter(false), _release_icholder(false) { - } - ~CompiledICInfo() { - // In rare cases the info is computed but not used, so release any - // CompiledICHolder* that was created - if (_release_icholder) { - assert(_is_icholder, "must be"); - CompiledICHolder* icholder = (CompiledICHolder*)_cached_value; - icholder->claim(); - delete icholder; - } - } -}; + static ByteSize itable_defc_klass_offset() { return byte_offset_of(CompiledICData, _itable_defc_klass); } + static ByteSize itable_refc_klass_offset() { return byte_offset_of(CompiledICData, _itable_refc_klass); } -class NativeCallWrapper: public ResourceObj { -public: - virtual address destination() const = 0; - virtual address instruction_address() const = 0; - virtual address next_instruction_address() const = 0; - virtual address return_address() const = 0; - virtual address get_resolve_call_stub(bool is_optimized) const = 0; - virtual void set_destination_mt_safe(address dest) = 0; - virtual void set_to_interpreted(const methodHandle& method, CompiledICInfo& info) = 0; - virtual void verify() const = 0; - virtual void verify_resolve_call(address dest) const = 0; - - virtual bool is_call_to_interpreted(address dest) const = 0; - virtual bool is_safe_for_patching() const = 0; - - virtual NativeInstruction* get_load_instruction(virtual_call_Relocation* r) const = 0; - - virtual void *get_data(NativeInstruction* instruction) const = 0; - virtual void set_data(NativeInstruction* instruction, intptr_t data) = 0; + void initialize(CallInfo* call_info, Klass* receiver_klass); + + bool is_initialized() const { return _is_initialized; } + + // GC Support + void clean_metadata(); + void metadata_do(MetadataClosure* cl); }; class CompiledIC: public ResourceObj { - friend class InlineCacheBuffer; - friend class ICStub; - - private: - NativeCallWrapper* _call; - NativeInstruction* _value; // patchable value cell for this IC - bool _is_optimized; // an optimized virtual call (i.e., no compiled IC) +private: CompiledMethod* _method; + CompiledICData* _data; + NativeCall* _call; - CompiledIC(CompiledMethod* cm, NativeCall* ic_call); CompiledIC(RelocIterator* iter); - void initialize_from_iter(RelocIterator* iter); + // CompiledICData wrappers + void ensure_initialized(CallInfo* call_info, Klass* receiver_klass); + bool is_speculated_klass(Klass* receiver_klass); - static bool is_icholder_entry(address entry); + // Inline cache states + void set_to_monomorphic(); + void set_to_megamorphic(CallInfo* call_info); - // low-level inline-cache manipulation. Cannot be accessed directly, since it might not be MT-safe - // to change an inline-cache. These changes the underlying inline-cache directly. They *newer* make - // changes to a transition stub. - void internal_set_ic_destination(address entry_point, bool is_icstub, void* cache, bool is_icholder); - void set_ic_destination(ICStub* stub); - void set_ic_destination(address entry_point) { - assert(_is_optimized, "use set_ic_destination_and_value instead"); - internal_set_ic_destination(entry_point, false, nullptr, false); - } - // This only for use by ICStubs where the type of the value isn't known - void set_ic_destination_and_value(address entry_point, void* value) { - internal_set_ic_destination(entry_point, false, value, is_icholder_entry(entry_point)); - } - void set_ic_destination_and_value(address entry_point, Metadata* value) { - internal_set_ic_destination(entry_point, false, value, false); - } - void set_ic_destination_and_value(address entry_point, CompiledICHolder* value) { - internal_set_ic_destination(entry_point, false, value, true); - } - - // Reads the location of the transition stub. This will fail with an assertion, if no transition stub is - // associated with the inline cache. - address stub_address() const; - bool is_in_transition_state() const; // Use InlineCacheBuffer - - public: +public: // conversion (machine PC to CompiledIC*) friend CompiledIC* CompiledIC_before(CompiledMethod* nm, address return_addr); friend CompiledIC* CompiledIC_at(CompiledMethod* nm, address call_site); friend CompiledIC* CompiledIC_at(Relocation* call_site); friend CompiledIC* CompiledIC_at(RelocIterator* reloc_iter); - static bool is_icholder_call_site(virtual_call_Relocation* call_site, const CompiledMethod* cm); - - // Return the cached_metadata/destination associated with this inline cache. If the cache currently points - // to a transition stub, it will read the values from the transition stub. - void* cached_value() const; - CompiledICHolder* cached_icholder() const { - assert(is_icholder_call(), "must be"); - return (CompiledICHolder*) cached_value(); - } - Metadata* cached_metadata() const { - assert(!is_icholder_call(), "must be"); - return (Metadata*) cached_value(); - } - - void* get_data() const { - return _call->get_data(_value); - } - - void set_data(intptr_t data) { - _call->set_data(_value, data); - } - - address ic_destination() const; - - bool is_optimized() const { return _is_optimized; } + CompiledICData* data() const; // State - bool is_clean() const; + bool is_clean() const; + bool is_monomorphic() const; bool is_megamorphic() const; - bool is_call_to_compiled() const; - bool is_call_to_interpreted() const; - - bool is_icholder_call() const; - address end_of_call() const { return _call->return_address(); } + address end_of_call() const { return _call->return_address(); } - // MT-safe patching of inline caches. Note: Only safe to call is_xxx when holding the CompiledIC_ock + // MT-safe patching of inline caches. Note: Only safe to call is_xxx when holding the CompiledICLocker // so you are guaranteed that no patching takes place. The same goes for verify. - // - // Note: We do not provide any direct access to the stub code, to prevent parts of the code - // to manipulate the inline cache in MT-unsafe ways. - // - // They all takes a TRAP argument, since they can cause a GC if the inline-cache buffer is full. - // - bool set_to_clean(bool in_use = true); - bool set_to_monomorphic(CompiledICInfo& info); - void clear_ic_stub(); - - // Returns true if successful and false otherwise. The call can fail if memory - // allocation in the code cache fails, or ic stub refill is required. - bool set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecode, bool& needs_ic_stub_refill, TRAPS); - - static void compute_monomorphic_entry(const methodHandle& method, Klass* receiver_klass, - bool is_optimized, bool static_bound, bool caller_is_nmethod, - CompiledICInfo& info, TRAPS); + void set_to_clean(); + void update(CallInfo* call_info, Klass* receiver_klass); + + // GC support + void clean_metadata(); + void metadata_do(MetadataClosure* cl); // Location address instruction_address() const { return _call->instruction_address(); } + address destination() const { return _call->destination(); } // Misc void print() PRODUCT_RETURN; - void print_compiled_ic() PRODUCT_RETURN; void verify() PRODUCT_RETURN; }; -inline CompiledIC* CompiledIC_before(CompiledMethod* nm, address return_addr) { - CompiledIC* c_ic = new CompiledIC(nm, nativeCall_before(return_addr)); - c_ic->verify(); - return c_ic; -} - -inline CompiledIC* CompiledIC_at(CompiledMethod* nm, address call_site) { - CompiledIC* c_ic = new CompiledIC(nm, nativeCall_at(call_site)); - c_ic->verify(); - return c_ic; -} - -inline CompiledIC* CompiledIC_at(Relocation* call_site) { - assert(call_site->type() == relocInfo::virtual_call_type || - call_site->type() == relocInfo::opt_virtual_call_type, "wrong reloc. info"); - CompiledIC* c_ic = new CompiledIC(call_site->code(), nativeCall_at(call_site->addr())); - c_ic->verify(); - return c_ic; -} - -inline CompiledIC* CompiledIC_at(RelocIterator* reloc_iter) { - assert(reloc_iter->type() == relocInfo::virtual_call_type || - reloc_iter->type() == relocInfo::opt_virtual_call_type, "wrong reloc. info"); - CompiledIC* c_ic = new CompiledIC(reloc_iter); - c_ic->verify(); - return c_ic; -} +CompiledIC* CompiledIC_before(CompiledMethod* nm, address return_addr); +CompiledIC* CompiledIC_at(CompiledMethod* nm, address call_site); +CompiledIC* CompiledIC_at(Relocation* call_site); +CompiledIC* CompiledIC_at(RelocIterator* reloc_iter); //----------------------------------------------------------------------------- -// The CompiledStaticCall represents a call to a static method in the compiled -// -// Transition diagram of a static call site is somewhat simpler than for an inlined cache: +// The CompiledDirectCall represents a call to a method in the compiled code // // // -----<----- Clean ----->----- @@ -321,63 +166,7 @@ inline CompiledIC* CompiledIC_at(RelocIterator* reloc_iter) { // // -class StaticCallInfo { - private: - address _entry; // Entrypoint - methodHandle _callee; // Callee (used when calling interpreter) - bool _to_interpreter; // call to interpreted method (otherwise compiled) - - friend class CompiledStaticCall; - friend class CompiledDirectStaticCall; - friend class CompiledPltStaticCall; - public: - address entry() const { return _entry; } - methodHandle callee() const { return _callee; } -}; - -class CompiledStaticCall : public ResourceObj { - public: - // Code - - // Returns null if CodeBuffer::expand fails - static address emit_to_interp_stub(CodeBuffer &cbuf, address mark = nullptr); - static int to_interp_stub_size(); - static int to_trampoline_stub_size(); - static int reloc_to_interp_stub(); - - // Compute entry point given a method - static void compute_entry(const methodHandle& m, bool caller_is_nmethod, StaticCallInfo& info); - void compute_entry_for_continuation_entry(const methodHandle& m, StaticCallInfo& info); - -public: - // Clean static call (will force resolving on next use) - virtual address destination() const = 0; - - // Clean static call (will force resolving on next use) - bool set_to_clean(bool in_use = true); - - // Set state. The entry must be the same, as computed by compute_entry. - // Computation and setting is split up, since the actions are separate during - // a OptoRuntime::resolve_xxx. - void set(const StaticCallInfo& info); - - // State - bool is_clean() const; - bool is_call_to_compiled() const; - virtual bool is_call_to_interpreted() const = 0; - - virtual address instruction_address() const = 0; - virtual address end_of_call() const = 0; -protected: - virtual address resolve_call_stub() const = 0; - virtual void set_destination_mt_safe(address dest) = 0; - virtual void set_to_interpreted(const methodHandle& callee, address entry) = 0; - virtual const char* name() const = 0; - - void set_to_compiled(address entry); -}; - -class CompiledDirectStaticCall : public CompiledStaticCall { +class CompiledDirectCall : public ResourceObj { private: friend class CompiledIC; friend class DirectNativeCallWrapper; @@ -392,22 +181,28 @@ class CompiledDirectStaticCall : public CompiledStaticCall { NativeCall* _call; - CompiledDirectStaticCall(NativeCall* call) : _call(call) {} + CompiledDirectCall(NativeCall* call) : _call(call) {} public: - static inline CompiledDirectStaticCall* before(address return_addr) { - CompiledDirectStaticCall* st = new CompiledDirectStaticCall(nativeCall_before(return_addr)); + // Returns null if CodeBuffer::expand fails + static address emit_to_interp_stub(CodeBuffer &cbuf, address mark = nullptr); + static int to_interp_stub_size(); + static int to_trampoline_stub_size(); + static int reloc_to_interp_stub(); + + static inline CompiledDirectCall* before(address return_addr) { + CompiledDirectCall* st = new CompiledDirectCall(nativeCall_before(return_addr)); st->verify(); return st; } - static inline CompiledDirectStaticCall* at(address native_call) { - CompiledDirectStaticCall* st = new CompiledDirectStaticCall(nativeCall_at(native_call)); + static inline CompiledDirectCall* at(address native_call) { + CompiledDirectCall* st = new CompiledDirectCall(nativeCall_at(native_call)); st->verify(); return st; } - static inline CompiledDirectStaticCall* at(Relocation* call_site) { + static inline CompiledDirectCall* at(Relocation* call_site) { return at(call_site->addr()); } @@ -415,8 +210,15 @@ class CompiledDirectStaticCall : public CompiledStaticCall { address destination() const { return _call->destination(); } address end_of_call() const { return _call->return_address(); } + // Clean static call (will force resolving on next use) + void set_to_clean(); + + void set(const methodHandle& callee_method); + // State - virtual bool is_call_to_interpreted() const; + bool is_clean() const; + bool is_call_to_interpreted() const; + bool is_call_to_compiled() const; // Stub support static address find_stub_for(address instruction); @@ -426,10 +228,6 @@ class CompiledDirectStaticCall : public CompiledStaticCall { // Misc. void print() PRODUCT_RETURN; void verify() PRODUCT_RETURN; - - protected: - virtual address resolve_call_stub() const; - virtual const char* name() const { return "CompiledDirectStaticCall"; } }; #endif // SHARE_CODE_COMPILEDIC_HPP diff --git a/src/hotspot/share/code/compiledMethod.cpp b/src/hotspot/share/code/compiledMethod.cpp index 30b4e3617d6..6553d6f7934 100644 --- a/src/hotspot/share/code/compiledMethod.cpp +++ b/src/hotspot/share/code/compiledMethod.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ #include "code/exceptionHandlerTable.hpp" #include "code/scopeDesc.hpp" #include "code/codeCache.hpp" -#include "code/icBuffer.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/gcBehaviours.hpp" @@ -36,7 +35,6 @@ #include "logging/log.hpp" #include "logging/logTag.hpp" #include "memory/resourceArea.hpp" -#include "oops/compiledICHolder.inline.hpp" #include "oops/klass.inline.hpp" #include "oops/methodData.hpp" #include "oops/method.inline.hpp" @@ -335,28 +333,6 @@ address CompiledMethod::oops_reloc_begin() const { return low_boundary; } -int CompiledMethod::verify_icholder_relocations() { - ResourceMark rm; - int count = 0; - - RelocIterator iter(this); - while(iter.next()) { - if (iter.type() == relocInfo::virtual_call_type) { - if (CompiledIC::is_icholder_call_site(iter.virtual_call_reloc(), this)) { - CompiledIC *ic = CompiledIC_at(&iter); - if (TraceCompiledIC) { - tty->print("noticed icholder " INTPTR_FORMAT " ", p2i(ic->cached_icholder())); - ic->print(); - } - assert(ic->cached_icholder() != nullptr, "must be non-nullptr"); - count++; - } - } - } - - return count; -} - // Method that knows how to preserve outgoing arguments at call. This method must be // called with a frame corresponding to a Java invoke void CompiledMethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { @@ -431,20 +407,6 @@ void CompiledMethod::clear_inline_caches() { } } -// Clear IC callsites, releasing ICStubs of all compiled ICs -// as well as any associated CompiledICHolders. -void CompiledMethod::clear_ic_callsites() { - assert(CompiledICLocker::is_safe(this), "mt unsafe call"); - ResourceMark rm; - RelocIterator iter(this); - while(iter.next()) { - if (iter.type() == relocInfo::virtual_call_type) { - CompiledIC* ic = CompiledIC_at(&iter); - ic->set_to_clean(false); - } - } -} - #ifdef ASSERT // Check class_loader is alive for this bit of metadata. class CheckClass : public MetadataClosure { @@ -466,70 +428,22 @@ class CheckClass : public MetadataClosure { #endif // ASSERT -bool CompiledMethod::clean_ic_if_metadata_is_dead(CompiledIC *ic) { - if (ic->is_clean()) { - return true; - } - if (ic->is_icholder_call()) { - // The only exception is compiledICHolder metadata which may - // yet be marked below. (We check this further below). - CompiledICHolder* cichk_metdata = ic->cached_icholder(); - - if (cichk_metdata->is_loader_alive()) { - return true; - } - } else { - Metadata* ic_metdata = ic->cached_metadata(); - if (ic_metdata != nullptr) { - if (ic_metdata->is_klass()) { - if (((Klass*)ic_metdata)->is_loader_alive()) { - return true; - } - } else if (ic_metdata->is_method()) { - Method* method = (Method*)ic_metdata; - assert(!method->is_old(), "old method should have been cleaned"); - if (method->method_holder()->is_loader_alive()) { - return true; - } - } else { - ShouldNotReachHere(); - } - } else { - // This inline cache is a megamorphic vtable call. Those ICs never hold - // any Metadata and should therefore never be cleaned by this function. - return true; - } - } - - return ic->set_to_clean(); +static void clean_ic_if_metadata_is_dead(CompiledIC *ic) { + ic->clean_metadata(); } // Clean references to unloaded nmethods at addr from this one, which is not unloaded. -template -static bool clean_if_nmethod_is_unloaded(CompiledICorStaticCall *ic, address addr, CompiledMethod* from, +template +static void clean_if_nmethod_is_unloaded(CallsiteT* callsite, CompiledMethod* from, bool clean_all) { - CodeBlob *cb = CodeCache::find_blob(addr); - CompiledMethod* nm = (cb != nullptr) ? cb->as_compiled_method_or_null() : nullptr; - if (nm != nullptr) { - // Clean inline caches pointing to bad nmethods - if (clean_all || !nm->is_in_use() || nm->is_unloading() || (nm->method()->code() != nm)) { - if (!ic->set_to_clean(!from->is_unloading())) { - return false; - } - assert(ic->is_clean(), "nmethod " PTR_FORMAT "not clean %s", p2i(from), from->method()->name_and_sig_as_C_string()); - } + CodeBlob* cb = CodeCache::find_blob(callsite->destination()); + if (!cb->is_compiled()) { + return; + } + CompiledMethod* cm = cb->as_compiled_method(); + if (clean_all || !cm->is_in_use() || cm->is_unloading() || cm->method()->code() != cm) { + callsite->set_to_clean(); } - return true; -} - -static bool clean_if_nmethod_is_unloaded(CompiledIC *ic, CompiledMethod* from, - bool clean_all) { - return clean_if_nmethod_is_unloaded(ic, ic->ic_destination(), from, clean_all); -} - -static bool clean_if_nmethod_is_unloaded(CompiledStaticCall *csc, CompiledMethod* from, - bool clean_all) { - return clean_if_nmethod_is_unloaded(csc, csc->destination(), from, clean_all); } // Cleans caches in nmethods that point to either classes that are unloaded @@ -539,7 +453,7 @@ static bool clean_if_nmethod_is_unloaded(CompiledStaticCall *csc, CompiledMethod // nmethods are unloaded. Return postponed=true in the parallel case for // inline caches found that point to nmethods that are not yet visited during // the do_unloading walk. -bool CompiledMethod::unload_nmethod_caches(bool unloading_occurred) { +void CompiledMethod::unload_nmethod_caches(bool unloading_occurred) { ResourceMark rm; // Exception cache only needs to be called if unloading occurred @@ -547,16 +461,13 @@ bool CompiledMethod::unload_nmethod_caches(bool unloading_occurred) { clean_exception_cache(); } - if (!cleanup_inline_caches_impl(unloading_occurred, false)) { - return false; - } + cleanup_inline_caches_impl(unloading_occurred, false); #ifdef ASSERT // Check that the metadata embedded in the nmethod is alive CheckClass check_class; metadata_do(&check_class); #endif - return true; } void CompiledMethod::run_nmethod_entry_barrier() { @@ -578,8 +489,7 @@ void CompiledMethod::run_nmethod_entry_barrier() { void CompiledMethod::cleanup_inline_caches_whitebox() { assert_locked_or_safepoint(CodeCache_lock); CompiledICLocker ic_locker(this); - guarantee(cleanup_inline_caches_impl(false /* unloading_occurred */, true /* clean_all */), - "Inline cache cleaning in a safepoint can't fail"); + cleanup_inline_caches_impl(false /* unloading_occurred */, true /* clean_all */); } address* CompiledMethod::orig_pc_addr(const frame* fr) { @@ -587,7 +497,7 @@ address* CompiledMethod::orig_pc_addr(const frame* fr) { } // Called to clean up after class unloading for live nmethods -bool CompiledMethod::cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all) { +void CompiledMethod::cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all) { assert(CompiledICLocker::is_safe(this), "mt unsafe call"); ResourceMark rm; @@ -602,26 +512,15 @@ bool CompiledMethod::cleanup_inline_caches_impl(bool unloading_occurred, bool cl if (unloading_occurred) { // If class unloading occurred we first clear ICs where the cached metadata // is referring to an unloaded klass or method. - if (!clean_ic_if_metadata_is_dead(CompiledIC_at(&iter))) { - return false; - } + clean_ic_if_metadata_is_dead(CompiledIC_at(&iter)); } - if (!clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this, clean_all)) { - return false; - } + clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this, clean_all); break; case relocInfo::opt_virtual_call_type: - if (!clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this, clean_all)) { - return false; - } - break; - case relocInfo::static_call_type: - if (!clean_if_nmethod_is_unloaded(compiledStaticCall_at(iter.reloc()), this, clean_all)) { - return false; - } + clean_if_nmethod_is_unloaded(CompiledDirectCall::at(iter.reloc()), this, clean_all); break; case relocInfo::static_stub_type: { @@ -672,8 +571,6 @@ bool CompiledMethod::cleanup_inline_caches_impl(bool unloading_occurred, bool cl break; } } - - return true; } address CompiledMethod::continuation_for_implicit_exception(address pc, bool for_div0_check) { @@ -687,12 +584,15 @@ address CompiledMethod::continuation_for_implicit_exception(address pc, bool for ResourceMark rm(thread); CodeBlob* cb = CodeCache::find_blob(pc); assert(cb != nullptr && cb == this, ""); - ttyLocker ttyl; - tty->print_cr("implicit exception happened at " INTPTR_FORMAT, p2i(pc)); - print(); - method()->print_codes(); - print_code(); - print_pcs(); + + // Keep tty output consistent. To avoid ttyLocker, we buffer in stream, and print all at once. + stringStream ss; + ss.print_cr("implicit exception happened at " INTPTR_FORMAT, p2i(pc)); + print_on(&ss); + method()->print_codes_on(&ss); + print_code_on(&ss); + print_pcs_on(&ss); + tty->print("%s", ss.as_string()); // print all at once } #endif if (cont_offset == 0) { diff --git a/src/hotspot/share/code/compiledMethod.hpp b/src/hotspot/share/code/compiledMethod.hpp index 6973911c063..42d68bda554 100644 --- a/src/hotspot/share/code/compiledMethod.hpp +++ b/src/hotspot/share/code/compiledMethod.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ class ExceptionHandlerTable; class ImplicitExceptionTable; class AbstractCompiler; class xmlStream; -class CompiledStaticCall; +class CompiledDirectCall; class NativeCallWrapper; class ScopeDesc; class CompiledIC; @@ -227,7 +227,7 @@ class CompiledMethod : public CodeBlob { virtual bool is_osr_method() const = 0; virtual int osr_entry_bci() const = 0; Method* method() const { return _method; } - virtual void print_pcs() = 0; + virtual void print_pcs_on(outputStream* st) = 0; bool is_native_method() const { return _method != nullptr && _method->is_native(); } bool is_java_method() const { return _method != nullptr && !_method->is_native(); } @@ -364,7 +364,7 @@ class CompiledMethod : public CodeBlob { // Inline cache support for class unloading and nmethod unloading private: - bool cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all); + void cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all); address continuation_for_implicit_exception(address pc, bool for_div0_check); @@ -373,13 +373,10 @@ class CompiledMethod : public CodeBlob { void cleanup_inline_caches_whitebox(); virtual void clear_inline_caches(); - void clear_ic_callsites(); // Execute nmethod barrier code, as if entering through nmethod call. void run_nmethod_entry_barrier(); - // Verify and count cached icholder relocations. - int verify_icholder_relocations(); void verify_oop_relocations(); bool has_evol_metadata(); @@ -389,14 +386,8 @@ class CompiledMethod : public CodeBlob { // corresponds to the given method as well. virtual bool is_dependent_on_method(Method* dependee) = 0; - virtual NativeCallWrapper* call_wrapper_at(address call) const = 0; - virtual NativeCallWrapper* call_wrapper_before(address return_pc) const = 0; virtual address call_instruction_address(address pc) const = 0; - virtual CompiledStaticCall* compiledStaticCall_at(Relocation* call_site) const = 0; - virtual CompiledStaticCall* compiledStaticCall_at(address addr) const = 0; - virtual CompiledStaticCall* compiledStaticCall_before(address addr) const = 0; - Method* attached_method(address call_pc); Method* attached_method_before_pc(address pc); @@ -406,16 +397,13 @@ class CompiledMethod : public CodeBlob { protected: address oops_reloc_begin() const; - private: - bool static clean_ic_if_metadata_is_dead(CompiledIC *ic); - public: // GC unloading support // Cleans unloaded klasses and unloaded nmethods in inline caches virtual bool is_unloading() = 0; - bool unload_nmethod_caches(bool class_unloading_occurred); + void unload_nmethod_caches(bool class_unloading_occurred); virtual void do_unloading(bool unloading_occurred) = 0; private: diff --git a/src/hotspot/share/code/icBuffer.cpp b/src/hotspot/share/code/icBuffer.cpp deleted file mode 100644 index ec489eff9c8..00000000000 --- a/src/hotspot/share/code/icBuffer.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "code/codeCache.hpp" -#include "code/compiledIC.hpp" -#include "code/icBuffer.hpp" -#include "code/nmethod.hpp" -#include "code/scopeDesc.hpp" -#include "gc/shared/collectedHeap.inline.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/linkResolver.hpp" -#include "memory/resourceArea.hpp" -#include "oops/method.hpp" -#include "oops/oop.inline.hpp" -#include "runtime/atomic.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/javaThread.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/vmOperations.hpp" - -DEF_STUB_INTERFACE(ICStub); - -StubQueue* InlineCacheBuffer::_buffer = nullptr; - -CompiledICHolder* volatile InlineCacheBuffer::_pending_released = nullptr; -volatile int InlineCacheBuffer::_pending_count = 0; - -#ifdef ASSERT -ICRefillVerifier::ICRefillVerifier() - : _refill_requested(false), - _refill_remembered(false) -{ - Thread* thread = Thread::current(); - assert(thread->missed_ic_stub_refill_verifier() == nullptr, "nesting not supported"); - thread->set_missed_ic_stub_refill_verifier(this); -} - -ICRefillVerifier::~ICRefillVerifier() { - assert(!_refill_requested || _refill_remembered, - "Forgot to refill IC stubs after failed IC transition"); - Thread::current()->set_missed_ic_stub_refill_verifier(nullptr); -} - -ICRefillVerifierMark::ICRefillVerifierMark(ICRefillVerifier* verifier) { - Thread* thread = Thread::current(); - assert(thread->missed_ic_stub_refill_verifier() == nullptr, "nesting not supported"); - thread->set_missed_ic_stub_refill_verifier(verifier); -} - -ICRefillVerifierMark::~ICRefillVerifierMark() { - Thread::current()->set_missed_ic_stub_refill_verifier(nullptr); -} - -static ICRefillVerifier* current_ic_refill_verifier() { - Thread* current = Thread::current(); - ICRefillVerifier* verifier = current->missed_ic_stub_refill_verifier(); - assert(verifier != nullptr, "need a verifier for safety"); - return verifier; -} -#endif - -void ICStub::finalize() { - if (!is_empty()) { - ResourceMark rm; - CompiledIC *ic = CompiledIC_at(CodeCache::find_compiled(ic_site()), ic_site()); - assert(CodeCache::find_compiled(ic->instruction_address()) != nullptr, "inline cache in non-compiled?"); - - assert(this == ICStub::from_destination_address(ic->stub_address()), "wrong owner of ic buffer"); - ic->set_ic_destination_and_value(destination(), cached_value()); - } -} - - -address ICStub::destination() const { - return InlineCacheBuffer::ic_buffer_entry_point(code_begin()); -} - -void* ICStub::cached_value() const { - return InlineCacheBuffer::ic_buffer_cached_value(code_begin()); -} - - -void ICStub::set_stub(CompiledIC *ic, void* cached_val, address dest_addr) { - // We cannot store a pointer to the 'ic' object, since it is resource allocated. Instead we - // store the location of the inline cache. Then we have enough information recreate the CompiledIC - // object when we need to remove the stub. - _ic_site = ic->instruction_address(); - - // Assemble new stub - InlineCacheBuffer::assemble_ic_buffer_code(code_begin(), cached_val, dest_addr); - assert(destination() == dest_addr, "can recover destination"); - assert(cached_value() == cached_val, "can recover destination"); -} - - -void ICStub::clear() { - if (CompiledIC::is_icholder_entry(destination())) { - InlineCacheBuffer::queue_for_release((CompiledICHolder*)cached_value()); - } - _ic_site = nullptr; -} - - -#ifndef PRODUCT -// anybody calling to this stub will trap - -void ICStub::verify() { -} - -void ICStub::print() { - tty->print_cr("ICStub: site: " INTPTR_FORMAT, p2i(_ic_site)); -} -#endif - -//----------------------------------------------------------------------------------------------- -// Implementation of InlineCacheBuffer - - -void InlineCacheBuffer::initialize() { - if (_buffer != nullptr) return; // already initialized - _buffer = new StubQueue(new ICStubInterface, checked_cast(InlineCacheBufferSize), InlineCacheBuffer_lock, "InlineCacheBuffer"); - assert (_buffer != nullptr, "cannot allocate InlineCacheBuffer"); -} - - -void InlineCacheBuffer::refill_ic_stubs() { -#ifdef ASSERT - ICRefillVerifier* verifier = current_ic_refill_verifier(); - verifier->request_remembered(); -#endif - // we ran out of inline cache buffer space; must enter safepoint. - // We do this by forcing a safepoint - VM_ICBufferFull ibf; - VMThread::execute(&ibf); -} - -bool InlineCacheBuffer::needs_update_inline_caches() { - // Stub removal - if (buffer()->number_of_stubs() > 0) { - return true; - } - - // Release pending CompiledICHolder - if (pending_icholder_count() > 0) { - return true; - } - - return false; -} - -void InlineCacheBuffer::update_inline_caches() { - if (buffer()->number_of_stubs() > 0) { - if (TraceICBuffer) { - tty->print_cr("[updating inline caches with %d stubs]", buffer()->number_of_stubs()); - } - buffer()->remove_all(); - } - release_pending_icholders(); -} - - -bool InlineCacheBuffer::contains(address instruction_address) { - return buffer()->contains(instruction_address); -} - - -bool InlineCacheBuffer::is_empty() { - return buffer()->number_of_stubs() == 0; -} - - -void InlineCacheBuffer_init() { - InlineCacheBuffer::initialize(); -} - -bool InlineCacheBuffer::create_transition_stub(CompiledIC *ic, void* cached_value, address entry) { - assert(!SafepointSynchronize::is_at_safepoint(), "should not be called during a safepoint"); - assert(CompiledICLocker::is_safe(ic->instruction_address()), "mt unsafe call"); - if (TraceICBuffer) { - tty->print_cr(" create transition stub for " INTPTR_FORMAT " destination " INTPTR_FORMAT " cached value " INTPTR_FORMAT, - p2i(ic->instruction_address()), p2i(entry), p2i(cached_value)); - } - - // allocate and initialize new "out-of-line" inline-cache - ICStub* ic_stub = (ICStub*) buffer()->request_committed(ic_stub_code_size()); - if (ic_stub == nullptr) { -#ifdef ASSERT - ICRefillVerifier* verifier = current_ic_refill_verifier(); - verifier->request_refill(); -#endif - return false; - } - -#ifdef ASSERT - { - ICStub* rev_stub = ICStub::from_destination_address(ic_stub->code_begin()); - assert(ic_stub == rev_stub, - "ICStub mapping is reversible: stub=" PTR_FORMAT ", code=" PTR_FORMAT ", rev_stub=" PTR_FORMAT, - p2i(ic_stub), p2i(ic_stub->code_begin()), p2i(rev_stub)); - } -#endif - - // If an transition stub is already associate with the inline cache, then we remove the association. - if (ic->is_in_transition_state()) { - ICStub* old_stub = ICStub::from_destination_address(ic->stub_address()); - old_stub->clear(); - } - - ic_stub->set_stub(ic, cached_value, entry); - - // Update inline cache in nmethod to point to new "out-of-line" allocated inline cache - ic->set_ic_destination(ic_stub); - return true; -} - - -address InlineCacheBuffer::ic_destination_for(CompiledIC *ic) { - ICStub* stub = ICStub::from_destination_address(ic->stub_address()); - return stub->destination(); -} - - -void* InlineCacheBuffer::cached_value_for(CompiledIC *ic) { - ICStub* stub = ICStub::from_destination_address(ic->stub_address()); - return stub->cached_value(); -} - - -// Free CompiledICHolder*s that are no longer in use -void InlineCacheBuffer::release_pending_icholders() { - assert(SafepointSynchronize::is_at_safepoint(), "should only be called during a safepoint"); - CompiledICHolder* holder = Atomic::load(&_pending_released); - _pending_released = nullptr; - int count = 0; - while (holder != nullptr) { - CompiledICHolder* next = holder->next(); - delete holder; - holder = next; - count++; - } - assert(pending_icholder_count() == count, "wrong count"); - Atomic::store(&_pending_count, 0); -} - -// Enqueue this icholder for release during the next safepoint. It's -// not safe to free them until then since they might be visible to -// another thread. -void InlineCacheBuffer::queue_for_release(CompiledICHolder* icholder) { - assert(icholder->next() == nullptr, "multiple enqueue?"); - - CompiledICHolder* old = Atomic::load(&_pending_released); - for (;;) { - icholder->set_next(old); - // The only reader runs at a safepoint serially so there is no need for a more strict atomic. - CompiledICHolder* cur = Atomic::cmpxchg(&_pending_released, old, icholder, memory_order_relaxed); - if (cur == old) { - break; - } - old = cur; - } - Atomic::inc(&_pending_count, memory_order_relaxed); - - if (TraceICBuffer) { - tty->print_cr("enqueueing icholder " INTPTR_FORMAT " to be freed", p2i(icholder)); - } -} - -int InlineCacheBuffer::pending_icholder_count() { - return Atomic::load(&_pending_count); -} diff --git a/src/hotspot/share/code/icBuffer.hpp b/src/hotspot/share/code/icBuffer.hpp deleted file mode 100644 index f67080e6b58..00000000000 --- a/src/hotspot/share/code/icBuffer.hpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_CODE_ICBUFFER_HPP -#define SHARE_CODE_ICBUFFER_HPP - -#include "asm/codeBuffer.hpp" -#include "code/stubs.hpp" -#include "interpreter/bytecodes.hpp" -#include "memory/allocation.hpp" -#include "runtime/safepointVerifiers.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" -#include "utilities/macros.hpp" - -class CompiledIC; -class CompiledICHolder; - -// -// For CompiledIC's: -// -// In cases where we do not have MT-safe state transformation, -// we go to a transition state, using ICStubs. At a safepoint, -// the inline caches are transferred from the transitional code: -// -// instruction_address --> 01 set xxx_oop, Ginline_cache_klass -// 23 jump_to Gtemp, yyyy -// 4 nop - -class ICStub: public Stub { - private: - int _size; // total size of the stub incl. code - address _ic_site; // points at call instruction of owning ic-buffer - /* stub code follows here */ - protected: - friend class ICStubInterface; - // This will be called only by ICStubInterface - void initialize(int size) { _size = size; _ic_site = nullptr; } - void finalize(); // called when a method is removed - - // General info - int size() const { return _size; } - - // To be cautious, we want to make sure that each ICStub is in a separate instruction - // cache line. This would allow for piggybacking on instruction cache coherency on - // some architectures to order the updates to ICStub and setting the destination to - // the ICStub. Note that cache line size might be larger than CodeEntryAlignment - // that is normal alignment for CodeBlobs. - static int alignment() { return DEFAULT_CACHE_LINE_SIZE; } - - // Aligning the code section is normally done for performance reasons, which is not - // required for ICStubs, as these stubs are transitional. Setting code alignment - // to CodeEntryAlignment would waste a lot of memory in ICBuffer. Aligning to - // word size should be enough. This also offsets the costs of aligning the entire - // ICStub to cache line (see above), as smaller code alignment would allow ICStub - // to fit a _single_ cache line. - static int code_alignment() { return HeapWordSize; } - - public: - // Creation - void set_stub(CompiledIC *ic, void* cached_value, address dest_addr); - - // Code info - address code_begin() const { return align_up((address)this + sizeof(ICStub), code_alignment()); } - address code_end() const { return (address)this + size(); } - - // Call site info - address ic_site() const { return _ic_site; } - void clear(); - bool is_empty() const { return _ic_site == nullptr; } - - // stub info - address destination() const; // destination of jump instruction - void* cached_value() const; // cached_value for stub - - // Debugging - void verify() PRODUCT_RETURN; - void print() PRODUCT_RETURN; - - // Creation - static inline ICStub* from_destination_address(address destination_address) { - ICStub* stub = (ICStub*) align_down(destination_address - sizeof(ICStub), alignment()); -#ifdef ASSERT - stub->verify(); -#endif - return stub; - } -}; - -#ifdef ASSERT -// The ICRefillVerifier class is a stack allocated RAII object used to -// detect if a failed IC transition that required IC stub refilling has -// been accidentally missed. It is up to the caller to in that case -// refill IC stubs. -class ICRefillVerifier: StackObj { - bool _refill_requested; - bool _refill_remembered; - - public: - ICRefillVerifier(); - ~ICRefillVerifier(); - - void request_refill() { _refill_requested = true; } - void request_remembered() { _refill_remembered = true; } -}; - -// The ICRefillVerifierMark is used to set the thread's current -// ICRefillVerifier to a provided one. This is useful in particular -// when transitioning IC stubs in parallel and refilling from the -// master thread invoking the IC stub transitioning code. -class ICRefillVerifierMark: StackObj { - public: - ICRefillVerifierMark(ICRefillVerifier* verifier); - ~ICRefillVerifierMark(); -}; -#else -class ICRefillVerifier: StackObj { - public: - ICRefillVerifier() {} -}; -class ICRefillVerifierMark: StackObj { - public: - ICRefillVerifierMark(ICRefillVerifier* verifier) {} -}; -#endif - -class InlineCacheBuffer: public AllStatic { - private: - // friends - friend class ICStub; - - static int ic_stub_code_size(); - - static StubQueue* _buffer; - - static CompiledICHolder* volatile _pending_released; - static volatile int _pending_count; - - static StubQueue* buffer() { return _buffer; } - - // Machine-dependent implementation of ICBuffer - static void assemble_ic_buffer_code(address code_begin, void* cached_value, address entry_point); - static address ic_buffer_entry_point (address code_begin); - static void* ic_buffer_cached_value (address code_begin); - - public: - - // Initialization; must be called before first usage - static void initialize(); - - // Access - static bool contains(address instruction_address); - - // removes the ICStubs after backpatching - static bool needs_update_inline_caches(); - static void update_inline_caches(); - static void refill_ic_stubs(); - - // for debugging - static bool is_empty(); - - static void release_pending_icholders(); - static void queue_for_release(CompiledICHolder* icholder); - static int pending_icholder_count(); - - // New interface - static bool create_transition_stub(CompiledIC *ic, void* cached_value, address entry); - static address ic_destination_for(CompiledIC *ic); - static void* cached_value_for(CompiledIC *ic); -}; - -#endif // SHARE_CODE_ICBUFFER_HPP diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index b18077fddfd..2755df32513 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -640,6 +640,7 @@ nmethod::nmethod( ByteSize basic_lock_sp_offset, OopMapSet* oop_maps ) : CompiledMethod(method, "native nmethod", type, nmethod_size, sizeof(nmethod), code_buffer, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, false, true), + _compiled_ic_data(nullptr), _is_unlinked(false), _native_receiver_sp_offset(basic_lock_owner_sp_offset), _native_basic_lock_sp_offset(basic_lock_sp_offset), @@ -697,12 +698,12 @@ nmethod::nmethod( clear_unloading_state(); + finalize_relocations(); + Universe::heap()->register_nmethod(this); debug_only(Universe::heap()->verify_nmethod(this)); CodeCache::commit(this); - - finalize_relocations(); } if (PrintNativeNMethods || PrintDebugInfo || PrintRelocations || PrintDependencies) { @@ -784,6 +785,7 @@ nmethod::nmethod( #endif ) : CompiledMethod(method, "nmethod", type, nmethod_size, sizeof(nmethod), code_buffer, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, false, true), + _compiled_ic_data(nullptr), _is_unlinked(false), _native_receiver_sp_offset(in_ByteSize(-1)), _native_basic_lock_sp_offset(in_ByteSize(-1)), @@ -887,13 +889,13 @@ nmethod::nmethod( } #endif + finalize_relocations(); + Universe::heap()->register_nmethod(this); debug_only(Universe::heap()->verify_nmethod(this)); CodeCache::commit(this); - finalize_relocations(); - // Copy contents of ExceptionHandlerTable to nmethod handler_table->copy_to(this); nul_chk_table->copy_to(this); @@ -1021,7 +1023,7 @@ void nmethod::print_nmethod(bool printmethod) { tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); print_metadata(tty); tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); - print_pcs(); + print_pcs_on(tty); tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); if (oop_maps() != nullptr) { tty->print("oop maps:"); // oop_maps()->print_on(tty) outputs a cr() at the beginning @@ -1145,16 +1147,33 @@ static void install_post_call_nop_displacement(nmethod* nm, address pc) { void nmethod::finalize_relocations() { NoSafepointVerifier nsv; + GrowableArray virtual_call_data; + // Make sure that post call nops fill in nmethod offsets eagerly so // we don't have to race with deoptimization RelocIterator iter(this); while (iter.next()) { - if (iter.type() == relocInfo::post_call_nop_type) { + if (iter.type() == relocInfo::virtual_call_type) { + virtual_call_Relocation* r = iter.virtual_call_reloc(); + NativeMovConstReg* value = nativeMovConstReg_at(r->cached_value()); + virtual_call_data.append(value); + } else if (iter.type() == relocInfo::post_call_nop_type) { post_call_nop_Relocation* const reloc = iter.post_call_nop_reloc(); address pc = reloc->addr(); install_post_call_nop_displacement(this, pc); } } + + if (virtual_call_data.length() > 0) { + // We allocate a block of CompiledICData per nmethod so the GC can purge this faster. + _compiled_ic_data = new CompiledICData[virtual_call_data.length()]; + CompiledICData* next_data = _compiled_ic_data; + + for (NativeMovConstReg* value : virtual_call_data) { + value->set_data((intptr_t)next_data); + next_data++; + } + } } void nmethod::make_deoptimized() { @@ -1180,8 +1199,7 @@ void nmethod::make_deoptimized() { while (iter.next()) { switch (iter.type()) { - case relocInfo::virtual_call_type: - case relocInfo::opt_virtual_call_type: { + case relocInfo::virtual_call_type: { CompiledIC *ic = CompiledIC_at(&iter); address pc = ic->end_of_call(); NativePostCallNop* nop = nativePostCallNop_at(pc); @@ -1191,8 +1209,9 @@ void nmethod::make_deoptimized() { assert(NativeDeoptInstruction::is_deopt_at(pc), "check"); break; } - case relocInfo::static_call_type: { - CompiledStaticCall *csc = compiledStaticCall_at(iter.reloc()); + case relocInfo::static_call_type: + case relocInfo::opt_virtual_call_type: { + CompiledDirectCall *csc = CompiledDirectCall::at(iter.reloc()); address pc = csc->end_of_call(); NativePostCallNop* nop = nativePostCallNop_at(pc); //tty->print_cr(" - static pc %p", pc); @@ -1219,29 +1238,29 @@ void nmethod::verify_clean_inline_caches() { RelocIterator iter(this, oops_reloc_begin()); while(iter.next()) { switch(iter.type()) { - case relocInfo::virtual_call_type: - case relocInfo::opt_virtual_call_type: { + case relocInfo::virtual_call_type: { CompiledIC *ic = CompiledIC_at(&iter); - CodeBlob *cb = CodeCache::find_blob(ic->ic_destination()); + CodeBlob *cb = CodeCache::find_blob(ic->destination()); assert(cb != nullptr, "destination not in CodeBlob?"); nmethod* nm = cb->as_nmethod_or_null(); - if( nm != nullptr ) { + if (nm != nullptr) { // Verify that inline caches pointing to bad nmethods are clean - if (!nm->is_in_use() || (nm->method()->code() != nm)) { + if (!nm->is_in_use() || nm->is_unloading()) { assert(ic->is_clean(), "IC should be clean"); } } break; } - case relocInfo::static_call_type: { - CompiledStaticCall *csc = compiledStaticCall_at(iter.reloc()); - CodeBlob *cb = CodeCache::find_blob(csc->destination()); + case relocInfo::static_call_type: + case relocInfo::opt_virtual_call_type: { + CompiledDirectCall *cdc = CompiledDirectCall::at(iter.reloc()); + CodeBlob *cb = CodeCache::find_blob(cdc->destination()); assert(cb != nullptr, "destination not in CodeBlob?"); nmethod* nm = cb->as_nmethod_or_null(); - if( nm != nullptr ) { + if (nm != nullptr) { // Verify that inline caches pointing to bad nmethods are clean - if (!nm->is_in_use() || (nm->method()->code() != nm)) { - assert(csc->is_clean(), "IC should be clean"); + if (!nm->is_in_use() || nm->is_unloading() || nm->method()->code() != nm) { + assert(cdc->is_clean(), "IC should be clean"); } } break; @@ -1405,9 +1424,7 @@ bool nmethod::make_not_entrant() { // For concurrent GCs, there must be a handshake between unlink and flush void nmethod::unlink() { if (_is_unlinked) { - // Already unlinked. It can be invoked twice because concurrent code cache - // unloading might need to restart when inline cache cleaning fails due to - // running out of ICStubs, which can only be refilled at safepoints + // Already unlinked. return; } @@ -1418,7 +1435,6 @@ void nmethod::unlink() { // the Method, because it is only concurrently unlinked by // the entry barrier, which acquires the per nmethod lock. unlink_from_method(); - clear_ic_callsites(); if (is_osr_method()) { invalidate_osr_method(); @@ -1463,10 +1479,11 @@ void nmethod::purge(bool free_code_cache_data, bool unregister_nmethod) { ec = next; } + delete[] _compiled_ic_data; + if (unregister_nmethod) { Universe::heap()->unregister_nmethod(this); } - CodeCache::unregister_old_nmethod(this); CodeBlob::purge(free_code_cache_data, unregister_nmethod); @@ -1604,16 +1621,7 @@ void nmethod::metadata_do(MetadataClosure* f) { // Check compiledIC holders associated with this nmethod ResourceMark rm; CompiledIC *ic = CompiledIC_at(&iter); - if (ic->is_icholder_call()) { - CompiledICHolder* cichk = ic->cached_icholder(); - f->do_metadata(cichk->holder_metadata()); - f->do_metadata(cichk->holder_klass()); - } else { - Metadata* ic_oop = ic->cached_metadata(); - if (ic_oop != nullptr) { - f->do_metadata(ic_oop); - } - } + ic->metadata_do(f); } } } @@ -1750,8 +1758,7 @@ void nmethod::do_unloading(bool unloading_occurred) { if (is_unloading()) { unlink(); } else { - guarantee(unload_nmethod_caches(unloading_occurred), - "Should not need transition stubs"); + unload_nmethod_caches(unloading_occurred); BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); if (bs_nm != nullptr) { bs_nm->disarm(this); @@ -2284,15 +2291,23 @@ void nmethod::verify() { } -void nmethod::verify_interrupt_point(address call_site) { +void nmethod::verify_interrupt_point(address call_site, bool is_inline_cache) { // Verify IC only when nmethod installation is finished. if (!is_not_installed()) { if (CompiledICLocker::is_safe(this)) { - CompiledIC_at(this, call_site); + if (is_inline_cache) { + CompiledIC_at(this, call_site); + } else { + CompiledDirectCall::at(call_site); + } } else { CompiledICLocker ml_verify(this); - CompiledIC_at(this, call_site); + if (is_inline_cache) { + CompiledIC_at(this, call_site); + } else { + CompiledDirectCall::at(call_site); + } } } @@ -2316,15 +2331,15 @@ void nmethod::verify_scopes() { address stub = nullptr; switch (iter.type()) { case relocInfo::virtual_call_type: - verify_interrupt_point(iter.addr()); + verify_interrupt_point(iter.addr(), true /* is_inline_cache */); break; case relocInfo::opt_virtual_call_type: stub = iter.opt_virtual_call_reloc()->static_stub(); - verify_interrupt_point(iter.addr()); + verify_interrupt_point(iter.addr(), false /* is_inline_cache */); break; case relocInfo::static_call_type: stub = iter.static_call_reloc()->static_stub(); - //verify_interrupt_point(iter.addr()); + verify_interrupt_point(iter.addr(), false /* is_inline_cache */); break; case relocInfo::runtime_call_type: case relocInfo::runtime_call_w_cp_type: { @@ -3239,75 +3254,6 @@ void nmethod::print_code_comment_on(outputStream* st, int column, address begin, #endif -class DirectNativeCallWrapper: public NativeCallWrapper { -private: - NativeCall* _call; - -public: - DirectNativeCallWrapper(NativeCall* call) : _call(call) {} - - virtual address destination() const { return _call->destination(); } - virtual address instruction_address() const { return _call->instruction_address(); } - virtual address next_instruction_address() const { return _call->next_instruction_address(); } - virtual address return_address() const { return _call->return_address(); } - - virtual address get_resolve_call_stub(bool is_optimized) const { - if (is_optimized) { - return SharedRuntime::get_resolve_opt_virtual_call_stub(); - } - return SharedRuntime::get_resolve_virtual_call_stub(); - } - - virtual void set_destination_mt_safe(address dest) { - _call->set_destination_mt_safe(dest); - } - - virtual void set_to_interpreted(const methodHandle& method, CompiledICInfo& info) { - CompiledDirectStaticCall* csc = CompiledDirectStaticCall::at(instruction_address()); - { - csc->set_to_interpreted(method, info.entry()); - } - } - - virtual void verify() const { - // make sure code pattern is actually a call imm32 instruction - _call->verify(); - _call->verify_alignment(); - } - - virtual void verify_resolve_call(address dest) const { - CodeBlob* db = CodeCache::find_blob(dest); - assert(db != nullptr && !db->is_adapter_blob(), "must use stub!"); - } - - virtual bool is_call_to_interpreted(address dest) const { - CodeBlob* cb = CodeCache::find_blob(_call->instruction_address()); - return cb->contains(dest); - } - - virtual bool is_safe_for_patching() const { return false; } - - virtual NativeInstruction* get_load_instruction(virtual_call_Relocation* r) const { - return nativeMovConstReg_at(r->cached_value()); - } - - virtual void *get_data(NativeInstruction* instruction) const { - return (void*)((NativeMovConstReg*) instruction)->data(); - } - - virtual void set_data(NativeInstruction* instruction, intptr_t data) { - ((NativeMovConstReg*) instruction)->set_data(data); - } -}; - -NativeCallWrapper* nmethod::call_wrapper_at(address call) const { - return new DirectNativeCallWrapper((NativeCall*) call); -} - -NativeCallWrapper* nmethod::call_wrapper_before(address return_pc) const { - return new DirectNativeCallWrapper(nativeCall_before(return_pc)); -} - address nmethod::call_instruction_address(address pc) const { if (NativeCall::is_call_before(pc)) { NativeCall *ncall = nativeCall_before(pc); @@ -3316,18 +3262,6 @@ address nmethod::call_instruction_address(address pc) const { return nullptr; } -CompiledStaticCall* nmethod::compiledStaticCall_at(Relocation* call_site) const { - return CompiledDirectStaticCall::at(call_site); -} - -CompiledStaticCall* nmethod::compiledStaticCall_at(address call_site) const { - return CompiledDirectStaticCall::at(call_site); -} - -CompiledStaticCall* nmethod::compiledStaticCall_before(address return_addr) const { - return CompiledDirectStaticCall::before(return_addr); -} - #if defined(SUPPORT_DATA_STRUCTS) void nmethod::print_value_on(outputStream* st) const { st->print("nmethod"); @@ -3341,15 +3275,15 @@ void nmethod::print_calls(outputStream* st) { RelocIterator iter(this); while (iter.next()) { switch (iter.type()) { - case relocInfo::virtual_call_type: - case relocInfo::opt_virtual_call_type: { + case relocInfo::virtual_call_type: { CompiledICLocker ml_verify(this); CompiledIC_at(&iter)->print(); break; } case relocInfo::static_call_type: - st->print_cr("Static call at " INTPTR_FORMAT, p2i(iter.reloc()->addr())); - CompiledDirectStaticCall::at(iter.reloc())->print(); + case relocInfo::opt_virtual_call_type: + st->print_cr("Direct call at " INTPTR_FORMAT, p2i(iter.reloc()->addr())); + CompiledDirectCall::at(iter.reloc())->print(); break; default: break; diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 656dae4171b..2993db21305 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "code/compiledMethod.hpp" +class CompiledICData; class CompileTask; class DepChange; class DirectiveSet; @@ -196,6 +197,7 @@ class nmethod : public CompiledMethod { address _verified_entry_point; // entry point without class check address _osr_entry_point; // entry point for on stack replacement + CompiledICData* _compiled_ic_data; bool _is_unlinked; // Shared fields for all nmethod's @@ -604,7 +606,7 @@ class nmethod : public CompiledMethod { // verify operations void verify(); void verify_scopes(); - void verify_interrupt_point(address interrupt_point); + void verify_interrupt_point(address interrupt_point, bool is_inline_cache); // Disassemble this nmethod with additional debug information, e.g. information about blocks. void decode2(outputStream* st) const; @@ -621,7 +623,6 @@ class nmethod : public CompiledMethod { #if defined(SUPPORT_DATA_STRUCTS) // print output in opt build for disassembler library void print_relocations() PRODUCT_RETURN; - void print_pcs() { print_pcs_on(tty); } void print_pcs_on(outputStream* st); void print_scopes() { print_scopes_on(tty); } void print_scopes_on(outputStream* st) PRODUCT_RETURN; @@ -635,8 +636,7 @@ class nmethod : public CompiledMethod { void print_oops(outputStream* st); // oops from the underlying CodeBlob. void print_metadata(outputStream* st); // metadata in metadata pool. #else - // void print_pcs() PRODUCT_RETURN; - void print_pcs() { return; } + void print_pcs_on(outputStream* st) { return; } #endif void print_calls(outputStream* st) PRODUCT_RETURN; @@ -701,14 +701,8 @@ class nmethod : public CompiledMethod { virtual void metadata_do(MetadataClosure* f); - NativeCallWrapper* call_wrapper_at(address call) const; - NativeCallWrapper* call_wrapper_before(address return_pc) const; address call_instruction_address(address pc) const; - virtual CompiledStaticCall* compiledStaticCall_at(Relocation* call_site) const; - virtual CompiledStaticCall* compiledStaticCall_at(address addr) const; - virtual CompiledStaticCall* compiledStaticCall_before(address addr) const; - virtual void make_deoptimized(); void finalize_relocations(); }; diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index bfb3db72d72..ef908757675 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -641,12 +641,10 @@ Method* virtual_call_Relocation::method_value() { return (Method*)m; } -bool virtual_call_Relocation::clear_inline_cache() { - // No stubs for ICs - // Clean IC +void virtual_call_Relocation::clear_inline_cache() { ResourceMark rm; CompiledIC* icache = CompiledIC_at(this); - return icache->set_to_clean(); + icache->set_to_clean(); } @@ -669,18 +667,10 @@ Method* opt_virtual_call_Relocation::method_value() { return (Method*)m; } -template -static bool set_to_clean_no_ic_refill(CompiledICorStaticCall* ic) { - guarantee(ic->set_to_clean(), "Should not need transition stubs"); - return true; -} - -bool opt_virtual_call_Relocation::clear_inline_cache() { - // No stubs for ICs - // Clean IC +void opt_virtual_call_Relocation::clear_inline_cache() { ResourceMark rm; - CompiledIC* icache = CompiledIC_at(this); - return set_to_clean_no_ic_refill(icache); + CompiledDirectCall* callsite = CompiledDirectCall::at(this); + callsite->set_to_clean(); } address opt_virtual_call_Relocation::static_stub() { @@ -717,10 +707,10 @@ void static_call_Relocation::unpack_data() { _method_index = unpack_1_int(); } -bool static_call_Relocation::clear_inline_cache() { - // Safe call site info - CompiledStaticCall* handler = this->code()->compiledStaticCall_at(this); - return set_to_clean_no_ic_refill(handler); +void static_call_Relocation::clear_inline_cache() { + ResourceMark rm; + CompiledDirectCall* callsite = CompiledDirectCall::at(this); + callsite->set_to_clean(); } @@ -759,11 +749,10 @@ address trampoline_stub_Relocation::get_trampoline_for(address call, nmethod* co return nullptr; } -bool static_stub_Relocation::clear_inline_cache() { +void static_stub_Relocation::clear_inline_cache() { // Call stub is only used when calling the interpreted code. // It does not really need to be cleared, except that we want to clean out the methodoop. - CompiledDirectStaticCall::set_stub_to_clean(this); - return true; + CompiledDirectCall::set_stub_to_clean(this); } diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 77e24708bb1..5f67f94bdad 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -862,7 +862,7 @@ class Relocation { // all relocations are able to reassert their values virtual void set_value(address x); - virtual bool clear_inline_cache() { return true; } + virtual void clear_inline_cache() {} // This method assumes that all virtual/static (inline) caches are cleared (since for static_call_type and // ic_call_type is not always position dependent (depending on the state of the cache)). However, this is @@ -1141,7 +1141,7 @@ class virtual_call_Relocation : public CallRelocation { void pack_data_to(CodeSection* dest) override; void unpack_data() override; - bool clear_inline_cache() override; + void clear_inline_cache() override; }; @@ -1170,7 +1170,7 @@ class opt_virtual_call_Relocation : public CallRelocation { void pack_data_to(CodeSection* dest) override; void unpack_data() override; - bool clear_inline_cache() override; + void clear_inline_cache() override; // find the matching static_stub address static_stub(); @@ -1202,7 +1202,7 @@ class static_call_Relocation : public CallRelocation { void pack_data_to(CodeSection* dest) override; void unpack_data() override; - bool clear_inline_cache() override; + void clear_inline_cache() override; // find the matching static_stub address static_stub(); @@ -1227,7 +1227,7 @@ class static_stub_Relocation : public Relocation { static_stub_Relocation() : Relocation(relocInfo::static_stub_type) { } public: - bool clear_inline_cache() override; + void clear_inline_cache() override; address static_call() { return _static_call; } diff --git a/src/hotspot/share/code/vtableStubs.cpp b/src/hotspot/share/code/vtableStubs.cpp index eed3dc8e787..5a54426d6a4 100644 --- a/src/hotspot/share/code/vtableStubs.cpp +++ b/src/hotspot/share/code/vtableStubs.cpp @@ -283,13 +283,6 @@ VtableStub* VtableStubs::entry_point(address pc) { return (s == stub) ? s : nullptr; } -bool VtableStubs::is_icholder_entry(address pc) { - assert(contains(pc), "must contain all vtable blobs"); - VtableStub* stub = (VtableStub*)(pc - VtableStub::entry_offset()); - // itable stubs use CompiledICHolder. - return stub->is_itable_stub(); -} - bool VtableStubs::contains(address pc) { // simple solution for now - we may want to use // a faster way if this function is called often diff --git a/src/hotspot/share/code/vtableStubs.hpp b/src/hotspot/share/code/vtableStubs.hpp index 7076e50f3e3..3993e1e72d5 100644 --- a/src/hotspot/share/code/vtableStubs.hpp +++ b/src/hotspot/share/code/vtableStubs.hpp @@ -107,7 +107,6 @@ class VtableStubs : AllStatic { static address find_itable_stub(int itable_index) { return find_stub(false, itable_index); } static VtableStub* entry_point(address pc); // vtable stub entry point for a pc - static bool is_icholder_entry(address pc); // is the blob containing pc (which must be a vtable blob) an icholder? static bool contains(address pc); // is pc within any stub? static VtableStub* stub_containing(address pc); // stub containing pc or nullptr static void initialize(); diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index ff5fa44050c..3a251128914 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -582,7 +582,7 @@ CompilerCounters::CompilerCounters() { // c2 uses explicit CompilerPhaseType idToPhase mapping in opto/phasetype.hpp, // so if c2 is used, it should be always registered first. // This function is called during vm initialization. -void register_jfr_phasetype_serializer(CompilerType compiler_type) { +static void register_jfr_phasetype_serializer(CompilerType compiler_type) { ResourceMark rm; static bool first_registration = true; if (compiler_type == compiler_jvmci) { @@ -841,8 +841,15 @@ void DeoptimizeObjectsALotThread::deoptimize_objects_alot_loop_all() { JavaThread* CompileBroker::make_thread(ThreadType type, jobject thread_handle, CompileQueue* queue, AbstractCompiler* comp, JavaThread* THREAD) { - JavaThread* new_thread = nullptr; + Handle thread_oop(THREAD, JNIHandles::resolve_non_null(thread_handle)); + if (java_lang_Thread::thread(thread_oop()) != nullptr) { + assert(type == compiler_t, "should only happen with reused compiler threads"); + // The compiler thread hasn't actually exited yet so don't try to reuse it + return nullptr; + } + + JavaThread* new_thread = nullptr; switch (type) { case compiler_t: assert(comp != nullptr, "Compiler instance missing."); @@ -871,7 +878,6 @@ JavaThread* CompileBroker::make_thread(ThreadType type, jobject thread_handle, C // JavaThread due to lack of resources. We will handle that failure below. // Also check new_thread so that static analysis is happy. if (new_thread != nullptr && new_thread->osthread() != nullptr) { - Handle thread_oop(THREAD, JNIHandles::resolve_non_null(thread_handle)); if (type == compiler_t) { CompilerThread::cast(new_thread)->set_compiler(comp); diff --git a/src/hotspot/share/compiler/compilerDirectives.cpp b/src/hotspot/share/compiler/compilerDirectives.cpp index d7d4c5b60ed..a16e5f23ed9 100644 --- a/src/hotspot/share/compiler/compilerDirectives.cpp +++ b/src/hotspot/share/compiler/compilerDirectives.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "opto/phasetype.hpp" +#include "opto/traceAutoVectorizationTag.hpp" #include "runtime/globals_extension.hpp" CompilerDirectives::CompilerDirectives() : _next(nullptr), _match(nullptr), _ref_count(0) { @@ -300,7 +301,8 @@ void DirectiveSet::init_control_intrinsic() { DirectiveSet::DirectiveSet(CompilerDirectives* d) : _inlinematchers(nullptr), _directive(d), - _ideal_phase_name_set(PHASE_NUM_TYPES, mtCompiler) + _ideal_phase_name_set(PHASE_NUM_TYPES, mtCompiler), + _trace_auto_vectorization_tags(TRACE_AUTO_VECTORIZATION_TAG_NUM, mtCompiler) { #define init_defaults_definition(name, type, dvalue, compiler) this->name##Option = dvalue; compilerdirectives_common_flags(init_defaults_definition) @@ -433,6 +435,16 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle // Parse PrintIdealPhaseName and create a lookup set #ifndef PRODUCT #ifdef COMPILER2 + if (!_modified[TraceAutoVectorizationIndex]) { + // Parse ccstr and create mask + ccstrlist option; + if (CompilerOracle::has_option_value(method, CompileCommand::TraceAutoVectorization, option)) { + TraceAutoVectorizationTagValidator validator(option, false); + if (validator.is_valid()) { + set.cloned()->set_trace_auto_vectorization_tags(validator.tags()); + } + } + } if (!_modified[PrintIdealPhaseIndex]) { // Parse ccstr and create set ccstrlist option; diff --git a/src/hotspot/share/compiler/compilerDirectives.hpp b/src/hotspot/share/compiler/compilerDirectives.hpp index 4c9b51724f9..747c8781817 100644 --- a/src/hotspot/share/compiler/compilerDirectives.hpp +++ b/src/hotspot/share/compiler/compilerDirectives.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,10 +87,10 @@ NOT_PRODUCT(cflags(PrintIdeal, bool, PrintIdeal, PrintIdeal)) \ cflags(Vectorize, bool, false, Vectorize) \ cflags(CloneMapDebug, bool, false, CloneMapDebug) \ NOT_PRODUCT(cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLevel)) \ - cflags(VectorizeDebug, uintx, 0, VectorizeDebug) \ cflags(IncrementalInlineForceCleanup, bool, IncrementalInlineForceCleanup, IncrementalInlineForceCleanup) \ cflags(MaxNodeLimit, intx, MaxNodeLimit, MaxNodeLimit) #define compilerdirectives_c2_string_flags(cflags) \ +NOT_PRODUCT(cflags(TraceAutoVectorization, ccstrlist, "", TraceAutoVectorization)) \ NOT_PRODUCT(cflags(PrintIdealPhase, ccstrlist, "", PrintIdealPhase)) #else #define compilerdirectives_c2_other_flags(cflags) @@ -131,6 +131,7 @@ class DirectiveSet : public CHeapObj { CompilerDirectives* _directive; TriBoolArray<(size_t)vmIntrinsics::number_of_intrinsics(), int> _intrinsic_control_words; CHeapBitMap _ideal_phase_name_set; + CHeapBitMap _trace_auto_vectorization_tags; public: DirectiveSet(CompilerDirectives* directive); @@ -205,6 +206,12 @@ void set_##name(void* value) { \ bool should_print_phase(const CompilerPhaseType cpt) const { return _ideal_phase_name_set.at(cpt); }; + void set_trace_auto_vectorization_tags(const CHeapBitMap& tags) { + _trace_auto_vectorization_tags.set_from(tags); + }; + const CHeapBitMap& trace_auto_vectorization_tags() { + return _trace_auto_vectorization_tags; + }; void print_intx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" INTX_FORMAT " ", n, v); } } void print_uintx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" UINTX_FORMAT " ", n, v); } } diff --git a/src/hotspot/share/compiler/compilerOracle.cpp b/src/hotspot/share/compiler/compilerOracle.cpp index 66eea29fcc1..a8eee10fac5 100644 --- a/src/hotspot/share/compiler/compilerOracle.cpp +++ b/src/hotspot/share/compiler/compilerOracle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ #include "oops/method.inline.hpp" #include "oops/symbol.hpp" #include "opto/phasetype.hpp" +#include "opto/traceAutoVectorizationTag.hpp" #include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.hpp" @@ -47,7 +48,7 @@ static const char* optiontype_names[] = { #undef enum_of_types }; -const char* optiontype2name(enum OptionType type) { +static const char* optiontype2name(enum OptionType type) { return optiontype_names[static_cast(type)]; } @@ -57,7 +58,7 @@ static enum OptionType option_types[] = { #undef enum_of_options }; -enum OptionType option2type(enum CompileCommand option) { +static enum OptionType option2type(enum CompileCommand option) { return option_types[static_cast(option)]; } @@ -67,7 +68,7 @@ static const char* option_names[] = { #undef enum_of_options }; -const char* option2name(enum CompileCommand option) { +static const char* option2name(enum CompileCommand option) { return option_names[static_cast(option)]; } @@ -107,7 +108,7 @@ static bool print_final_memstat_report = false; // A filter for quick lookup if an option is set static bool option_filter[static_cast(CompileCommand::Unknown) + 1] = { 0 }; -void command_set_in_filter(enum CompileCommand option) { +static void command_set_in_filter(enum CompileCommand option) { assert(option != CompileCommand::Unknown, "sanity"); assert(option2type(option) != OptionType::Unknown, "sanity"); @@ -119,7 +120,7 @@ void command_set_in_filter(enum CompileCommand option) { option_filter[static_cast(option)] = true; } -bool has_command(enum CompileCommand option) { +static bool has_command(enum CompileCommand option) { return option_filter[static_cast(option)]; } @@ -546,7 +547,7 @@ enum OptionType CompilerOracle::parse_option_type(const char* type_str) { return OptionType::Unknown; } -void print_tip() { // CMH Update info +static void print_tip() { // CMH Update info tty->cr(); tty->print_cr("Usage: '-XX:CompileCommand=